diff --git a/pkg/kubelet/container/runtime.go b/pkg/kubelet/container/runtime.go index c0eeaea422c..3403f401c71 100644 --- a/pkg/kubelet/container/runtime.go +++ b/pkg/kubelet/container/runtime.go @@ -284,6 +284,24 @@ func (p *Pod) FindContainerByName(containerName string) *Container { return nil } +// ToAPIPod converts Pod to api.Pod. Note that if a field in api.Pod has no +// corresponding field in Pod, the field would not be populated. +func (p *Pod) ToAPIPod() *api.Pod { + var pod api.Pod + pod.UID = p.ID + pod.Name = p.Name + pod.Namespace = p.Namespace + pod.Status = p.Status + + for _, c := range p.Containers { + var container api.Container + container.Name = c.Name + container.Image = c.Image + pod.Spec.Containers = append(pod.Spec.Containers, container) + } + return &pod +} + // IsEmpty returns true if the pod is empty. func (p *Pod) IsEmpty() bool { return reflect.DeepEqual(p, &Pod{}) diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index 4b9e91890eb..4b6411df78e 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -1850,6 +1850,23 @@ func (kl *Kubelet) GetPods() []*api.Pod { return kl.podManager.GetPods() } +// GetRunningPods returns all pods running on kubelet from looking at the +// container runtime cache. This function converts kubecontainer.Pod to +// api.Pod, so only the fields that exist in both kubecontainer.Pod and +// api.Pod are considered meaningful. +func (kl *Kubelet) GetRunningPods() ([]*api.Pod, error) { + pods, err := kl.runtimeCache.GetPods() + if err != nil { + return nil, err + } + + apiPods := make([]*api.Pod, 0, len(pods)) + for _, pod := range pods { + apiPods = append(apiPods, pod.ToAPIPod()) + } + return apiPods, nil +} + func (kl *Kubelet) GetPodByFullName(podFullName string) (*api.Pod, bool) { return kl.podManager.GetPodByFullName(podFullName) } diff --git a/pkg/kubelet/server.go b/pkg/kubelet/server.go index 32d0c3a7dd3..7d76a62d081 100644 --- a/pkg/kubelet/server.go +++ b/pkg/kubelet/server.go @@ -101,6 +101,7 @@ type HostInterface interface { GetRawContainerInfo(containerName string, req *cadvisorApi.ContainerInfoRequest, subcontainers bool) (map[string]*cadvisorApi.ContainerInfo, error) GetCachedMachineInfo() (*cadvisorApi.MachineInfo, error) GetPods() []*api.Pod + GetRunningPods() ([]*api.Pod, error) GetPodByName(namespace, name string) (*api.Pod, bool) RunInContainer(name string, uid types.UID, container string, cmd []string) ([]byte, error) ExecInContainer(name string, uid types.UID, container string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool) error @@ -148,6 +149,8 @@ func (s *Server) InstallDebuggingHandlers() { s.mux.HandleFunc("/logs/", s.handleLogs) s.mux.HandleFunc("/containerLogs/", s.handleContainerLogs) s.mux.Handle("/metrics", prometheus.Handler()) + // The /runningpods endpoint is used for testing only. + s.mux.HandleFunc("/runningpods", s.handleRunningPods) s.mux.HandleFunc("/debug/pprof/", pprof.Index) s.mux.HandleFunc("/debug/pprof/profile", pprof.Profile) @@ -280,14 +283,38 @@ func (s *Server) handleContainerLogs(w http.ResponseWriter, req *http.Request) { } } -// handlePods returns a list of pod bound to the Kubelet and their spec -func (s *Server) handlePods(w http.ResponseWriter, req *http.Request) { - pods := s.host.GetPods() +// encodePods creates an api.PodList object from pods and returns the encoded +// PodList. +func encodePods(pods []*api.Pod) (data []byte, err error) { podList := new(api.PodList) for _, pod := range pods { podList.Items = append(podList.Items, *pod) } - data, err := latest.Codec.Encode(podList) + return latest.Codec.Encode(podList) +} + +// handlePods returns a list of pods bound to the Kubelet and their spec. +func (s *Server) handlePods(w http.ResponseWriter, req *http.Request) { + pods := s.host.GetPods() + data, err := encodePods(pods) + if err != nil { + s.error(w, err) + return + } + w.Header().Add("Content-type", "application/json") + w.Write(data) +} + +// handleRunningPods returns a list of pods running on Kubelet. The list is +// provided by the container runtime, and is different from the list returned +// by handlePods, which is a set of desired pods to run. +func (s *Server) handleRunningPods(w http.ResponseWriter, req *http.Request) { + pods, err := s.host.GetRunningPods() + if err != nil { + s.error(w, err) + return + } + data, err := encodePods(pods) if err != nil { s.error(w, err) return diff --git a/pkg/kubelet/server_test.go b/pkg/kubelet/server_test.go index 51de9625a75..39c7a4eaa77 100644 --- a/pkg/kubelet/server_test.go +++ b/pkg/kubelet/server_test.go @@ -47,6 +47,7 @@ type fakeKubelet struct { rawInfoFunc func(query *cadvisorApi.ContainerInfoRequest) (map[string]*cadvisorApi.ContainerInfo, error) machineInfoFunc func() (*cadvisorApi.MachineInfo, error) podsFunc func() []*api.Pod + runningPodsFunc func() ([]*api.Pod, error) logFunc func(w http.ResponseWriter, req *http.Request) runFunc func(podFullName string, uid types.UID, containerName string, cmd []string) ([]byte, error) containerVersionFunc func() (kubecontainer.Version, error) @@ -91,6 +92,10 @@ func (fk *fakeKubelet) GetPods() []*api.Pod { return fk.podsFunc() } +func (fk *fakeKubelet) GetRunningPods() ([]*api.Pod, error) { + return fk.runningPodsFunc() +} + func (fk *fakeKubelet) ServeLogs(w http.ResponseWriter, req *http.Request) { fk.logFunc(w, req) }