{"action":"created","comment":{"url":"https://api.github.com/repos/apache/kafka/pulls/comments/195823376","pull_request_review_id":129226628,"id":195823376,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE5NTgyMzM3Ng==","diff_hunk":"@@ -306,14 +310,84 @@ class ConfigCommandTest extends ZooKeeperTestHarness with Logging {\n     ConfigCommand.alterConfig(null, createOpts, new DummyAdminZkClient(zkClient))\n   }\n \n-  @Test (expected = classOf[IllegalArgumentException])\n-  def shouldNotUpdateDynamicBrokerConfigUsingZooKeeper(): Unit = {\n-    val createOpts = new ConfigCommandOptions(Array(\"--zookeeper\", zkConnect,\n-      \"--entity-name\", \"1\",\n-      \"--entity-type\", \"brokers\",\n-      \"--alter\",\n-      \"--add-config\", \"message.max.size=100000\"))\n-    ConfigCommand.alterConfig(null, createOpts, new DummyAdminZkClient(zkClient))\n+  @Test\n+  def testDynamicBrokerConfigUpdateUsingZooKeeper(): Unit = {\n+    val brokerId = \"1\"\n+    val adminZkClient = new AdminZkClient(zkClient)\n+    val alterOpts = Array(\"--zookeeper\", zkConnect, \"--entity-type\", \"brokers\", \"--alter\")\n+\n+    def entityOpt(brokerId: Option[String]): Array[String] = {\n+      brokerId.map(id => Array(\"--entity-name\", id)).getOrElse(Array(\"--entity-default\"))\n+    }\n+\n+    def alterConfig(configs: Map[String, String], brokerId: Option[String], encoderSecret: Option[String] = None): Unit = {\n+      val configStr = configs.map { case (k, v) => s\"$k=$v\" }.mkString(\",\") +\n+        encoderSecret.map(secret => s\",${KafkaConfig.PasswordEncoderSecretProp}=$secret\").getOrElse(\"\")\n+      val addOpts = new ConfigCommandOptions(alterOpts ++ entityOpt(brokerId) ++ Array(\"--add-config\", configStr))\n+      ConfigCommand.alterConfig(zkClient, addOpts, adminZkClient)\n+    }\n+\n+    def verifyConfig(configs: Map[String, String], brokerId: Option[String]): Unit = {\n+      val entityConfigs = zkClient.getEntityConfigs(\"brokers\", brokerId.getOrElse(ConfigEntityName.Default))\n+      assertEquals(configs, entityConfigs.asScala)\n+    }\n+\n+    def alterAndVerifyConfig(configs: Map[String, String], brokerId: Option[String]): Unit = {\n+      alterConfig(configs, brokerId)\n+      verifyConfig(configs, brokerId)\n+    }\n+\n+    def deleteAndVerifyConfig(configNames: Set[String], brokerId: Option[String]): Unit = {\n+      val deleteOpts = new ConfigCommandOptions(alterOpts ++ entityOpt(brokerId) ++\n+        Array(\"--delete-config\", configNames.mkString(\",\")))\n+      ConfigCommand.alterConfig(zkClient, deleteOpts, adminZkClient)\n+      verifyConfig(Map.empty, brokerId)\n+    }\n+\n+    // Add config\n+    alterAndVerifyConfig(Map(\"message.max.size\" -> \"110000\"), Some(brokerId))\n+    alterAndVerifyConfig(Map(\"message.max.size\" -> \"120000\"), None)\n+\n+    // Change config\n+    alterAndVerifyConfig(Map(\"message.max.size\" -> \"130000\"), Some(brokerId))\n+    alterAndVerifyConfig(Map(\"message.max.size\" -> \"140000\"), None)\n+\n+    // Delete config\n+    deleteAndVerifyConfig(Set(\"message.max.size\"), Some(brokerId))\n+    deleteAndVerifyConfig(Set(\"message.max.size\"), None)\n+\n+    // Listener configs: should work only with listener name\n+    alterAndVerifyConfig(Map(\"listener.name.external.ssl.keystore.location\" -> \"/tmp/test.jks\"), Some(brokerId))\n+    intercept[ConfigException](alterConfig(Map(\"ssl.keystore.location\" -> \"/tmp/test.jks\"), Some(brokerId)))\n+\n+    // Per-broker config configured at default cluster-level should fail\n+    intercept[ConfigException](alterConfig(Map(\"listener.name.external.ssl.keystore.location\" -> \"/tmp/test.jks\"), None))\n+    deleteAndVerifyConfig(Set(\"listener.name.external.ssl.keystore.location\"), Some(brokerId))\n+\n+    // Password config update without encoder secret should fail\n+    intercept[IllegalArgumentException](alterConfig(Map(\"listener.name.external.ssl.keystore.password\" -> \"secret\"), Some(brokerId)))\n+\n+    // Password config update with encoder secret should succeed and encoded password must be stored in ZK\n+    val configs = Map(\"listener.name.external.ssl.keystore.password\" -> \"secret\", \"log.cleaner.threads\" -> \"2\")\n+    alterConfig(configs, Some(brokerId), Some(\"encoder-secret\"))\n+    val brokerConfigs = zkClient.getEntityConfigs(\"brokers\", brokerId)\n+    assertFalse(\"Encoder secret stored in ZooKeeper\", brokerConfigs.contains(KafkaConfig.PasswordEncoderSecretProp))\n+    assertEquals(\"2\", brokerConfigs.getProperty(\"log.cleaner.threads\")) // not encoded\n+    val encodedPassword = brokerConfigs.getProperty(\"listener.name.external.ssl.keystore.password\")\n+    val passwordEncoder = ConfigCommand.createPasswordEncoder(\"encoder-secret\")\n+    assertEquals(\"secret\", passwordEncoder.decode(encodedPassword).value)\n+    assertEquals(configs.size, brokerConfigs.size)\n+\n+    // Password config update at default cluster-level should fail\n+    intercept[ConfigException](alterConfig(configs, None, Some(\"encoder-secret\")))\n+\n+    // Dynamic config updates using ZK should fail if broker is running.\n+    registerBrokerInZk(1)","path":"core/src/test/scala/unit/kafka/admin/ConfigCommandTest.scala","position":123,"original_position":123,"commit_id":"ca1962db944794d47bfa9f2eb7d10afb534219a2","original_commit_id":"ca1962db944794d47bfa9f2eb7d10afb534219a2","user":{"login":"hachikuji","id":12502538,"node_id":"MDQ6VXNlcjEyNTAyNTM4","avatar_url":"https://avatars3.githubusercontent.com/u/12502538?v=4","gravatar_id":"","url":"https://api.github.com/users/hachikuji","html_url":"https://github.com/hachikuji","followers_url":"https://api.github.com/users/hachikuji/followers","following_url":"https://api.github.com/users/hachikuji/following{/other_user}","gists_url":"https://api.github.com/users/hachikuji/gists{/gist_id}","starred_url":"https://api.github.com/users/hachikuji/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hachikuji/subscriptions","organizations_url":"https://api.github.com/users/hachikuji/orgs","repos_url":"https://api.github.com/users/hachikuji/repos","events_url":"https://api.github.com/users/hachikuji/events{/privacy}","received_events_url":"https://api.github.com/users/hachikuji/received_events","type":"User","site_admin":false},"body":"nit: maybe we should refer to the value `brokerId` here and the line below?","created_at":"2018-06-15T18:11:30Z","updated_at":"2018-06-15T18:12:00Z","html_url":"https://github.com/apache/kafka/pull/4898#discussion_r195823376","pull_request_url":"https://api.github.com/repos/apache/kafka/pulls/4898","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/apache/kafka/pulls/comments/195823376"},"html":{"href":"https://github.com/apache/kafka/pull/4898#discussion_r195823376"},"pull_request":{"href":"https://api.github.com/repos/apache/kafka/pulls/4898"}}},"pull_request":{"url":"https://api.github.com/repos/apache/kafka/pulls/4898","id":182820128,"node_id":"MDExOlB1bGxSZXF1ZXN0MTgyODIwMTI4","html_url":"https://github.com/apache/kafka/pull/4898","diff_url":"https://github.com/apache/kafka/pull/4898.diff","patch_url":"https://github.com/apache/kafka/pull/4898.patch","issue_url":"https://api.github.com/repos/apache/kafka/issues/4898","number":4898,"state":"open","locked":false,"title":"KAFKA-6805: Enable broker configs to be stored in ZK before broker start","user":{"login":"rajinisivaram","id":13164074,"node_id":"MDQ6VXNlcjEzMTY0MDc0","avatar_url":"https://avatars0.githubusercontent.com/u/13164074?v=4","gravatar_id":"","url":"https://api.github.com/users/rajinisivaram","html_url":"https://github.com/rajinisivaram","followers_url":"https://api.github.com/users/rajinisivaram/followers","following_url":"https://api.github.com/users/rajinisivaram/following{/other_user}","gists_url":"https://api.github.com/users/rajinisivaram/gists{/gist_id}","starred_url":"https://api.github.com/users/rajinisivaram/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rajinisivaram/subscriptions","organizations_url":"https://api.github.com/users/rajinisivaram/orgs","repos_url":"https://api.github.com/users/rajinisivaram/repos","events_url":"https://api.github.com/users/rajinisivaram/events{/privacy}","received_events_url":"https://api.github.com/users/rajinisivaram/received_events","type":"User","site_admin":false},"body":"Support configuration of dynamic broker configs in ZooKeeper before starting brokers using ConfigCommand. This will allow password configs to be encrypted and stored in ZooKeeper, without requiring clear passwords in server.properties to bootstrap the broker first.\r\n\r\n### Committer Checklist (excluded from commit message)\r\n- [ ] Verify design and implementation \r\n- [ ] Verify test coverage and CI build status\r\n- [ ] Verify documentation (including upgrade notes)\r\n","created_at":"2018-04-19T15:47:19Z","updated_at":"2018-06-15T18:12:00Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4f8957b8b3f1d7fb3f3b0f92f25b4fc008db01b5","assignee":null,"assignees":[],"requested_reviewers":[{"login":"ijuma","id":24747,"node_id":"MDQ6VXNlcjI0NzQ3","avatar_url":"https://avatars2.githubusercontent.com/u/24747?v=4","gravatar_id":"","url":"https://api.github.com/users/ijuma","html_url":"https://github.com/ijuma","followers_url":"https://api.github.com/users/ijuma/followers","following_url":"https://api.github.com/users/ijuma/following{/other_user}","gists_url":"https://api.github.com/users/ijuma/gists{/gist_id}","starred_url":"https://api.github.com/users/ijuma/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ijuma/subscriptions","organizations_url":"https://api.github.com/users/ijuma/orgs","repos_url":"https://api.github.com/users/ijuma/repos","events_url":"https://api.github.com/users/ijuma/events{/privacy}","received_events_url":"https://api.github.com/users/ijuma/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/apache/kafka/pulls/4898/commits","review_comments_url":"https://api.github.com/repos/apache/kafka/pulls/4898/comments","review_comment_url":"https://api.github.com/repos/apache/kafka/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/kafka/issues/4898/comments","statuses_url":"https://api.github.com/repos/apache/kafka/statuses/ca1962db944794d47bfa9f2eb7d10afb534219a2","head":{"label":"rajinisivaram:KAFKA-6805-configcommand","ref":"KAFKA-6805-configcommand","sha":"ca1962db944794d47bfa9f2eb7d10afb534219a2","user":{"login":"rajinisivaram","id":13164074,"node_id":"MDQ6VXNlcjEzMTY0MDc0","avatar_url":"https://avatars0.githubusercontent.com/u/13164074?v=4","gravatar_id":"","url":"https://api.github.com/users/rajinisivaram","html_url":"https://github.com/rajinisivaram","followers_url":"https://api.github.com/users/rajinisivaram/followers","following_url":"https://api.github.com/users/rajinisivaram/following{/other_user}","gists_url":"https://api.github.com/users/rajinisivaram/gists{/gist_id}","starred_url":"https://api.github.com/users/rajinisivaram/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rajinisivaram/subscriptions","organizations_url":"https://api.github.com/users/rajinisivaram/orgs","repos_url":"https://api.github.com/users/rajinisivaram/repos","events_url":"https://api.github.com/users/rajinisivaram/events{/privacy}","received_events_url":"https://api.github.com/users/rajinisivaram/received_events","type":"User","site_admin":false},"repo":{"id":42296329,"node_id":"MDEwOlJlcG9zaXRvcnk0MjI5NjMyOQ==","name":"kafka","full_name":"rajinisivaram/kafka","owner":{"login":"rajinisivaram","id":13164074,"node_id":"MDQ6VXNlcjEzMTY0MDc0","avatar_url":"https://avatars0.githubusercontent.com/u/13164074?v=4","gravatar_id":"","url":"https://api.github.com/users/rajinisivaram","html_url":"https://github.com/rajinisivaram","followers_url":"https://api.github.com/users/rajinisivaram/followers","following_url":"https://api.github.com/users/rajinisivaram/following{/other_user}","gists_url":"https://api.github.com/users/rajinisivaram/gists{/gist_id}","starred_url":"https://api.github.com/users/rajinisivaram/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rajinisivaram/subscriptions","organizations_url":"https://api.github.com/users/rajinisivaram/orgs","repos_url":"https://api.github.com/users/rajinisivaram/repos","events_url":"https://api.github.com/users/rajinisivaram/events{/privacy}","received_events_url":"https://api.github.com/users/rajinisivaram/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/rajinisivaram/kafka","description":"Mirror of Apache Kafka","fork":true,"url":"https://api.github.com/repos/rajinisivaram/kafka","forks_url":"https://api.github.com/repos/rajinisivaram/kafka/forks","keys_url":"https://api.github.com/repos/rajinisivaram/kafka/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rajinisivaram/kafka/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rajinisivaram/kafka/teams","hooks_url":"https://api.github.com/repos/rajinisivaram/kafka/hooks","issue_events_url":"https://api.github.com/repos/rajinisivaram/kafka/issues/events{/number}","events_url":"https://api.github.com/repos/rajinisivaram/kafka/events","assignees_url":"https://api.github.com/repos/rajinisivaram/kafka/assignees{/user}","branches_url":"https://api.github.com/repos/rajinisivaram/kafka/branches{/branch}","tags_url":"https://api.github.com/repos/rajinisivaram/kafka/tags","blobs_url":"https://api.github.com/repos/rajinisivaram/kafka/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rajinisivaram/kafka/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rajinisivaram/kafka/git/refs{/sha}","trees_url":"https://api.github.com/repos/rajinisivaram/kafka/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rajinisivaram/kafka/statuses/{sha}","languages_url":"https://api.github.com/repos/rajinisivaram/kafka/languages","stargazers_url":"https://api.github.com/repos/rajinisivaram/kafka/stargazers","contributors_url":"https://api.github.com/repos/rajinisivaram/kafka/contributors","subscribers_url":"https://api.github.com/repos/rajinisivaram/kafka/subscribers","subscription_url":"https://api.github.com/repos/rajinisivaram/kafka/subscription","commits_url":"https://api.github.com/repos/rajinisivaram/kafka/commits{/sha}","git_commits_url":"https://api.github.com/repos/rajinisivaram/kafka/git/commits{/sha}","comments_url":"https://api.github.com/repos/rajinisivaram/kafka/comments{/number}","issue_comment_url":"https://api.github.com/repos/rajinisivaram/kafka/issues/comments{/number}","contents_url":"https://api.github.com/repos/rajinisivaram/kafka/contents/{+path}","compare_url":"https://api.github.com/repos/rajinisivaram/kafka/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rajinisivaram/kafka/merges","archive_url":"https://api.github.com/repos/rajinisivaram/kafka/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rajinisivaram/kafka/downloads","issues_url":"https://api.github.com/repos/rajinisivaram/kafka/issues{/number}","pulls_url":"https://api.github.com/repos/rajinisivaram/kafka/pulls{/number}","milestones_url":"https://api.github.com/repos/rajinisivaram/kafka/milestones{/number}","notifications_url":"https://api.github.com/repos/rajinisivaram/kafka/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rajinisivaram/kafka/labels{/name}","releases_url":"https://api.github.com/repos/rajinisivaram/kafka/releases{/id}","deployments_url":"https://api.github.com/repos/rajinisivaram/kafka/deployments","created_at":"2015-09-11T08:16:17Z","updated_at":"2018-06-04T14:52:17Z","pushed_at":"2018-06-15T07:38:22Z","git_url":"git://github.com/rajinisivaram/kafka.git","ssh_url":"git@github.com:rajinisivaram/kafka.git","clone_url":"https://github.com/rajinisivaram/kafka.git","svn_url":"https://github.com/rajinisivaram/kafka","homepage":null,"size":66413,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":1,"open_issues":0,"watchers":0,"default_branch":"trunk"}},"base":{"label":"apache:trunk","ref":"trunk","sha":"a4c292173618e22b3f99ab8615c6b585c7688a40","user":{"login":"apache","id":47359,"node_id":"MDEyOk9yZ2FuaXphdGlvbjQ3MzU5","avatar_url":"https://avatars0.githubusercontent.com/u/47359?v=4","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"repo":{"id":2211243,"node_id":"MDEwOlJlcG9zaXRvcnkyMjExMjQz","name":"kafka","full_name":"apache/kafka","owner":{"login":"apache","id":47359,"node_id":"MDEyOk9yZ2FuaXphdGlvbjQ3MzU5","avatar_url":"https://avatars0.githubusercontent.com/u/47359?v=4","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apache/kafka","description":"Mirror of Apache Kafka","fork":false,"url":"https://api.github.com/repos/apache/kafka","forks_url":"https://api.github.com/repos/apache/kafka/forks","keys_url":"https://api.github.com/repos/apache/kafka/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/kafka/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/kafka/teams","hooks_url":"https://api.github.com/repos/apache/kafka/hooks","issue_events_url":"https://api.github.com/repos/apache/kafka/issues/events{/number}","events_url":"https://api.github.com/repos/apache/kafka/events","assignees_url":"https://api.github.com/repos/apache/kafka/assignees{/user}","branches_url":"https://api.github.com/repos/apache/kafka/branches{/branch}","tags_url":"https://api.github.com/repos/apache/kafka/tags","blobs_url":"https://api.github.com/repos/apache/kafka/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/kafka/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/kafka/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/kafka/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/kafka/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/kafka/languages","stargazers_url":"https://api.github.com/repos/apache/kafka/stargazers","contributors_url":"https://api.github.com/repos/apache/kafka/contributors","subscribers_url":"https://api.github.com/repos/apache/kafka/subscribers","subscription_url":"https://api.github.com/repos/apache/kafka/subscription","commits_url":"https://api.github.com/repos/apache/kafka/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/kafka/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/kafka/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/kafka/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/kafka/contents/{+path}","compare_url":"https://api.github.com/repos/apache/kafka/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/kafka/merges","archive_url":"https://api.github.com/repos/apache/kafka/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/kafka/downloads","issues_url":"https://api.github.com/repos/apache/kafka/issues{/number}","pulls_url":"https://api.github.com/repos/apache/kafka/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/kafka/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/kafka/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/kafka/labels{/name}","releases_url":"https://api.github.com/repos/apache/kafka/releases{/id}","deployments_url":"https://api.github.com/repos/apache/kafka/deployments","created_at":"2011-08-15T18:06:16Z","updated_at":"2018-06-15T15:51:29Z","pushed_at":"2018-06-15T17:02:13Z","git_url":"git://github.com/apache/kafka.git","ssh_url":"git@github.com:apache/kafka.git","clone_url":"https://github.com/apache/kafka.git","svn_url":"https://github.com/apache/kafka","homepage":null,"size":67979,"stargazers_count":8652,"watchers_count":8652,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":5000,"mirror_url":null,"archived":false,"open_issues_count":458,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":5000,"open_issues":458,"watchers":8652,"default_branch":"trunk"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/kafka/pulls/4898"},"html":{"href":"https://github.com/apache/kafka/pull/4898"},"issue":{"href":"https://api.github.com/repos/apache/kafka/issues/4898"},"comments":{"href":"https://api.github.com/repos/apache/kafka/issues/4898/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/kafka/pulls/4898/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/kafka/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/kafka/pulls/4898/commits"},"statuses":{"href":"https://api.github.com/repos/apache/kafka/statuses/ca1962db944794d47bfa9f2eb7d10afb534219a2"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"hachikuji"}}