{"action":"created","comment":{"url":"https://api.github.com/repos/linkedin/gobblin/pulls/comments/41053987","id":41053987,"diff_hunk":"@@ -0,0 +1,598 @@\n+/*\n+ * Copyright (C) 2014-2015 LinkedIn Corp. All rights reserved.\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use\n+ * this file except in compliance with the License. You may obtain a copy of the\n+ * License at  http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software distributed\n+ * under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n+ * CONDITIONS OF ANY KIND, either express or implied.\n+ */\n+\n+package gobblin.yarn;\n+\n+import java.io.File;\n+import java.io.IOException;\n+import java.net.URI;\n+import java.nio.ByteBuffer;\n+import java.util.List;\n+import java.util.Map;\n+import java.util.UUID;\n+import java.util.concurrent.Callable;\n+import java.util.concurrent.Executors;\n+import java.util.concurrent.TimeUnit;\n+import javax.annotation.Nonnull;\n+\n+import org.apache.hadoop.conf.Configuration;\n+import org.apache.hadoop.fs.FileStatus;\n+import org.apache.hadoop.fs.FileSystem;\n+import org.apache.hadoop.fs.Path;\n+import org.apache.hadoop.io.DataOutputBuffer;\n+import org.apache.hadoop.security.Credentials;\n+import org.apache.hadoop.security.UserGroupInformation;\n+import org.apache.hadoop.security.token.Token;\n+import org.apache.hadoop.yarn.api.ApplicationConstants;\n+import org.apache.hadoop.yarn.api.protocolrecords.GetNewApplicationResponse;\n+import org.apache.hadoop.yarn.api.records.ApplicationId;\n+import org.apache.hadoop.yarn.api.records.ApplicationReport;\n+import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;\n+import org.apache.hadoop.yarn.api.records.ContainerLaunchContext;\n+import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;\n+import org.apache.hadoop.yarn.api.records.LocalResource;\n+import org.apache.hadoop.yarn.api.records.LocalResourceType;\n+import org.apache.hadoop.yarn.api.records.LocalResourceVisibility;\n+import org.apache.hadoop.yarn.api.records.Priority;\n+import org.apache.hadoop.yarn.api.records.Resource;\n+import org.apache.hadoop.yarn.api.records.YarnApplicationState;\n+import org.apache.hadoop.yarn.client.api.YarnClient;\n+import org.apache.hadoop.yarn.client.api.YarnClientApplication;\n+import org.apache.hadoop.yarn.conf.YarnConfiguration;\n+import org.apache.hadoop.yarn.exceptions.YarnException;\n+import org.apache.hadoop.yarn.util.Apps;\n+import org.apache.hadoop.yarn.util.ConverterUtils;\n+import org.apache.hadoop.yarn.util.Records;\n+import org.apache.helix.Criteria;\n+import org.apache.helix.HelixConnection;\n+import org.apache.helix.HelixManager;\n+import org.apache.helix.HelixManagerFactory;\n+import org.apache.helix.InstanceType;\n+import org.apache.helix.api.config.ClusterConfig;\n+import org.apache.helix.api.id.ClusterId;\n+import org.apache.helix.manager.zk.ZkHelixConnection;\n+import org.apache.helix.model.Message;\n+import org.apache.helix.model.StateModelDefinition;\n+import org.apache.helix.tools.StateModelConfigGenerator;\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+\n+import com.google.common.base.Optional;\n+import com.google.common.base.Splitter;\n+import com.google.common.base.Strings;\n+import com.google.common.base.Throwables;\n+import com.google.common.collect.Lists;\n+import com.google.common.collect.Maps;\n+import com.google.common.io.Closer;\n+import com.google.common.util.concurrent.FutureCallback;\n+import com.google.common.util.concurrent.Futures;\n+import com.google.common.util.concurrent.ListenableFuture;\n+import com.google.common.util.concurrent.ListeningExecutorService;\n+import com.google.common.util.concurrent.MoreExecutors;\n+import com.google.common.util.concurrent.Service;\n+import com.google.common.util.concurrent.ServiceManager;\n+\n+import com.typesafe.config.Config;\n+import com.typesafe.config.ConfigFactory;\n+\n+import gobblin.configuration.ConfigurationKeys;\n+import gobblin.util.ExecutorsUtils;\n+\n+\n+/**\n+ * A client driver to launch Gobblin as a Yarn application.\n+ *\n+ * <p>\n+ *   This class starts the {@link GobblinApplicationMaster}. Once the application is launched, this class\n+ *   periodically polls the status of the application through a {@link ListeningExecutorService}. If a\n+ *   shutdown signal is received, it sends a Helix {@link org.apache.helix.model.Message.MessageType#SCHEDULER_MSG}\n+ *   to the {@link GobblinApplicationMaster} asking it to shutdown and release all the allocated containers.\n+ * </p>\n+ *\n+ * @author ynli\n+ */\n+public class GobblinYarnAppLauncher {\n+\n+  private static final Logger LOGGER = LoggerFactory.getLogger(GobblinYarnAppLauncher.class);\n+\n+  private static final Splitter SPLITTER = Splitter.on(',').omitEmptyStrings().trimResults();\n+\n+  private final String appName;\n+  private final String appQueueName;\n+\n+  private final Config config;\n+\n+  private final HelixManager helixManager;\n+\n+  private final ServiceManager serviceManager;\n+\n+  private final Configuration yarnConfiguration;\n+  private final YarnClient yarnClient;\n+  private final FileSystem fs;\n+\n+  private final ListeningExecutorService applicationStatusMonitor;\n+\n+  private final String appMasterJvmArgs;\n+\n+  // Yarn application ID\n+  private volatile Optional<ApplicationId> applicationId = Optional.absent();\n+\n+  // This flag tells if the Yarn application has already completed. This is used to\n+  // tell if it is necessary to send a shutdown message to the ApplicationMaster.\n+  private volatile boolean applicationCompleted = false;\n+\n+  private volatile boolean stopped = false;\n+\n+  public GobblinYarnAppLauncher(Config config) throws IOException {\n+    this.config = config;\n+\n+    this.appName = config.getString(ConfigurationConstants.APPLICATION_NAME_KEY);\n+    this.appQueueName = config.getString(ConfigurationConstants.APP_QUEUE_KEY);\n+\n+    String zkConnectionString = config.getString(ConfigurationConstants.ZK_CONNECTION_STRING_KEY);\n+    LOGGER.info(\"Using ZooKeeper connection string: \" + zkConnectionString);\n+\n+    this.helixManager = HelixManagerFactory.getZKHelixManager(\n+        config.getString(ConfigurationConstants.HELIX_CLUSTER_NAME_KEY), YarnHelixUtils.getHostname(),\n+        InstanceType.SPECTATOR, zkConnectionString);\n+\n+    this.yarnConfiguration = new YarnConfiguration();\n+    this.yarnConfiguration.set(\"fs.automatic.close\", \"false\");\n+    this.yarnClient = YarnClient.createYarnClient();\n+    this.yarnClient.init(this.yarnConfiguration);\n+\n+    this.fs = config.hasPath(ConfigurationKeys.FS_URI_KEY) ?\n+        FileSystem.get(URI.create(config.getString(ConfigurationKeys.FS_URI_KEY)), this.yarnConfiguration) :\n+        FileSystem.get(this.yarnConfiguration);\n+\n+    List<Service> services = Lists.newArrayList();\n+    if (UserGroupInformation.isSecurityEnabled()) {\n+      LOGGER.info(\"Adding YarnAppSecurityManager since security is enabled\");\n+      services.add(new YarnAppSecurityManager(config, this.helixManager, this.fs));\n+    }\n+    this.serviceManager = new ServiceManager(services);\n+\n+    this.applicationStatusMonitor = MoreExecutors.listeningDecorator(Executors.newSingleThreadScheduledExecutor(\n+        ExecutorsUtils.newThreadFactory(Optional.of(LOGGER), Optional.of(\"GobblinYarnAppStatusMonitor\"))));\n+\n+    this.appMasterJvmArgs = Strings.nullToEmpty(config.getString(ConfigurationConstants.APP_MASTER_JVM_ARGS_KEY));\n+  }\n+\n+  /**\n+   * Launch a new Gobblin instance on Yarn.\n+   *\n+   * @throws IOException if there's something wrong launching the application\n+   * @throws YarnException if there's something wrong launching the application\n+   */\n+  public void launch() throws IOException, YarnException {\n+    createGobblinYarnHelixCluster();\n+\n+    try {\n+      this.helixManager.connect();\n+    } catch (Exception e) {\n+      LOGGER.error(\"HelixManager failed to connect\", e);\n+      throw Throwables.propagate(e);\n+    }\n+\n+    // Start all the services running in the ApplicationMaster\n+    this.serviceManager.startAsync();\n+\n+    this.yarnClient.start();\n+    this.applicationId = Optional.of(setupAndSubmitApplication());\n+\n+    ListenableFuture<ApplicationReport> appReportFuture =","path":"gobblin-yarn/src/main/java/gobblin/yarn/GobblinYarnAppLauncher.java","position":189,"original_position":192,"commit_id":"bfab54685f912541322c4ab64f4498f32081d1a9","original_commit_id":"f9bc130e002838430dbe3bf99c1bfb770225300b","user":{"login":"sahilTakiar","id":1282583,"avatar_url":"https://avatars.githubusercontent.com/u/1282583?v=3","gravatar_id":"","url":"https://api.github.com/users/sahilTakiar","html_url":"https://github.com/sahilTakiar","followers_url":"https://api.github.com/users/sahilTakiar/followers","following_url":"https://api.github.com/users/sahilTakiar/following{/other_user}","gists_url":"https://api.github.com/users/sahilTakiar/gists{/gist_id}","starred_url":"https://api.github.com/users/sahilTakiar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sahilTakiar/subscriptions","organizations_url":"https://api.github.com/users/sahilTakiar/orgs","repos_url":"https://api.github.com/users/sahilTakiar/repos","events_url":"https://api.github.com/users/sahilTakiar/events{/privacy}","received_events_url":"https://api.github.com/users/sahilTakiar/received_events","type":"User","site_admin":false},"body":"I see. In that case this approach is probably fine.\r\n\r\nAlthough I would consider either (1) using an `EventBus` so that instead you can use `Runnable` instead of `Callable`, or (2) using something like Akka's Actor model, or (3) making `appReport` an instance variable, and have a single thread pool with two scheduled threads: the first to check the `YarnApplicationState` and set `appReport` accordingly, and the second to see if `appReport` becomes non-null and act accordingly.","created_at":"2015-10-02T18:44:09Z","updated_at":"2015-10-02T18:44:09Z","html_url":"https://github.com/linkedin/gobblin/pull/339#discussion_r41053987","pull_request_url":"https://api.github.com/repos/linkedin/gobblin/pulls/339","_links":{"self":{"href":"https://api.github.com/repos/linkedin/gobblin/pulls/comments/41053987"},"html":{"href":"https://github.com/linkedin/gobblin/pull/339#discussion_r41053987"},"pull_request":{"href":"https://api.github.com/repos/linkedin/gobblin/pulls/339"}}},"pull_request":{"url":"https://api.github.com/repos/linkedin/gobblin/pulls/339","id":45729701,"html_url":"https://github.com/linkedin/gobblin/pull/339","diff_url":"https://github.com/linkedin/gobblin/pull/339.diff","patch_url":"https://github.com/linkedin/gobblin/pull/339.patch","issue_url":"https://api.github.com/repos/linkedin/gobblin/issues/339","number":339,"state":"open","locked":false,"title":"Gobblin on Yarn POC preview","user":{"login":"liyinan926","id":3709137,"avatar_url":"https://avatars.githubusercontent.com/u/3709137?v=3","gravatar_id":"","url":"https://api.github.com/users/liyinan926","html_url":"https://github.com/liyinan926","followers_url":"https://api.github.com/users/liyinan926/followers","following_url":"https://api.github.com/users/liyinan926/following{/other_user}","gists_url":"https://api.github.com/users/liyinan926/gists{/gist_id}","starred_url":"https://api.github.com/users/liyinan926/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/liyinan926/subscriptions","organizations_url":"https://api.github.com/users/liyinan926/orgs","repos_url":"https://api.github.com/users/liyinan926/repos","events_url":"https://api.github.com/users/liyinan926/events{/privacy}","received_events_url":"https://api.github.com/users/liyinan926/received_events","type":"User","site_admin":false},"body":"This is a preview PR for the Gobblin on Yarn POC. I am still testing this and particularly the part that handles security/authentication so this probably will be updated as I find and fix issues. I will schedule a meeting to go over this PR later this week. ","created_at":"2015-09-22T23:25:36Z","updated_at":"2015-10-02T18:44:09Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a57a9584e6ee79777cc3b65d35d4d70eb595c5d8","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/linkedin/gobblin/pulls/339/commits","review_comments_url":"https://api.github.com/repos/linkedin/gobblin/pulls/339/comments","review_comment_url":"https://api.github.com/repos/linkedin/gobblin/pulls/comments{/number}","comments_url":"https://api.github.com/repos/linkedin/gobblin/issues/339/comments","statuses_url":"https://api.github.com/repos/linkedin/gobblin/statuses/bfab54685f912541322c4ab64f4498f32081d1a9","head":{"label":"liyinan926:gobblin-yarn","ref":"gobblin-yarn","sha":"bfab54685f912541322c4ab64f4498f32081d1a9","user":{"login":"liyinan926","id":3709137,"avatar_url":"https://avatars.githubusercontent.com/u/3709137?v=3","gravatar_id":"","url":"https://api.github.com/users/liyinan926","html_url":"https://github.com/liyinan926","followers_url":"https://api.github.com/users/liyinan926/followers","following_url":"https://api.github.com/users/liyinan926/following{/other_user}","gists_url":"https://api.github.com/users/liyinan926/gists{/gist_id}","starred_url":"https://api.github.com/users/liyinan926/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/liyinan926/subscriptions","organizations_url":"https://api.github.com/users/liyinan926/orgs","repos_url":"https://api.github.com/users/liyinan926/repos","events_url":"https://api.github.com/users/liyinan926/events{/privacy}","received_events_url":"https://api.github.com/users/liyinan926/received_events","type":"User","site_admin":false},"repo":{"id":31117112,"name":"gobblin","full_name":"liyinan926/gobblin","owner":{"login":"liyinan926","id":3709137,"avatar_url":"https://avatars.githubusercontent.com/u/3709137?v=3","gravatar_id":"","url":"https://api.github.com/users/liyinan926","html_url":"https://github.com/liyinan926","followers_url":"https://api.github.com/users/liyinan926/followers","following_url":"https://api.github.com/users/liyinan926/following{/other_user}","gists_url":"https://api.github.com/users/liyinan926/gists{/gist_id}","starred_url":"https://api.github.com/users/liyinan926/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/liyinan926/subscriptions","organizations_url":"https://api.github.com/users/liyinan926/orgs","repos_url":"https://api.github.com/users/liyinan926/repos","events_url":"https://api.github.com/users/liyinan926/events{/privacy}","received_events_url":"https://api.github.com/users/liyinan926/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/liyinan926/gobblin","description":"","fork":true,"url":"https://api.github.com/repos/liyinan926/gobblin","forks_url":"https://api.github.com/repos/liyinan926/gobblin/forks","keys_url":"https://api.github.com/repos/liyinan926/gobblin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/liyinan926/gobblin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/liyinan926/gobblin/teams","hooks_url":"https://api.github.com/repos/liyinan926/gobblin/hooks","issue_events_url":"https://api.github.com/repos/liyinan926/gobblin/issues/events{/number}","events_url":"https://api.github.com/repos/liyinan926/gobblin/events","assignees_url":"https://api.github.com/repos/liyinan926/gobblin/assignees{/user}","branches_url":"https://api.github.com/repos/liyinan926/gobblin/branches{/branch}","tags_url":"https://api.github.com/repos/liyinan926/gobblin/tags","blobs_url":"https://api.github.com/repos/liyinan926/gobblin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/liyinan926/gobblin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/liyinan926/gobblin/git/refs{/sha}","trees_url":"https://api.github.com/repos/liyinan926/gobblin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/liyinan926/gobblin/statuses/{sha}","languages_url":"https://api.github.com/repos/liyinan926/gobblin/languages","stargazers_url":"https://api.github.com/repos/liyinan926/gobblin/stargazers","contributors_url":"https://api.github.com/repos/liyinan926/gobblin/contributors","subscribers_url":"https://api.github.com/repos/liyinan926/gobblin/subscribers","subscription_url":"https://api.github.com/repos/liyinan926/gobblin/subscription","commits_url":"https://api.github.com/repos/liyinan926/gobblin/commits{/sha}","git_commits_url":"https://api.github.com/repos/liyinan926/gobblin/git/commits{/sha}","comments_url":"https://api.github.com/repos/liyinan926/gobblin/comments{/number}","issue_comment_url":"https://api.github.com/repos/liyinan926/gobblin/issues/comments{/number}","contents_url":"https://api.github.com/repos/liyinan926/gobblin/contents/{+path}","compare_url":"https://api.github.com/repos/liyinan926/gobblin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/liyinan926/gobblin/merges","archive_url":"https://api.github.com/repos/liyinan926/gobblin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/liyinan926/gobblin/downloads","issues_url":"https://api.github.com/repos/liyinan926/gobblin/issues{/number}","pulls_url":"https://api.github.com/repos/liyinan926/gobblin/pulls{/number}","milestones_url":"https://api.github.com/repos/liyinan926/gobblin/milestones{/number}","notifications_url":"https://api.github.com/repos/liyinan926/gobblin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/liyinan926/gobblin/labels{/name}","releases_url":"https://api.github.com/repos/liyinan926/gobblin/releases{/id}","created_at":"2015-02-21T06:07:55Z","updated_at":"2015-05-05T00:31:33Z","pushed_at":"2015-10-02T00:11:45Z","git_url":"git://github.com/liyinan926/gobblin.git","ssh_url":"git@github.com:liyinan926/gobblin.git","clone_url":"https://github.com/liyinan926/gobblin.git","svn_url":"https://github.com/liyinan926/gobblin","homepage":null,"size":80551,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"linkedin:master","ref":"master","sha":"7aa94d83c69c89221048c398d3ce178f2e9b25cd","user":{"login":"linkedin","id":357098,"avatar_url":"https://avatars.githubusercontent.com/u/357098?v=3","gravatar_id":"","url":"https://api.github.com/users/linkedin","html_url":"https://github.com/linkedin","followers_url":"https://api.github.com/users/linkedin/followers","following_url":"https://api.github.com/users/linkedin/following{/other_user}","gists_url":"https://api.github.com/users/linkedin/gists{/gist_id}","starred_url":"https://api.github.com/users/linkedin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/linkedin/subscriptions","organizations_url":"https://api.github.com/users/linkedin/orgs","repos_url":"https://api.github.com/users/linkedin/repos","events_url":"https://api.github.com/users/linkedin/events{/privacy}","received_events_url":"https://api.github.com/users/linkedin/received_events","type":"Organization","site_admin":false},"repo":{"id":27392543,"name":"gobblin","full_name":"linkedin/gobblin","owner":{"login":"linkedin","id":357098,"avatar_url":"https://avatars.githubusercontent.com/u/357098?v=3","gravatar_id":"","url":"https://api.github.com/users/linkedin","html_url":"https://github.com/linkedin","followers_url":"https://api.github.com/users/linkedin/followers","following_url":"https://api.github.com/users/linkedin/following{/other_user}","gists_url":"https://api.github.com/users/linkedin/gists{/gist_id}","starred_url":"https://api.github.com/users/linkedin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/linkedin/subscriptions","organizations_url":"https://api.github.com/users/linkedin/orgs","repos_url":"https://api.github.com/users/linkedin/repos","events_url":"https://api.github.com/users/linkedin/events{/privacy}","received_events_url":"https://api.github.com/users/linkedin/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/linkedin/gobblin","description":"Universal data ingestion framework for Hadoop.","fork":false,"url":"https://api.github.com/repos/linkedin/gobblin","forks_url":"https://api.github.com/repos/linkedin/gobblin/forks","keys_url":"https://api.github.com/repos/linkedin/gobblin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/linkedin/gobblin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/linkedin/gobblin/teams","hooks_url":"https://api.github.com/repos/linkedin/gobblin/hooks","issue_events_url":"https://api.github.com/repos/linkedin/gobblin/issues/events{/number}","events_url":"https://api.github.com/repos/linkedin/gobblin/events","assignees_url":"https://api.github.com/repos/linkedin/gobblin/assignees{/user}","branches_url":"https://api.github.com/repos/linkedin/gobblin/branches{/branch}","tags_url":"https://api.github.com/repos/linkedin/gobblin/tags","blobs_url":"https://api.github.com/repos/linkedin/gobblin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/linkedin/gobblin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/linkedin/gobblin/git/refs{/sha}","trees_url":"https://api.github.com/repos/linkedin/gobblin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/linkedin/gobblin/statuses/{sha}","languages_url":"https://api.github.com/repos/linkedin/gobblin/languages","stargazers_url":"https://api.github.com/repos/linkedin/gobblin/stargazers","contributors_url":"https://api.github.com/repos/linkedin/gobblin/contributors","subscribers_url":"https://api.github.com/repos/linkedin/gobblin/subscribers","subscription_url":"https://api.github.com/repos/linkedin/gobblin/subscription","commits_url":"https://api.github.com/repos/linkedin/gobblin/commits{/sha}","git_commits_url":"https://api.github.com/repos/linkedin/gobblin/git/commits{/sha}","comments_url":"https://api.github.com/repos/linkedin/gobblin/comments{/number}","issue_comment_url":"https://api.github.com/repos/linkedin/gobblin/issues/comments{/number}","contents_url":"https://api.github.com/repos/linkedin/gobblin/contents/{+path}","compare_url":"https://api.github.com/repos/linkedin/gobblin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/linkedin/gobblin/merges","archive_url":"https://api.github.com/repos/linkedin/gobblin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/linkedin/gobblin/downloads","issues_url":"https://api.github.com/repos/linkedin/gobblin/issues{/number}","pulls_url":"https://api.github.com/repos/linkedin/gobblin/pulls{/number}","milestones_url":"https://api.github.com/repos/linkedin/gobblin/milestones{/number}","notifications_url":"https://api.github.com/repos/linkedin/gobblin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/linkedin/gobblin/labels{/name}","releases_url":"https://api.github.com/repos/linkedin/gobblin/releases{/id}","created_at":"2014-12-01T18:10:50Z","updated_at":"2015-10-02T05:16:08Z","pushed_at":"2015-10-02T18:25:32Z","git_url":"git://github.com/linkedin/gobblin.git","ssh_url":"git@github.com:linkedin/gobblin.git","clone_url":"https://github.com/linkedin/gobblin.git","svn_url":"https://github.com/linkedin/gobblin","homepage":"https://github.com/linkedin/gobblin/wiki","size":161089,"stargazers_count":204,"watchers_count":204,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":70,"mirror_url":null,"open_issues_count":9,"forks":70,"open_issues":9,"watchers":204,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/linkedin/gobblin/pulls/339"},"html":{"href":"https://github.com/linkedin/gobblin/pull/339"},"issue":{"href":"https://api.github.com/repos/linkedin/gobblin/issues/339"},"comments":{"href":"https://api.github.com/repos/linkedin/gobblin/issues/339/comments"},"review_comments":{"href":"https://api.github.com/repos/linkedin/gobblin/pulls/339/comments"},"review_comment":{"href":"https://api.github.com/repos/linkedin/gobblin/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/linkedin/gobblin/pulls/339/commits"},"statuses":{"href":"https://api.github.com/repos/linkedin/gobblin/statuses/bfab54685f912541322c4ab64f4498f32081d1a9"}}}}