{"action":"created","comment":{"url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments/38880976","id":38880976,"diff_hunk":"@@ -0,0 +1,475 @@\n+/*\n+Copyright 2015 The Kubernetes Authors All rights reserved.\n+\n+Licensed under the Apache License, Version 2.0 (the \"License\");\n+you may not use this file except in compliance with the License.\n+You may obtain a copy of the License at\n+\n+    http://www.apache.org/licenses/LICENSE-2.0\n+\n+Unless required by applicable law or agreed to in writing, software\n+distributed under the License is distributed on an \"AS IS\" BASIS,\n+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+See the License for the specific language governing permissions and\n+limitations under the License.\n+*/\n+\n+package daemon\n+\n+import (\n+\t\"reflect\"\n+\t\"time\"\n+\n+\t\"github.com/golang/glog\"\n+\t\"k8s.io/kubernetes/pkg/api\"\n+\tclient \"k8s.io/kubernetes/pkg/client/unversioned\"\n+\t\"k8s.io/kubernetes/pkg/client/unversioned/cache\"\n+\t\"k8s.io/kubernetes/pkg/client/unversioned/record\"\n+\t\"k8s.io/kubernetes/pkg/controller\"\n+\t\"k8s.io/kubernetes/pkg/controller/framework\"\n+\t\"k8s.io/kubernetes/pkg/expapi\"\n+\t\"k8s.io/kubernetes/pkg/fields\"\n+\t\"k8s.io/kubernetes/pkg/labels\"\n+\t\"k8s.io/kubernetes/pkg/runtime\"\n+\t\"k8s.io/kubernetes/pkg/util\"\n+\t\"k8s.io/kubernetes/pkg/util/workqueue\"\n+\t\"k8s.io/kubernetes/pkg/watch\"\n+)\n+\n+const (\n+\t// Daemons will periodically check that their daemon pods are running as expected.\n+\tFullDaemonResyncPeriod = 30 * time.Second // TODO: Figure out if this time seems reasonable.\n+\t// Nodes don't need relisting.\n+\tFullNodeResyncPeriod = 0\n+\t// Daemon pods don't need relisting.\n+\tFullDaemonPodResyncPeriod = 0\n+\t// If sending a status upate to API server fails, we retry a finite number of times.\n+\tStatusUpdateRetries = 1\n+)\n+\n+type DaemonManager struct {\n+\tkubeClient client.Interface\n+\tpodControl controller.PodControlInterface\n+\n+\t// To allow injection of syncDaemon for testing.\n+\tsyncHandler func(dcKey string) error\n+\t// A TTLCache of pod creates/deletes each dc expects to see\n+\texpectations controller.ControllerExpectationsInterface\n+\t// A store of daemons, populated by the podController.\n+\tdcStore cache.StoreToDaemonLister\n+\t// A store of pods, populated by the podController\n+\tpodStore cache.StoreToPodLister\n+\t// A store of pods, populated by the podController\n+\tnodeStore cache.StoreToNodeLister\n+\t// Watches changes to all pods.\n+\tdcController *framework.Controller\n+\t// Watches changes to all pods\n+\tpodController *framework.Controller\n+\t// Watches changes to all nodes.\n+\tnodeController *framework.Controller\n+\t// Controllers that need to be updated.\n+\tqueue *workqueue.Type\n+}\n+\n+func NewDaemonManager(kubeClient client.Interface) *DaemonManager {\n+\teventBroadcaster := record.NewBroadcaster()\n+\teventBroadcaster.StartLogging(glog.Infof)\n+\teventBroadcaster.StartRecordingToSink(kubeClient.Events(\"\"))\n+\n+\tdm := &DaemonManager{\n+\t\tkubeClient: kubeClient,\n+\t\tpodControl: controller.RealPodControl{\n+\t\t\tKubeClient: kubeClient,\n+\t\t\tRecorder:   eventBroadcaster.NewRecorder(api.EventSource{Component: \"daemon\"}),\n+\t\t},\n+\t\texpectations: controller.NewControllerExpectations(),\n+\t\tqueue:        workqueue.New(),\n+\t}\n+\t// Manage addition/update of daemon controllers.\n+\tdm.dcStore.Store, dm.dcController = framework.NewInformer(\n+\t\t&cache.ListWatch{\n+\t\t\tListFunc: func() (runtime.Object, error) {\n+\t\t\t\treturn dm.kubeClient.Experimental().Daemons(api.NamespaceAll).List(labels.Everything())\n+\t\t\t},\n+\t\t\tWatchFunc: func(rv string) (watch.Interface, error) {\n+\t\t\t\treturn dm.kubeClient.Experimental().Daemons(api.NamespaceAll).Watch(labels.Everything(), fields.Everything(), rv)\n+\t\t\t},\n+\t\t},\n+\t\t&expapi.Daemon{},\n+\t\tFullDaemonResyncPeriod,\n+\t\tframework.ResourceEventHandlerFuncs{\n+\t\t\tAddFunc: func(obj interface{}) {\n+\t\t\t\tdaemon := obj.(*expapi.Daemon)\n+\t\t\t\tglog.V(4).Infof(\"Adding daemon %s\", daemon.Name)\n+\t\t\t\tdm.enqueueController(obj)\n+\t\t\t},\n+\t\t\tUpdateFunc: func(old, cur interface{}) {\n+\t\t\t\toldDaemon := old.(*expapi.Daemon)\n+\t\t\t\tglog.V(4).Infof(\"Updating daemon %s\", oldDaemon.Name)\n+\t\t\t\tdm.enqueueController(cur)\n+\t\t\t},\n+\t\t\tDeleteFunc: func(obj interface{}) {\n+\t\t\t\tdaemon := obj.(*expapi.Daemon)\n+\t\t\t\tglog.V(4).Infof(\"Deleting daemon %s\", daemon.Name)\n+\t\t\t\tdm.enqueueController(obj)\n+\t\t\t},\n+\t\t},\n+\t)\n+\t// Watch for creation/deletion of pods. The reason we watch is that we don't want a daemon controller to create/delete\n+\t// more pods until all the effects (expectations) of a daemon controller's create/delete have been observed.\n+\tdm.podStore.Store, dm.podController = framework.NewInformer(\n+\t\t&cache.ListWatch{\n+\t\t\tListFunc: func() (runtime.Object, error) {\n+\t\t\t\treturn dm.kubeClient.Pods(api.NamespaceAll).List(labels.Everything(), fields.Everything())\n+\t\t\t},\n+\t\t\tWatchFunc: func(rv string) (watch.Interface, error) {\n+\t\t\t\treturn dm.kubeClient.Pods(api.NamespaceAll).Watch(labels.Everything(), fields.Everything(), rv)\n+\t\t\t},\n+\t\t},\n+\t\t&api.Pod{},\n+\t\tFullDaemonPodResyncPeriod,\n+\t\tframework.ResourceEventHandlerFuncs{\n+\t\t\tAddFunc:    dm.addPod,\n+\t\t\tUpdateFunc: dm.updatePod,\n+\t\t\tDeleteFunc: dm.deletePod,\n+\t\t},\n+\t)\n+\t// Watch for new nodes or updates to nodes - daemons are launched on new nodes, and possibly when labels on nodes change,\n+\tdm.nodeStore.Store, dm.nodeController = framework.NewInformer(\n+\t\t&cache.ListWatch{\n+\t\t\tListFunc: func() (runtime.Object, error) {\n+\t\t\t\treturn dm.kubeClient.Nodes().List(labels.Everything(), fields.Everything())\n+\t\t\t},\n+\t\t\tWatchFunc: func(rv string) (watch.Interface, error) {\n+\t\t\t\treturn dm.kubeClient.Nodes().Watch(labels.Everything(), fields.Everything(), rv)\n+\t\t\t},\n+\t\t},\n+\t\t&api.Node{},\n+\t\tFullNodeResyncPeriod,\n+\t\tframework.ResourceEventHandlerFuncs{\n+\t\t\tAddFunc:    dm.addNode,\n+\t\t\tUpdateFunc: dm.updateNode,\n+\t\t\tDeleteFunc: func(node interface{}) {},\n+\t\t},\n+\t)\n+\tdm.syncHandler = dm.syncDaemon\n+\treturn dm\n+}\n+\n+// Run begins watching and syncing daemons.\n+func (dm *DaemonManager) Run(workers int, stopCh <-chan struct{}) {\n+\tgo dm.dcController.Run(stopCh)\n+\tgo dm.podController.Run(stopCh)\n+\tgo dm.nodeController.Run(stopCh)\n+\tfor i := 0; i < workers; i++ {\n+\t\tgo util.Until(dm.worker, time.Second, stopCh)\n+\t}\n+\t<-stopCh\n+\tglog.Infof(\"Shutting down Daemon Controller Manager\")\n+\tdm.queue.ShutDown()\n+}\n+\n+func (dm *DaemonManager) worker() {\n+\tfor {\n+\t\tfunc() {\n+\t\t\tkey, quit := dm.queue.Get()\n+\t\t\tif quit {\n+\t\t\t\treturn\n+\t\t\t}\n+\t\t\tdefer dm.queue.Done(key)\n+\t\t\terr := dm.syncHandler(key.(string))\n+\t\t\tif err != nil {\n+\t\t\t\tglog.Errorf(\"Error syncing daemon controller with key %s: %v\", key.(string), err)\n+\t\t\t}\n+\t\t}()\n+\t}\n+}\n+\n+func (dm *DaemonManager) enqueueAllDaemons() {\n+\tglog.V(4).Infof(\"Enqueueing all daemons\")\n+\tdaemons, err := dm.dcStore.List()\n+\tif err != nil {\n+\t\tglog.Errorf(\"Error enqueueing daemon controllers: %v\", err)\n+\t\treturn\n+\t}\n+\tfor i := range daemons {\n+\t\tdm.enqueueController(&daemons[i])\n+\t}\n+}\n+\n+func (dm *DaemonManager) enqueueController(obj interface{}) {\n+\tkey, err := controller.KeyFunc(obj)\n+\tif err != nil {\n+\t\tglog.Errorf(\"Couldn't get key for object %+v: %v\", obj, err)\n+\t\treturn\n+\t}\n+\tdm.queue.Add(key)\n+}\n+\n+func (dm *DaemonManager) getPodDaemon(pod *api.Pod) *expapi.Daemon {\n+\tcontrollers, err := dm.dcStore.GetPodDaemons(pod)\n+\tif err != nil {\n+\t\tglog.V(4).Infof(\"No controllers found for pod %v, daemon manager will avoid syncing\", pod.Name)\n+\t\treturn nil\n+\t}\n+\treturn &controllers[0]\n+}\n+\n+func (dm *DaemonManager) addPod(obj interface{}) {\n+\tpod := obj.(*api.Pod)\n+\tglog.V(4).Infof(\"Pod %s added.\", pod.Name)\n+\tif dc := dm.getPodDaemon(pod); dc != nil {\n+\t\tdcKey, err := controller.KeyFunc(dc)\n+\t\tif err != nil {\n+\t\t\tglog.Errorf(\"Couldn't get key for object %+v: %v\", dc, err)\n+\t\t\treturn\n+\t\t}\n+\t\tdm.expectations.CreationObserved(dcKey)\n+\t\tdm.enqueueController(dc)\n+\t}\n+}\n+\n+// When a pod is updated, figure out what controller/s manage it and wake them\n+// up. If the labels of the pod have changed we need to awaken both the old\n+// and new controller. old and cur must be *api.Pod types.\n+func (dm *DaemonManager) updatePod(old, cur interface{}) {\n+\tif api.Semantic.DeepEqual(old, cur) {\n+\t\t// A periodic relist will send update events for all known pods.\n+\t\treturn\n+\t}\n+\tcurPod := cur.(*api.Pod)\n+\tglog.V(4).Infof(\"Pod %s updated.\", curPod.Name)\n+\tif dc := dm.getPodDaemon(curPod); dc != nil {\n+\t\tdm.enqueueController(dc)\n+\t}\n+\toldPod := old.(*api.Pod)\n+\t// If the labels have not changed, then the daemon controller responsible for\n+\t// the pod is the same as it was before. In that case we have enqueued the daemon\n+\t// controller above, and do not have to enqueue the controller again.\n+\tif !reflect.DeepEqual(curPod.Labels, oldPod.Labels) {\n+\t\t// If the old and new dc are the same, the first one that syncs\n+\t\t// will set expectations preventing any damage from the second.\n+\t\tif oldRC := dm.getPodDaemon(oldPod); oldRC != nil {","path":"pkg/controller/daemon/manager.go","position":252,"original_position":252,"commit_id":"a58704e18139c0efa970d74d1caee74f7897dc0b","original_commit_id":"a58704e18139c0efa970d74d1caee74f7897dc0b","user":{"login":"davidopp","id":8264113,"avatar_url":"https://avatars.githubusercontent.com/u/8264113?v=3","gravatar_id":"","url":"https://api.github.com/users/davidopp","html_url":"https://github.com/davidopp","followers_url":"https://api.github.com/users/davidopp/followers","following_url":"https://api.github.com/users/davidopp/following{/other_user}","gists_url":"https://api.github.com/users/davidopp/gists{/gist_id}","starred_url":"https://api.github.com/users/davidopp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/davidopp/subscriptions","organizations_url":"https://api.github.com/users/davidopp/orgs","repos_url":"https://api.github.com/users/davidopp/repos","events_url":"https://api.github.com/users/davidopp/events{/privacy}","received_events_url":"https://api.github.com/users/davidopp/received_events","type":"User","site_admin":false},"body":"oldDC would be a better variable name","created_at":"2015-09-07T22:14:14Z","updated_at":"2015-09-07T22:14:14Z","html_url":"https://github.com/kubernetes/kubernetes/pull/13182#discussion_r38880976","pull_request_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13182","_links":{"self":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments/38880976"},"html":{"href":"https://github.com/kubernetes/kubernetes/pull/13182#discussion_r38880976"},"pull_request":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13182"}}},"pull_request":{"url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13182","id":43374418,"html_url":"https://github.com/kubernetes/kubernetes/pull/13182","diff_url":"https://github.com/kubernetes/kubernetes/pull/13182.diff","patch_url":"https://github.com/kubernetes/kubernetes/pull/13182.patch","issue_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/13182","number":13182,"state":"open","locked":false,"title":"Add daemon controller","user":{"login":"mikedanese","id":1787169,"avatar_url":"https://avatars.githubusercontent.com/u/1787169?v=3","gravatar_id":"","url":"https://api.github.com/users/mikedanese","html_url":"https://github.com/mikedanese","followers_url":"https://api.github.com/users/mikedanese/followers","following_url":"https://api.github.com/users/mikedanese/following{/other_user}","gists_url":"https://api.github.com/users/mikedanese/gists{/gist_id}","starred_url":"https://api.github.com/users/mikedanese/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mikedanese/subscriptions","organizations_url":"https://api.github.com/users/mikedanese/orgs","repos_url":"https://api.github.com/users/mikedanese/repos","events_url":"https://api.github.com/users/mikedanese/events{/privacy}","received_events_url":"https://api.github.com/users/mikedanese/received_events","type":"User","site_admin":false},"body":"This PR contains the daemon controller code.\r\n\r\nDepends on #13181 (first 4 commits). Last 3 commits should be reviewed here.\r\n\r\ncc @vishh @bgrant0607 @davidopp @AnanyaKumar ","created_at":"2015-08-26T08:04:55Z","updated_at":"2015-09-07T22:14:14Z","closed_at":null,"merged_at":null,"merge_commit_sha":"21e945699ce1741e3e4bbbd25ee23379b150b3e4","assignee":{"login":"davidopp","id":8264113,"avatar_url":"https://avatars.githubusercontent.com/u/8264113?v=3","gravatar_id":"","url":"https://api.github.com/users/davidopp","html_url":"https://github.com/davidopp","followers_url":"https://api.github.com/users/davidopp/followers","following_url":"https://api.github.com/users/davidopp/following{/other_user}","gists_url":"https://api.github.com/users/davidopp/gists{/gist_id}","starred_url":"https://api.github.com/users/davidopp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/davidopp/subscriptions","organizations_url":"https://api.github.com/users/davidopp/orgs","repos_url":"https://api.github.com/users/davidopp/repos","events_url":"https://api.github.com/users/davidopp/events{/privacy}","received_events_url":"https://api.github.com/users/davidopp/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13182/commits","review_comments_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13182/comments","review_comment_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments{/number}","comments_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/13182/comments","statuses_url":"https://api.github.com/repos/kubernetes/kubernetes/statuses/a58704e18139c0efa970d74d1caee74f7897dc0b","head":{"label":"mikedanese:daemon_manager","ref":"daemon_manager","sha":"a58704e18139c0efa970d74d1caee74f7897dc0b","user":{"login":"mikedanese","id":1787169,"avatar_url":"https://avatars.githubusercontent.com/u/1787169?v=3","gravatar_id":"","url":"https://api.github.com/users/mikedanese","html_url":"https://github.com/mikedanese","followers_url":"https://api.github.com/users/mikedanese/followers","following_url":"https://api.github.com/users/mikedanese/following{/other_user}","gists_url":"https://api.github.com/users/mikedanese/gists{/gist_id}","starred_url":"https://api.github.com/users/mikedanese/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mikedanese/subscriptions","organizations_url":"https://api.github.com/users/mikedanese/orgs","repos_url":"https://api.github.com/users/mikedanese/repos","events_url":"https://api.github.com/users/mikedanese/events{/privacy}","received_events_url":"https://api.github.com/users/mikedanese/received_events","type":"User","site_admin":false},"repo":{"id":26203986,"name":"kubernetes","full_name":"mikedanese/kubernetes","owner":{"login":"mikedanese","id":1787169,"avatar_url":"https://avatars.githubusercontent.com/u/1787169?v=3","gravatar_id":"","url":"https://api.github.com/users/mikedanese","html_url":"https://github.com/mikedanese","followers_url":"https://api.github.com/users/mikedanese/followers","following_url":"https://api.github.com/users/mikedanese/following{/other_user}","gists_url":"https://api.github.com/users/mikedanese/gists{/gist_id}","starred_url":"https://api.github.com/users/mikedanese/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mikedanese/subscriptions","organizations_url":"https://api.github.com/users/mikedanese/orgs","repos_url":"https://api.github.com/users/mikedanese/repos","events_url":"https://api.github.com/users/mikedanese/events{/privacy}","received_events_url":"https://api.github.com/users/mikedanese/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mikedanese/kubernetes","description":"Container Cluster Manager","fork":true,"url":"https://api.github.com/repos/mikedanese/kubernetes","forks_url":"https://api.github.com/repos/mikedanese/kubernetes/forks","keys_url":"https://api.github.com/repos/mikedanese/kubernetes/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mikedanese/kubernetes/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mikedanese/kubernetes/teams","hooks_url":"https://api.github.com/repos/mikedanese/kubernetes/hooks","issue_events_url":"https://api.github.com/repos/mikedanese/kubernetes/issues/events{/number}","events_url":"https://api.github.com/repos/mikedanese/kubernetes/events","assignees_url":"https://api.github.com/repos/mikedanese/kubernetes/assignees{/user}","branches_url":"https://api.github.com/repos/mikedanese/kubernetes/branches{/branch}","tags_url":"https://api.github.com/repos/mikedanese/kubernetes/tags","blobs_url":"https://api.github.com/repos/mikedanese/kubernetes/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mikedanese/kubernetes/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mikedanese/kubernetes/git/refs{/sha}","trees_url":"https://api.github.com/repos/mikedanese/kubernetes/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mikedanese/kubernetes/statuses/{sha}","languages_url":"https://api.github.com/repos/mikedanese/kubernetes/languages","stargazers_url":"https://api.github.com/repos/mikedanese/kubernetes/stargazers","contributors_url":"https://api.github.com/repos/mikedanese/kubernetes/contributors","subscribers_url":"https://api.github.com/repos/mikedanese/kubernetes/subscribers","subscription_url":"https://api.github.com/repos/mikedanese/kubernetes/subscription","commits_url":"https://api.github.com/repos/mikedanese/kubernetes/commits{/sha}","git_commits_url":"https://api.github.com/repos/mikedanese/kubernetes/git/commits{/sha}","comments_url":"https://api.github.com/repos/mikedanese/kubernetes/comments{/number}","issue_comment_url":"https://api.github.com/repos/mikedanese/kubernetes/issues/comments{/number}","contents_url":"https://api.github.com/repos/mikedanese/kubernetes/contents/{+path}","compare_url":"https://api.github.com/repos/mikedanese/kubernetes/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mikedanese/kubernetes/merges","archive_url":"https://api.github.com/repos/mikedanese/kubernetes/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mikedanese/kubernetes/downloads","issues_url":"https://api.github.com/repos/mikedanese/kubernetes/issues{/number}","pulls_url":"https://api.github.com/repos/mikedanese/kubernetes/pulls{/number}","milestones_url":"https://api.github.com/repos/mikedanese/kubernetes/milestones{/number}","notifications_url":"https://api.github.com/repos/mikedanese/kubernetes/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mikedanese/kubernetes/labels{/name}","releases_url":"https://api.github.com/repos/mikedanese/kubernetes/releases{/id}","created_at":"2014-11-05T05:02:25Z","updated_at":"2015-04-15T00:20:12Z","pushed_at":"2015-09-04T20:14:58Z","git_url":"git://github.com/mikedanese/kubernetes.git","ssh_url":"git@github.com:mikedanese/kubernetes.git","clone_url":"https://github.com/mikedanese/kubernetes.git","svn_url":"https://github.com/mikedanese/kubernetes","homepage":null,"size":104818,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"kubernetes:master","ref":"master","sha":"49702f905979491d402b3a77360d13dc15845c8c","user":{"login":"kubernetes","id":13629408,"avatar_url":"https://avatars.githubusercontent.com/u/13629408?v=3","gravatar_id":"","url":"https://api.github.com/users/kubernetes","html_url":"https://github.com/kubernetes","followers_url":"https://api.github.com/users/kubernetes/followers","following_url":"https://api.github.com/users/kubernetes/following{/other_user}","gists_url":"https://api.github.com/users/kubernetes/gists{/gist_id}","starred_url":"https://api.github.com/users/kubernetes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kubernetes/subscriptions","organizations_url":"https://api.github.com/users/kubernetes/orgs","repos_url":"https://api.github.com/users/kubernetes/repos","events_url":"https://api.github.com/users/kubernetes/events{/privacy}","received_events_url":"https://api.github.com/users/kubernetes/received_events","type":"Organization","site_admin":false},"repo":{"id":20580498,"name":"kubernetes","full_name":"kubernetes/kubernetes","owner":{"login":"kubernetes","id":13629408,"avatar_url":"https://avatars.githubusercontent.com/u/13629408?v=3","gravatar_id":"","url":"https://api.github.com/users/kubernetes","html_url":"https://github.com/kubernetes","followers_url":"https://api.github.com/users/kubernetes/followers","following_url":"https://api.github.com/users/kubernetes/following{/other_user}","gists_url":"https://api.github.com/users/kubernetes/gists{/gist_id}","starred_url":"https://api.github.com/users/kubernetes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kubernetes/subscriptions","organizations_url":"https://api.github.com/users/kubernetes/orgs","repos_url":"https://api.github.com/users/kubernetes/repos","events_url":"https://api.github.com/users/kubernetes/events{/privacy}","received_events_url":"https://api.github.com/users/kubernetes/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/kubernetes/kubernetes","description":"Container Cluster Manager from Google","fork":false,"url":"https://api.github.com/repos/kubernetes/kubernetes","forks_url":"https://api.github.com/repos/kubernetes/kubernetes/forks","keys_url":"https://api.github.com/repos/kubernetes/kubernetes/keys{/key_id}","collaborators_url":"https://api.github.com/repos/kubernetes/kubernetes/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/kubernetes/kubernetes/teams","hooks_url":"https://api.github.com/repos/kubernetes/kubernetes/hooks","issue_events_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/events{/number}","events_url":"https://api.github.com/repos/kubernetes/kubernetes/events","assignees_url":"https://api.github.com/repos/kubernetes/kubernetes/assignees{/user}","branches_url":"https://api.github.com/repos/kubernetes/kubernetes/branches{/branch}","tags_url":"https://api.github.com/repos/kubernetes/kubernetes/tags","blobs_url":"https://api.github.com/repos/kubernetes/kubernetes/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/kubernetes/kubernetes/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/kubernetes/kubernetes/git/refs{/sha}","trees_url":"https://api.github.com/repos/kubernetes/kubernetes/git/trees{/sha}","statuses_url":"https://api.github.com/repos/kubernetes/kubernetes/statuses/{sha}","languages_url":"https://api.github.com/repos/kubernetes/kubernetes/languages","stargazers_url":"https://api.github.com/repos/kubernetes/kubernetes/stargazers","contributors_url":"https://api.github.com/repos/kubernetes/kubernetes/contributors","subscribers_url":"https://api.github.com/repos/kubernetes/kubernetes/subscribers","subscription_url":"https://api.github.com/repos/kubernetes/kubernetes/subscription","commits_url":"https://api.github.com/repos/kubernetes/kubernetes/commits{/sha}","git_commits_url":"https://api.github.com/repos/kubernetes/kubernetes/git/commits{/sha}","comments_url":"https://api.github.com/repos/kubernetes/kubernetes/comments{/number}","issue_comment_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/comments{/number}","contents_url":"https://api.github.com/repos/kubernetes/kubernetes/contents/{+path}","compare_url":"https://api.github.com/repos/kubernetes/kubernetes/compare/{base}...{head}","merges_url":"https://api.github.com/repos/kubernetes/kubernetes/merges","archive_url":"https://api.github.com/repos/kubernetes/kubernetes/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/kubernetes/kubernetes/downloads","issues_url":"https://api.github.com/repos/kubernetes/kubernetes/issues{/number}","pulls_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls{/number}","milestones_url":"https://api.github.com/repos/kubernetes/kubernetes/milestones{/number}","notifications_url":"https://api.github.com/repos/kubernetes/kubernetes/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/kubernetes/kubernetes/labels{/name}","releases_url":"https://api.github.com/repos/kubernetes/kubernetes/releases{/id}","created_at":"2014-06-06T22:56:04Z","updated_at":"2015-09-07T19:31:42Z","pushed_at":"2015-09-07T20:09:33Z","git_url":"git://github.com/kubernetes/kubernetes.git","ssh_url":"git@github.com:kubernetes/kubernetes.git","clone_url":"https://github.com/kubernetes/kubernetes.git","svn_url":"https://github.com/kubernetes/kubernetes","homepage":"http://kubernetes.io","size":393079,"stargazers_count":10106,"watchers_count":10106,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":2469,"mirror_url":null,"open_issues_count":1684,"forks":2469,"open_issues":1684,"watchers":10106,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13182"},"html":{"href":"https://github.com/kubernetes/kubernetes/pull/13182"},"issue":{"href":"https://api.github.com/repos/kubernetes/kubernetes/issues/13182"},"comments":{"href":"https://api.github.com/repos/kubernetes/kubernetes/issues/13182/comments"},"review_comments":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13182/comments"},"review_comment":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13182/commits"},"statuses":{"href":"https://api.github.com/repos/kubernetes/kubernetes/statuses/a58704e18139c0efa970d74d1caee74f7897dc0b"}}}}