{"action":"created","comment":{"url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments/74542307","id":74542307,"diff_hunk":"@@ -123,184 +104,54 @@ HTTP server: The kubelet can also listen for HTTP and respond to a simple API\n \treturn cmd\n }\n \n-// UnsecuredKubeletConfig returns a KubeletConfig suitable for being run, or an error if the server setup\n+// UnsecuredKubeletDeps returns a KubeletDeps suitable for being run, or an error if the server setup\n // is not valid.  It will not start any background processes, and does not include authentication/authorization\n-func UnsecuredKubeletConfig(s *options.KubeletServer) (*KubeletConfig, error) {\n-\thostNetworkSources, err := kubetypes.GetValidatedSources(s.HostNetworkSources)\n-\tif err != nil {\n-\t\treturn nil, err\n-\t}\n+func UnsecuredKubeletDeps(s *options.KubeletServer) (*kubelet.KubeletDeps, error) {\n \n-\thostPIDSources, err := kubetypes.GetValidatedSources(s.HostPIDSources)\n-\tif err != nil {\n-\t\treturn nil, err\n-\t}\n-\n-\thostIPCSources, err := kubetypes.GetValidatedSources(s.HostIPCSources)\n+\t// Initialize the TLS Options\n+\ttlsOptions, err := InitializeTLS(&s.KubeletConfiguration)\n \tif err != nil {\n \t\treturn nil, err\n \t}\n \n \tmounter := mount.New()\n-\tvar writer io.Writer = &io.StdWriter{}\n+\tvar writer kubeio.Writer = &kubeio.StdWriter{}\n \tif s.Containerized {\n \t\tglog.V(2).Info(\"Running kubelet in containerized mode (experimental)\")\n \t\tmounter = mount.NewNsenterMounter()\n-\t\twriter = &io.NsenterWriter{}\n-\t}\n-\n-\ttlsOptions, err := InitializeTLS(s)\n-\tif err != nil {\n-\t\treturn nil, err\n-\t}\n-\n-\tvar dockerExecHandler dockertools.ExecHandler\n-\tswitch s.DockerExecHandlerName {\n-\tcase \"native\":\n-\t\tdockerExecHandler = &dockertools.NativeExecHandler{}\n-\tcase \"nsenter\":\n-\t\tdockerExecHandler = &dockertools.NsenterExecHandler{}\n-\tdefault:\n-\t\tglog.Warningf(\"Unknown Docker exec handler %q; defaulting to native\", s.DockerExecHandlerName)\n-\t\tdockerExecHandler = &dockertools.NativeExecHandler{}\n-\t}\n-\n-\timageGCPolicy := images.ImageGCPolicy{\n-\t\tMinAge:               s.ImageMinimumGCAge.Duration,\n-\t\tHighThresholdPercent: int(s.ImageGCHighThresholdPercent),\n-\t\tLowThresholdPercent:  int(s.ImageGCLowThresholdPercent),\n-\t}\n-\n-\tdiskSpacePolicy := kubelet.DiskSpacePolicy{\n-\t\tDockerFreeDiskMB: int(s.LowDiskSpaceThresholdMB),\n-\t\tRootFreeDiskMB:   int(s.LowDiskSpaceThresholdMB),\n-\t}\n-\n-\tmanifestURLHeader := make(http.Header)\n-\tif s.ManifestURLHeader != \"\" {\n-\t\tpieces := strings.Split(s.ManifestURLHeader, \":\")\n-\t\tif len(pieces) != 2 {\n-\t\t\treturn nil, fmt.Errorf(\"manifest-url-header must have a single ':' key-value separator, got %q\", s.ManifestURLHeader)\n-\t\t}\n-\t\tmanifestURLHeader.Set(pieces[0], pieces[1])\n-\t}\n-\n-\treservation, err := parseReservation(s.KubeReserved, s.SystemReserved)\n-\tif err != nil {\n-\t\treturn nil, err\n-\t}\n-\n-\tthresholds, err := eviction.ParseThresholdConfig(s.EvictionHard, s.EvictionSoft, s.EvictionSoftGracePeriod, s.EvictionMinimumReclaim)\n-\tif err != nil {\n-\t\treturn nil, err\n-\t}\n-\tevictionConfig := eviction.Config{\n-\t\tPressureTransitionPeriod: s.EvictionPressureTransitionPeriod.Duration,\n-\t\tMaxPodGracePeriodSeconds: int64(s.EvictionMaxPodGracePeriod),\n-\t\tThresholds:               thresholds,\n-\t}\n-\n-\treturn &KubeletConfig{\n-\t\tAddress:                      net.ParseIP(s.Address),\n-\t\tAllowPrivileged:              s.AllowPrivileged,\n-\t\tAuth:                         nil, // default does not enforce auth[nz]\n-\t\tCAdvisorInterface:            nil, // launches background processes, not set here\n-\t\tVolumeStatsAggPeriod:         s.VolumeStatsAggPeriod.Duration,\n-\t\tCgroupRoot:                   s.CgroupRoot,\n-\t\tCloud:                        nil, // cloud provider might start background processes\n-\t\tClusterDNS:                   net.ParseIP(s.ClusterDNS),\n-\t\tClusterDomain:                s.ClusterDomain,\n-\t\tConfigFile:                   s.PodManifestPath,\n-\t\tConfigureCBR0:                s.ConfigureCBR0,\n-\t\tContainerManager:             nil,\n-\t\tContainerRuntime:             s.ContainerRuntime,\n-\t\tRuntimeRequestTimeout:        s.RuntimeRequestTimeout.Duration,\n-\t\tCPUCFSQuota:                  s.CPUCFSQuota,\n-\t\tDiskSpacePolicy:              diskSpacePolicy,\n-\t\tDockerClient:                 dockertools.ConnectToDockerOrDie(s.DockerEndpoint, s.RuntimeRequestTimeout.Duration), // TODO(random-liu): Set RuntimeRequestTimeout for rkt.\n-\t\tRuntimeCgroups:               s.RuntimeCgroups,\n-\t\tDockerExecHandler:            dockerExecHandler,\n-\t\tEnableControllerAttachDetach: s.EnableControllerAttachDetach,\n-\t\tEnableCustomMetrics:          s.EnableCustomMetrics,\n-\t\tEnableDebuggingHandlers:      s.EnableDebuggingHandlers,\n-\t\tCgroupsPerQOS:                s.CgroupsPerQOS,\n-\t\tEnableServer:                 s.EnableServer,\n-\t\tEventBurst:                   int(s.EventBurst),\n-\t\tEventRecordQPS:               float32(s.EventRecordQPS),\n-\t\tFileCheckFrequency:           s.FileCheckFrequency.Duration,\n-\t\tHostnameOverride:             s.HostnameOverride,\n-\t\tHostNetworkSources:           hostNetworkSources,\n-\t\tHostPIDSources:               hostPIDSources,\n-\t\tHostIPCSources:               hostIPCSources,\n-\t\tHTTPCheckFrequency:           s.HTTPCheckFrequency.Duration,\n-\t\tImageGCPolicy:                imageGCPolicy,\n-\t\tKubeClient:                   nil,\n-\t\tManifestURL:                  s.ManifestURL,\n-\t\tManifestURLHeader:            manifestURLHeader,\n-\t\tMasterServiceNamespace:       s.MasterServiceNamespace,\n-\t\tMaxContainerCount:            int(s.MaxContainerCount),\n-\t\tMaxOpenFiles:                 uint64(s.MaxOpenFiles),\n-\t\tMaxPerPodContainerCount:      int(s.MaxPerPodContainerCount),\n-\t\tMaxPods:                      int(s.MaxPods),\n-\t\tNvidiaGPUs:                   int(s.NvidiaGPUs),\n-\t\tMinimumGCAge:                 s.MinimumGCAge.Duration,\n-\t\tMounter:                      mounter,\n-\t\tNetworkPluginName:            s.NetworkPluginName,\n-\t\tNetworkPlugins:               ProbeNetworkPlugins(s.NetworkPluginDir),\n-\t\tNodeLabels:                   s.NodeLabels,\n-\t\tNodeStatusUpdateFrequency:    s.NodeStatusUpdateFrequency.Duration,\n-\t\tNonMasqueradeCIDR:            s.NonMasqueradeCIDR,\n-\t\tOOMAdjuster:                  oom.NewOOMAdjuster(),\n-\t\tOSInterface:                  kubecontainer.RealOS{},\n-\t\tPodCIDR:                      s.PodCIDR,\n-\t\tReconcileCIDR:                s.ReconcileCIDR,\n-\t\tPodInfraContainerImage:       s.PodInfraContainerImage,\n-\t\tPort:                           uint(s.Port),\n-\t\tReadOnlyPort:                   uint(s.ReadOnlyPort),\n-\t\tRegisterNode:                   s.RegisterNode,\n-\t\tRegisterSchedulable:            s.RegisterSchedulable,\n-\t\tRegistryBurst:                  int(s.RegistryBurst),\n-\t\tRegistryPullQPS:                float64(s.RegistryPullQPS),\n-\t\tResolverConfig:                 s.ResolverConfig,\n-\t\tReservation:                    *reservation,\n-\t\tKubeletCgroups:                 s.KubeletCgroups,\n-\t\tRktPath:                        s.RktPath,\n-\t\tRktAPIEndpoint:                 s.RktAPIEndpoint,\n-\t\tRktStage1Image:                 s.RktStage1Image,\n-\t\tRootDirectory:                  s.RootDirectory,\n-\t\tSeccompProfileRoot:             s.SeccompProfileRoot,\n-\t\tRunonce:                        s.RunOnce,\n-\t\tSerializeImagePulls:            s.SerializeImagePulls,\n-\t\tStandaloneMode:                 (len(s.APIServerList) == 0),\n-\t\tStreamingConnectionIdleTimeout: s.StreamingConnectionIdleTimeout.Duration,\n-\t\tSyncFrequency:                  s.SyncFrequency.Duration,\n-\t\tSystemCgroups:                  s.SystemCgroups,\n-\t\tTLSOptions:                     tlsOptions,\n-\t\tWriter:                         writer,\n-\t\tVolumePlugins:                  ProbeVolumePlugins(s.VolumePluginDir),\n-\t\tOutOfDiskTransitionFrequency:   s.OutOfDiskTransitionFrequency.Duration,\n-\t\tHairpinMode:                    s.HairpinMode,\n-\t\tBabysitDaemons:                 s.BabysitDaemons,\n-\t\tExperimentalFlannelOverlay:     s.ExperimentalFlannelOverlay,\n-\t\tNodeIP:         net.ParseIP(s.NodeIP),\n-\t\tEvictionConfig: evictionConfig,\n-\t\tPodsPerCore:    int(s.PodsPerCore),\n+\t\twriter = &kubeio.NsenterWriter{}\n+\t}\n+\n+\treturn &kubelet.KubeletDeps{\n+\t\tAuth:              nil, // default does not enforce auth[nz]\n+\t\tCAdvisorInterface: nil, // launches background processes, not set here\n+\t\tCloud:             nil, // cloud provider might start background processes\n+\t\tContainerManager:  nil,\n+\t\tDockerClient:      dockertools.ConnectToDockerOrDie(s.DockerEndpoint, s.RuntimeRequestTimeout.Duration), // TODO(random-liu): Set RuntimeRequestTimeout for rkt.","path":"cmd/kubelet/app/server.go","position":228,"original_position":228,"commit_id":"8d7ae7df3d1d481c74855447afad10b110c8360c","original_commit_id":"8d7ae7df3d1d481c74855447afad10b110c8360c","user":{"login":"mtaufen","id":903617,"avatar_url":"https://avatars.githubusercontent.com/u/903617?v=3","gravatar_id":"","url":"https://api.github.com/users/mtaufen","html_url":"https://github.com/mtaufen","followers_url":"https://api.github.com/users/mtaufen/followers","following_url":"https://api.github.com/users/mtaufen/following{/other_user}","gists_url":"https://api.github.com/users/mtaufen/gists{/gist_id}","starred_url":"https://api.github.com/users/mtaufen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mtaufen/subscriptions","organizations_url":"https://api.github.com/users/mtaufen/orgs","repos_url":"https://api.github.com/users/mtaufen/repos","events_url":"https://api.github.com/users/mtaufen/events{/privacy}","received_events_url":"https://api.github.com/users/mtaufen/received_events","type":"User","site_admin":false},"body":"Good catch.\r\nI think the way to solve this would probably be something like:\r\n```\r\nvar dockerClient DockerInterface\r\nif s.ContainerRuntime == \"docker\" {\r\n    dockerClient = dockertools.ConnectToDockerOrDie(s.DockerEndpoint, s.RuntimeRequestTimeout.Duration)\r\n} else {\r\n    dockerClient = nil\r\n}\r\n```\r\n\r\nWill try in the morning. Also worth noting @Random-Liu's TODO: \"Set RuntimeRequestTimeout for rkt.\" RuntimeRequestTimeout is part of the `KubeletConfiguration` now, so we're pretty much trusting the user to get that right (or be satisfied with the default 2 minutes) if they choose rkt. Perhaps this TODO can be removed.","created_at":"2016-08-12T05:14:45Z","updated_at":"2016-08-12T05:14:45Z","html_url":"https://github.com/kubernetes/kubernetes/pull/29216#discussion_r74542307","pull_request_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/29216","_links":{"self":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments/74542307"},"html":{"href":"https://github.com/kubernetes/kubernetes/pull/29216#discussion_r74542307"},"pull_request":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/29216"}}},"pull_request":{"url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/29216","id":78016791,"html_url":"https://github.com/kubernetes/kubernetes/pull/29216","diff_url":"https://github.com/kubernetes/kubernetes/pull/29216.diff","patch_url":"https://github.com/kubernetes/kubernetes/pull/29216.patch","issue_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/29216","number":29216,"state":"open","locked":false,"title":"Refactor to simplify the hard-traveled path of the KubeletConfiguration object","user":{"login":"mtaufen","id":903617,"avatar_url":"https://avatars.githubusercontent.com/u/903617?v=3","gravatar_id":"","url":"https://api.github.com/users/mtaufen","html_url":"https://github.com/mtaufen","followers_url":"https://api.github.com/users/mtaufen/followers","following_url":"https://api.github.com/users/mtaufen/following{/other_user}","gists_url":"https://api.github.com/users/mtaufen/gists{/gist_id}","starred_url":"https://api.github.com/users/mtaufen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mtaufen/subscriptions","organizations_url":"https://api.github.com/users/mtaufen/orgs","repos_url":"https://api.github.com/users/mtaufen/repos","events_url":"https://api.github.com/users/mtaufen/events{/privacy}","received_events_url":"https://api.github.com/users/mtaufen/received_events","type":"User","site_admin":false},"body":"**First note:** This needs cleanup before it's suitable for submission, I'm just posting it so we can talk about it in the SIG-node meeting today. Ignore the first two commits in this PR (0e7c992 and 0397069), I'm eventually going to cherry-pick everything over to a new branch to drop those. \r\n\r\n### There are two main goals of this PR:\r\n- Make `NewMainKubelet` take a `KubeletConfiguration` as its only argument.\r\n- Finally eliminate the legacy `KubeletConfig` type.\r\n\r\n### Why am I doing this?\r\nLong story short, I started adding an endpoint to the Kubelet to display the *current* config that the Kubelet was running with, and I realized a few things:\r\n- There were so many transformations to the configuration, in so many different places, before it was used that I wasn't confident the values initially passed in on the `KubeletConfiguration` would be the correct values to report by the time someone used the endpoint to check on them.\r\n- Trying to reconstruct a `KubeletConfiguration` object from a mix of the `Kubelet` object and the legacy `KubeletConfig` object would just add to the mess (not to mention maintenance burden), and it would be much easier if we passed the `KubeletConfiguration` all the way down to where we construct the `Kubelet` object, and then just store a reference to the `KubeletConfiguration` object on the `Kubelet` for later retrieval. \r\n- My hope is that by eliminating unnecessary internal transformations to the config information, and by consolidating the remaining ones in a single place (`NewMainKubelet`), we can have a much clearer understanding of what happens to the config before it makes it to the `Kubelet` object, and also a better ability to report up-to-date information on the status of the Kubelet. \r\n\r\nSo I started cleaning things up :-). \r\n\r\n### Discussion points\r\n\r\nIt was relatively simple to get `NewMainKubelet` to just take the legacy `KubeletConfig` as its only argument, because most of its arguments were just passing through `KubeletConfig` fields or passing information that was generated solely from `KubeletConfig` fields.\r\n\r\nCompletely eliminating the legacy `KubeletConfig` type has been more difficult, because the fields of the `KubeletConfiguration` do not have a one-to-one relationship with the fields of the `KubeletConfig`. While I was able to eliminate many of the `KubeletConfig` fields, I'm starting to get into the nontrivial stuff and I'd like to get a discussion started on what should happen with the remaining fields (pending cherry-picking notwithstanding). \r\n\r\nOn my `kconf-refactor` branch, the legacy `KubeletConfig` object is down to the following 27 fields (from the initial 93). I'd really appreciate any guidance people have on what should happen with these fields.\r\n```\r\ntype KubeletConfig struct {\r\n\tAuth                    server.AuthInterface\r\n\tAutoDetectCloudProvider bool\r\n\tBuilder                 KubeletBuilder\r\n\tCAdvisorInterface       cadvisor.Interface\r\n\tCloud                   cloudprovider.Interface\r\n\tContainerManager        cm.ContainerManager\r\n\tDockerClient            dockertools.DockerInterface\r\n\tEventClient             *clientset.Clientset\r\n\tHostname                string\r\n\tHostNetworkSources      []string\r\n\tHostPIDSources          []string\r\n\tHostIPCSources          []string\r\n\tKubeClient              *clientset.Clientset\r\n\tMounter                 mount.Interface\r\n\tNetworkPlugins          []network.NetworkPlugin\r\n\tNodeName                string\r\n\tOOMAdjuster             *oom.OOMAdjuster\r\n\tOSInterface             kubecontainer.OSInterface\r\n\tPodConfig               *config.PodConfig\r\n\tRecorder                record.EventRecorder\r\n\tReservation             kubetypes.Reservation\r\n\tTLSOptions              *server.TLSOptions\r\n\tWriter                  kubeio.Writer\r\n\tVolumePlugins           []volume.VolumePlugin\r\n\tEvictionConfig          eviction.Config\r\n\tContainerRuntimeOptions []kubecontainer.Option\r\n\tOptions                 []Option\r\n}\r\n```\r\n\r\nThe patterns I've seen so far with respect to eliminating `KubeletConfig` fields may be of some help:\r\n- Some fields could just be eliminated, because they were either the same on `KubeletConfiguration` or just a typecast away from being the same. \r\n- Some fields from `KubeletConfiguration` just ended up in substructures of `KubeletConfig`; it was easy to just remove those substructure fields from `KubeletConfig` and construct them using local vars in `NewMainKubelet` instead. \r\n- Some fields, e.g. `Runonce`, were able to move into the `KubeletConfiguration`.\r\n\r\n\r\n**P.S.** Part of the way I'm making the transition is by adding an extra `KubeletConfiguration` argument to functions that originally took a `KubeletConfig`, and field-by-field, switching those functions over to using information from the `KubeletConfiguration`. Once the `KubeletConfig` is gone, I'll remove the `KubeletConfig` argument, and the transition will be complete.\r\n\r\n**Final note:**\r\nPlease try to keep in mind that this is not a general Kubelet cleanup effort, it is just me cleaning things up that are directly in the path of what I'm trying to do. Let's keep this focused on cleanup related to the path that config takes on it's way to the Kubelet.\n\n<!-- Reviewable:start -->\n---\nThis change is [<img src=\"https://reviewable.kubernetes.io/review_button.svg\" height=\"34\" align=\"absmiddle\" alt=\"Reviewable\"/>](https://reviewable.kubernetes.io/reviews/kubernetes/kubernetes/29216)\n<!-- Reviewable:end -->\n","created_at":"2016-07-19T17:30:48Z","updated_at":"2016-08-12T05:14:45Z","closed_at":null,"merged_at":null,"merge_commit_sha":"06bcac75f42599a125fef78918c0d5a00418da19","assignee":{"login":"mtaufen","id":903617,"avatar_url":"https://avatars.githubusercontent.com/u/903617?v=3","gravatar_id":"","url":"https://api.github.com/users/mtaufen","html_url":"https://github.com/mtaufen","followers_url":"https://api.github.com/users/mtaufen/followers","following_url":"https://api.github.com/users/mtaufen/following{/other_user}","gists_url":"https://api.github.com/users/mtaufen/gists{/gist_id}","starred_url":"https://api.github.com/users/mtaufen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mtaufen/subscriptions","organizations_url":"https://api.github.com/users/mtaufen/orgs","repos_url":"https://api.github.com/users/mtaufen/repos","events_url":"https://api.github.com/users/mtaufen/events{/privacy}","received_events_url":"https://api.github.com/users/mtaufen/received_events","type":"User","site_admin":false},"assignees":[{"login":"mtaufen","id":903617,"avatar_url":"https://avatars.githubusercontent.com/u/903617?v=3","gravatar_id":"","url":"https://api.github.com/users/mtaufen","html_url":"https://github.com/mtaufen","followers_url":"https://api.github.com/users/mtaufen/followers","following_url":"https://api.github.com/users/mtaufen/following{/other_user}","gists_url":"https://api.github.com/users/mtaufen/gists{/gist_id}","starred_url":"https://api.github.com/users/mtaufen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mtaufen/subscriptions","organizations_url":"https://api.github.com/users/mtaufen/orgs","repos_url":"https://api.github.com/users/mtaufen/repos","events_url":"https://api.github.com/users/mtaufen/events{/privacy}","received_events_url":"https://api.github.com/users/mtaufen/received_events","type":"User","site_admin":false},{"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},{"login":"timstclair","id":3272040,"avatar_url":"https://avatars.githubusercontent.com/u/3272040?v=3","gravatar_id":"","url":"https://api.github.com/users/timstclair","html_url":"https://github.com/timstclair","followers_url":"https://api.github.com/users/timstclair/followers","following_url":"https://api.github.com/users/timstclair/following{/other_user}","gists_url":"https://api.github.com/users/timstclair/gists{/gist_id}","starred_url":"https://api.github.com/users/timstclair/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/timstclair/subscriptions","organizations_url":"https://api.github.com/users/timstclair/orgs","repos_url":"https://api.github.com/users/timstclair/repos","events_url":"https://api.github.com/users/timstclair/events{/privacy}","received_events_url":"https://api.github.com/users/timstclair/received_events","type":"User","site_admin":false},{"login":"Random-Liu","id":5821883,"avatar_url":"https://avatars.githubusercontent.com/u/5821883?v=3","gravatar_id":"","url":"https://api.github.com/users/Random-Liu","html_url":"https://github.com/Random-Liu","followers_url":"https://api.github.com/users/Random-Liu/followers","following_url":"https://api.github.com/users/Random-Liu/following{/other_user}","gists_url":"https://api.github.com/users/Random-Liu/gists{/gist_id}","starred_url":"https://api.github.com/users/Random-Liu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Random-Liu/subscriptions","organizations_url":"https://api.github.com/users/Random-Liu/orgs","repos_url":"https://api.github.com/users/Random-Liu/repos","events_url":"https://api.github.com/users/Random-Liu/events{/privacy}","received_events_url":"https://api.github.com/users/Random-Liu/received_events","type":"User","site_admin":false},{"login":"vishh","id":7063592,"avatar_url":"https://avatars.githubusercontent.com/u/7063592?v=3","gravatar_id":"","url":"https://api.github.com/users/vishh","html_url":"https://github.com/vishh","followers_url":"https://api.github.com/users/vishh/followers","following_url":"https://api.github.com/users/vishh/following{/other_user}","gists_url":"https://api.github.com/users/vishh/gists{/gist_id}","starred_url":"https://api.github.com/users/vishh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vishh/subscriptions","organizations_url":"https://api.github.com/users/vishh/orgs","repos_url":"https://api.github.com/users/vishh/repos","events_url":"https://api.github.com/users/vishh/events{/privacy}","received_events_url":"https://api.github.com/users/vishh/received_events","type":"User","site_admin":false},{"login":"yujuhong","id":10524058,"avatar_url":"https://avatars.githubusercontent.com/u/10524058?v=3","gravatar_id":"","url":"https://api.github.com/users/yujuhong","html_url":"https://github.com/yujuhong","followers_url":"https://api.github.com/users/yujuhong/followers","following_url":"https://api.github.com/users/yujuhong/following{/other_user}","gists_url":"https://api.github.com/users/yujuhong/gists{/gist_id}","starred_url":"https://api.github.com/users/yujuhong/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yujuhong/subscriptions","organizations_url":"https://api.github.com/users/yujuhong/orgs","repos_url":"https://api.github.com/users/yujuhong/repos","events_url":"https://api.github.com/users/yujuhong/events{/privacy}","received_events_url":"https://api.github.com/users/yujuhong/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/29216/commits","review_comments_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/29216/comments","review_comment_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments{/number}","comments_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/29216/comments","statuses_url":"https://api.github.com/repos/kubernetes/kubernetes/statuses/8d7ae7df3d1d481c74855447afad10b110c8360c","head":{"label":"mtaufen:kconf-refactor","ref":"kconf-refactor","sha":"8d7ae7df3d1d481c74855447afad10b110c8360c","user":{"login":"mtaufen","id":903617,"avatar_url":"https://avatars.githubusercontent.com/u/903617?v=3","gravatar_id":"","url":"https://api.github.com/users/mtaufen","html_url":"https://github.com/mtaufen","followers_url":"https://api.github.com/users/mtaufen/followers","following_url":"https://api.github.com/users/mtaufen/following{/other_user}","gists_url":"https://api.github.com/users/mtaufen/gists{/gist_id}","starred_url":"https://api.github.com/users/mtaufen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mtaufen/subscriptions","organizations_url":"https://api.github.com/users/mtaufen/orgs","repos_url":"https://api.github.com/users/mtaufen/repos","events_url":"https://api.github.com/users/mtaufen/events{/privacy}","received_events_url":"https://api.github.com/users/mtaufen/received_events","type":"User","site_admin":false},"repo":{"id":58391682,"name":"kubernetes","full_name":"mtaufen/kubernetes","owner":{"login":"mtaufen","id":903617,"avatar_url":"https://avatars.githubusercontent.com/u/903617?v=3","gravatar_id":"","url":"https://api.github.com/users/mtaufen","html_url":"https://github.com/mtaufen","followers_url":"https://api.github.com/users/mtaufen/followers","following_url":"https://api.github.com/users/mtaufen/following{/other_user}","gists_url":"https://api.github.com/users/mtaufen/gists{/gist_id}","starred_url":"https://api.github.com/users/mtaufen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mtaufen/subscriptions","organizations_url":"https://api.github.com/users/mtaufen/orgs","repos_url":"https://api.github.com/users/mtaufen/repos","events_url":"https://api.github.com/users/mtaufen/events{/privacy}","received_events_url":"https://api.github.com/users/mtaufen/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mtaufen/kubernetes","description":"Container Cluster Manager from Google","fork":true,"url":"https://api.github.com/repos/mtaufen/kubernetes","forks_url":"https://api.github.com/repos/mtaufen/kubernetes/forks","keys_url":"https://api.github.com/repos/mtaufen/kubernetes/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mtaufen/kubernetes/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mtaufen/kubernetes/teams","hooks_url":"https://api.github.com/repos/mtaufen/kubernetes/hooks","issue_events_url":"https://api.github.com/repos/mtaufen/kubernetes/issues/events{/number}","events_url":"https://api.github.com/repos/mtaufen/kubernetes/events","assignees_url":"https://api.github.com/repos/mtaufen/kubernetes/assignees{/user}","branches_url":"https://api.github.com/repos/mtaufen/kubernetes/branches{/branch}","tags_url":"https://api.github.com/repos/mtaufen/kubernetes/tags","blobs_url":"https://api.github.com/repos/mtaufen/kubernetes/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mtaufen/kubernetes/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mtaufen/kubernetes/git/refs{/sha}","trees_url":"https://api.github.com/repos/mtaufen/kubernetes/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mtaufen/kubernetes/statuses/{sha}","languages_url":"https://api.github.com/repos/mtaufen/kubernetes/languages","stargazers_url":"https://api.github.com/repos/mtaufen/kubernetes/stargazers","contributors_url":"https://api.github.com/repos/mtaufen/kubernetes/contributors","subscribers_url":"https://api.github.com/repos/mtaufen/kubernetes/subscribers","subscription_url":"https://api.github.com/repos/mtaufen/kubernetes/subscription","commits_url":"https://api.github.com/repos/mtaufen/kubernetes/commits{/sha}","git_commits_url":"https://api.github.com/repos/mtaufen/kubernetes/git/commits{/sha}","comments_url":"https://api.github.com/repos/mtaufen/kubernetes/comments{/number}","issue_comment_url":"https://api.github.com/repos/mtaufen/kubernetes/issues/comments{/number}","contents_url":"https://api.github.com/repos/mtaufen/kubernetes/contents/{+path}","compare_url":"https://api.github.com/repos/mtaufen/kubernetes/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mtaufen/kubernetes/merges","archive_url":"https://api.github.com/repos/mtaufen/kubernetes/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mtaufen/kubernetes/downloads","issues_url":"https://api.github.com/repos/mtaufen/kubernetes/issues{/number}","pulls_url":"https://api.github.com/repos/mtaufen/kubernetes/pulls{/number}","milestones_url":"https://api.github.com/repos/mtaufen/kubernetes/milestones{/number}","notifications_url":"https://api.github.com/repos/mtaufen/kubernetes/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mtaufen/kubernetes/labels{/name}","releases_url":"https://api.github.com/repos/mtaufen/kubernetes/releases{/id}","deployments_url":"https://api.github.com/repos/mtaufen/kubernetes/deployments","created_at":"2016-05-09T16:30:01Z","updated_at":"2016-05-09T16:30:16Z","pushed_at":"2016-08-11T22:22:09Z","git_url":"git://github.com/mtaufen/kubernetes.git","ssh_url":"git@github.com:mtaufen/kubernetes.git","clone_url":"https://github.com/mtaufen/kubernetes.git","svn_url":"https://github.com/mtaufen/kubernetes","homepage":"http://kubernetes.io","size":305656,"stargazers_count":0,"watchers_count":0,"language":"Go","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":"kubernetes:master","ref":"master","sha":"91a3930331dddcc6d85289948fface1d64c87f0e","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":"Production-Grade Container Scheduling and Management","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}","deployments_url":"https://api.github.com/repos/kubernetes/kubernetes/deployments","created_at":"2014-06-06T22:56:04Z","updated_at":"2016-08-12T04:49:38Z","pushed_at":"2016-08-12T04:54:29Z","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":521841,"stargazers_count":16092,"watchers_count":16092,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":5113,"mirror_url":null,"open_issues_count":4147,"forks":5113,"open_issues":4147,"watchers":16092,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/29216"},"html":{"href":"https://github.com/kubernetes/kubernetes/pull/29216"},"issue":{"href":"https://api.github.com/repos/kubernetes/kubernetes/issues/29216"},"comments":{"href":"https://api.github.com/repos/kubernetes/kubernetes/issues/29216/comments"},"review_comments":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/29216/comments"},"review_comment":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/29216/commits"},"statuses":{"href":"https://api.github.com/repos/kubernetes/kubernetes/statuses/8d7ae7df3d1d481c74855447afad10b110c8360c"}}}}
{"actor":{"display_login":"mtaufen"}}