From bc5d7a1bca272e9c59a5afa22408d3b5e84d5004 Mon Sep 17 00:00:00 2001 From: Paul Morie Date: Fri, 6 May 2016 00:26:48 -0400 Subject: [PATCH] Reduce kubelet LOC: extract cadvisor --- pkg/kubelet/kubelet.go | 66 -------- pkg/kubelet/kubelet_cadvisor.go | 89 ++++++++++ pkg/kubelet/kubelet_cadvisor_test.go | 232 +++++++++++++++++++++++++++ pkg/kubelet/kubelet_test.go | 207 ------------------------ 4 files changed, 321 insertions(+), 273 deletions(-) create mode 100644 pkg/kubelet/kubelet_cadvisor.go create mode 100644 pkg/kubelet/kubelet_cadvisor_test.go diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index c6be6894ad1..5437a3b309d 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -33,7 +33,6 @@ import ( "github.com/golang/glog" cadvisorapi "github.com/google/cadvisor/info/v1" - cadvisorapiv2 "github.com/google/cadvisor/info/v2" "k8s.io/kubernetes/pkg/api" apierrors "k8s.io/kubernetes/pkg/api/errors" utilpod "k8s.io/kubernetes/pkg/api/pod" @@ -3533,71 +3532,6 @@ func (kl *Kubelet) ResyncInterval() time.Duration { return kl.resyncInterval } -// GetContainerInfo returns stats (from Cadvisor) for a container. -func (kl *Kubelet) GetContainerInfo(podFullName string, podUID types.UID, containerName string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) { - - podUID = kl.podManager.TranslatePodUID(podUID) - - pods, err := kl.runtimeCache.GetPods() - if err != nil { - return nil, err - } - pod := kubecontainer.Pods(pods).FindPod(podFullName, podUID) - container := pod.FindContainerByName(containerName) - if container == nil { - return nil, kubecontainer.ErrContainerNotFound - } - - ci, err := kl.cadvisor.DockerContainer(container.ID.ID, req) - if err != nil { - return nil, err - } - return &ci, nil -} - -// GetContainerInfoV2 returns stats (from Cadvisor) for containers. -func (kl *Kubelet) GetContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) { - return kl.cadvisor.ContainerInfoV2(name, options) -} - -// DockerImagesFsInfo returns information about docker image fs usage from -// cadvisor. -func (kl *Kubelet) DockerImagesFsInfo() (cadvisorapiv2.FsInfo, error) { - return kl.cadvisor.DockerImagesFsInfo() -} - -// RootFsInfo returns info about the root fs from cadvisor. -func (kl *Kubelet) RootFsInfo() (cadvisorapiv2.FsInfo, error) { - return kl.cadvisor.RootFsInfo() -} - -// Returns stats (from Cadvisor) for a non-Kubernetes container. -func (kl *Kubelet) GetRawContainerInfo(containerName string, req *cadvisorapi.ContainerInfoRequest, subcontainers bool) (map[string]*cadvisorapi.ContainerInfo, error) { - if subcontainers { - return kl.cadvisor.SubcontainerInfo(containerName, req) - } else { - containerInfo, err := kl.cadvisor.ContainerInfo(containerName, req) - if err != nil { - return nil, err - } - return map[string]*cadvisorapi.ContainerInfo{ - containerInfo.Name: containerInfo, - }, nil - } -} - -// GetCachedMachineInfo assumes that the machine info can't change without a reboot -func (kl *Kubelet) GetCachedMachineInfo() (*cadvisorapi.MachineInfo, error) { - if kl.machineInfo == nil { - info, err := kl.cadvisor.MachineInfo() - if err != nil { - return nil, err - } - kl.machineInfo = info - } - return kl.machineInfo, nil -} - // ListenAndServe runs the kubelet HTTP server. func (kl *Kubelet) ListenAndServe(address net.IP, port uint, tlsOptions *server.TLSOptions, auth server.AuthInterface, enableDebuggingHandlers bool) { server.ListenAndServeKubeletServer(kl, kl.resourceAnalyzer, address, port, tlsOptions, auth, enableDebuggingHandlers, kl.containerRuntime) diff --git a/pkg/kubelet/kubelet_cadvisor.go b/pkg/kubelet/kubelet_cadvisor.go new file mode 100644 index 00000000000..a398f711039 --- /dev/null +++ b/pkg/kubelet/kubelet_cadvisor.go @@ -0,0 +1,89 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kubelet + +import ( + cadvisorapi "github.com/google/cadvisor/info/v1" + cadvisorapiv2 "github.com/google/cadvisor/info/v2" + kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" + "k8s.io/kubernetes/pkg/types" +) + +// GetContainerInfo returns stats (from Cadvisor) for a container. +func (kl *Kubelet) GetContainerInfo(podFullName string, podUID types.UID, containerName string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) { + + podUID = kl.podManager.TranslatePodUID(podUID) + + pods, err := kl.runtimeCache.GetPods() + if err != nil { + return nil, err + } + pod := kubecontainer.Pods(pods).FindPod(podFullName, podUID) + container := pod.FindContainerByName(containerName) + if container == nil { + return nil, kubecontainer.ErrContainerNotFound + } + + ci, err := kl.cadvisor.DockerContainer(container.ID.ID, req) + if err != nil { + return nil, err + } + return &ci, nil +} + +// GetContainerInfoV2 returns stats (from Cadvisor) for containers. +func (kl *Kubelet) GetContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) { + return kl.cadvisor.ContainerInfoV2(name, options) +} + +// DockerImagesFsInfo returns information about docker image fs usage from +// cadvisor. +func (kl *Kubelet) DockerImagesFsInfo() (cadvisorapiv2.FsInfo, error) { + return kl.cadvisor.DockerImagesFsInfo() +} + +// RootFsInfo returns info about the root fs from cadvisor. +func (kl *Kubelet) RootFsInfo() (cadvisorapiv2.FsInfo, error) { + return kl.cadvisor.RootFsInfo() +} + +// Returns stats (from Cadvisor) for a non-Kubernetes container. +func (kl *Kubelet) GetRawContainerInfo(containerName string, req *cadvisorapi.ContainerInfoRequest, subcontainers bool) (map[string]*cadvisorapi.ContainerInfo, error) { + if subcontainers { + return kl.cadvisor.SubcontainerInfo(containerName, req) + } else { + containerInfo, err := kl.cadvisor.ContainerInfo(containerName, req) + if err != nil { + return nil, err + } + return map[string]*cadvisorapi.ContainerInfo{ + containerInfo.Name: containerInfo, + }, nil + } +} + +// GetCachedMachineInfo assumes that the machine info can't change without a reboot +func (kl *Kubelet) GetCachedMachineInfo() (*cadvisorapi.MachineInfo, error) { + if kl.machineInfo == nil { + info, err := kl.cadvisor.MachineInfo() + if err != nil { + return nil, err + } + kl.machineInfo = info + } + return kl.machineInfo, nil +} diff --git a/pkg/kubelet/kubelet_cadvisor_test.go b/pkg/kubelet/kubelet_cadvisor_test.go new file mode 100644 index 00000000000..4b15e45aac4 --- /dev/null +++ b/pkg/kubelet/kubelet_cadvisor_test.go @@ -0,0 +1,232 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kubelet + +import ( + "fmt" + "testing" + + cadvisorapi "github.com/google/cadvisor/info/v1" + kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" +) + +func TestGetContainerInfo(t *testing.T) { + containerID := "ab2cdf" + containerPath := fmt.Sprintf("/docker/%v", containerID) + containerInfo := cadvisorapi.ContainerInfo{ + ContainerReference: cadvisorapi.ContainerReference{ + Name: containerPath, + }, + } + + testKubelet := newTestKubelet(t) + fakeRuntime := testKubelet.fakeRuntime + kubelet := testKubelet.kubelet + cadvisorReq := &cadvisorapi.ContainerInfoRequest{} + mockCadvisor := testKubelet.fakeCadvisor + mockCadvisor.On("DockerContainer", containerID, cadvisorReq).Return(containerInfo, nil) + fakeRuntime.PodList = []*kubecontainer.Pod{ + { + ID: "12345678", + Name: "qux", + Namespace: "ns", + Containers: []*kubecontainer.Container{ + { + Name: "foo", + ID: kubecontainer.ContainerID{Type: "test", ID: containerID}, + }, + }, + }, + } + stats, err := kubelet.GetContainerInfo("qux_ns", "", "foo", cadvisorReq) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if stats == nil { + t.Fatalf("stats should not be nil") + } + mockCadvisor.AssertExpectations(t) +} + +func TestGetRawContainerInfoRoot(t *testing.T) { + containerPath := "/" + containerInfo := &cadvisorapi.ContainerInfo{ + ContainerReference: cadvisorapi.ContainerReference{ + Name: containerPath, + }, + } + testKubelet := newTestKubelet(t) + kubelet := testKubelet.kubelet + mockCadvisor := testKubelet.fakeCadvisor + cadvisorReq := &cadvisorapi.ContainerInfoRequest{} + mockCadvisor.On("ContainerInfo", containerPath, cadvisorReq).Return(containerInfo, nil) + + _, err := kubelet.GetRawContainerInfo(containerPath, cadvisorReq, false) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + mockCadvisor.AssertExpectations(t) +} + +func TestGetRawContainerInfoSubcontainers(t *testing.T) { + containerPath := "/kubelet" + containerInfo := map[string]*cadvisorapi.ContainerInfo{ + containerPath: { + ContainerReference: cadvisorapi.ContainerReference{ + Name: containerPath, + }, + }, + "/kubelet/sub": { + ContainerReference: cadvisorapi.ContainerReference{ + Name: "/kubelet/sub", + }, + }, + } + testKubelet := newTestKubelet(t) + kubelet := testKubelet.kubelet + mockCadvisor := testKubelet.fakeCadvisor + cadvisorReq := &cadvisorapi.ContainerInfoRequest{} + mockCadvisor.On("SubcontainerInfo", containerPath, cadvisorReq).Return(containerInfo, nil) + + result, err := kubelet.GetRawContainerInfo(containerPath, cadvisorReq, true) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if len(result) != 2 { + t.Errorf("Expected 2 elements, received: %+v", result) + } + mockCadvisor.AssertExpectations(t) +} + +func TestGetContainerInfoWhenCadvisorFailed(t *testing.T) { + containerID := "ab2cdf" + testKubelet := newTestKubelet(t) + kubelet := testKubelet.kubelet + mockCadvisor := testKubelet.fakeCadvisor + fakeRuntime := testKubelet.fakeRuntime + cadvisorApiFailure := fmt.Errorf("cAdvisor failure") + containerInfo := cadvisorapi.ContainerInfo{} + cadvisorReq := &cadvisorapi.ContainerInfoRequest{} + mockCadvisor.On("DockerContainer", containerID, cadvisorReq).Return(containerInfo, cadvisorApiFailure) + fakeRuntime.PodList = []*kubecontainer.Pod{ + { + ID: "uuid", + Name: "qux", + Namespace: "ns", + Containers: []*kubecontainer.Container{ + {Name: "foo", + ID: kubecontainer.ContainerID{Type: "test", ID: containerID}, + }, + }, + }, + } + stats, err := kubelet.GetContainerInfo("qux_ns", "uuid", "foo", cadvisorReq) + if stats != nil { + t.Errorf("non-nil stats on error") + } + if err == nil { + t.Errorf("expect error but received nil error") + return + } + if err.Error() != cadvisorApiFailure.Error() { + t.Errorf("wrong error message. expect %v, got %v", cadvisorApiFailure, err) + } + mockCadvisor.AssertExpectations(t) +} + +func TestGetContainerInfoOnNonExistContainer(t *testing.T) { + testKubelet := newTestKubelet(t) + kubelet := testKubelet.kubelet + mockCadvisor := testKubelet.fakeCadvisor + fakeRuntime := testKubelet.fakeRuntime + fakeRuntime.PodList = []*kubecontainer.Pod{} + + stats, _ := kubelet.GetContainerInfo("qux", "", "foo", nil) + if stats != nil { + t.Errorf("non-nil stats on non exist container") + } + mockCadvisor.AssertExpectations(t) +} + +func TestGetContainerInfoWhenContainerRuntimeFailed(t *testing.T) { + testKubelet := newTestKubelet(t) + kubelet := testKubelet.kubelet + mockCadvisor := testKubelet.fakeCadvisor + fakeRuntime := testKubelet.fakeRuntime + expectedErr := fmt.Errorf("List containers error") + fakeRuntime.Err = expectedErr + + stats, err := kubelet.GetContainerInfo("qux", "", "foo", nil) + if err == nil { + t.Errorf("expected error from dockertools, got none") + } + if err.Error() != expectedErr.Error() { + t.Errorf("expected error %v got %v", expectedErr.Error(), err.Error()) + } + if stats != nil { + t.Errorf("non-nil stats when dockertools failed") + } + mockCadvisor.AssertExpectations(t) +} + +func TestGetContainerInfoWithNoContainers(t *testing.T) { + testKubelet := newTestKubelet(t) + kubelet := testKubelet.kubelet + mockCadvisor := testKubelet.fakeCadvisor + + stats, err := kubelet.GetContainerInfo("qux_ns", "", "foo", nil) + if err == nil { + t.Errorf("expected error from cadvisor client, got none") + } + if err != kubecontainer.ErrContainerNotFound { + t.Errorf("expected error %v, got %v", kubecontainer.ErrContainerNotFound.Error(), err.Error()) + } + if stats != nil { + t.Errorf("non-nil stats when dockertools returned no containers") + } + mockCadvisor.AssertExpectations(t) +} + +func TestGetContainerInfoWithNoMatchingContainers(t *testing.T) { + testKubelet := newTestKubelet(t) + fakeRuntime := testKubelet.fakeRuntime + kubelet := testKubelet.kubelet + mockCadvisor := testKubelet.fakeCadvisor + fakeRuntime.PodList = []*kubecontainer.Pod{ + { + ID: "12345678", + Name: "qux", + Namespace: "ns", + Containers: []*kubecontainer.Container{ + {Name: "bar", + ID: kubecontainer.ContainerID{Type: "test", ID: "fakeID"}, + }, + }}, + } + + stats, err := kubelet.GetContainerInfo("qux_ns", "", "foo", nil) + if err == nil { + t.Errorf("Expected error from cadvisor client, got none") + } + if err != kubecontainer.ErrContainerNotFound { + t.Errorf("Expected error %v, got %v", kubecontainer.ErrContainerNotFound.Error(), err.Error()) + } + if stats != nil { + t.Errorf("non-nil stats when dockertools returned no containers") + } + mockCadvisor.AssertExpectations(t) +} diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go index 71cd933e102..f8a99cd497c 100644 --- a/pkg/kubelet/kubelet_test.go +++ b/pkg/kubelet/kubelet_test.go @@ -611,183 +611,6 @@ func TestMakeVolumeMounts(t *testing.T) { } } -func TestGetContainerInfo(t *testing.T) { - containerID := "ab2cdf" - containerPath := fmt.Sprintf("/docker/%v", containerID) - containerInfo := cadvisorapi.ContainerInfo{ - ContainerReference: cadvisorapi.ContainerReference{ - Name: containerPath, - }, - } - - testKubelet := newTestKubelet(t) - fakeRuntime := testKubelet.fakeRuntime - kubelet := testKubelet.kubelet - cadvisorReq := &cadvisorapi.ContainerInfoRequest{} - mockCadvisor := testKubelet.fakeCadvisor - mockCadvisor.On("DockerContainer", containerID, cadvisorReq).Return(containerInfo, nil) - fakeRuntime.PodList = []*kubecontainer.Pod{ - { - ID: "12345678", - Name: "qux", - Namespace: "ns", - Containers: []*kubecontainer.Container{ - { - Name: "foo", - ID: kubecontainer.ContainerID{Type: "test", ID: containerID}, - }, - }, - }, - } - stats, err := kubelet.GetContainerInfo("qux_ns", "", "foo", cadvisorReq) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - if stats == nil { - t.Fatalf("stats should not be nil") - } - mockCadvisor.AssertExpectations(t) -} - -func TestGetRawContainerInfoRoot(t *testing.T) { - containerPath := "/" - containerInfo := &cadvisorapi.ContainerInfo{ - ContainerReference: cadvisorapi.ContainerReference{ - Name: containerPath, - }, - } - testKubelet := newTestKubelet(t) - kubelet := testKubelet.kubelet - mockCadvisor := testKubelet.fakeCadvisor - cadvisorReq := &cadvisorapi.ContainerInfoRequest{} - mockCadvisor.On("ContainerInfo", containerPath, cadvisorReq).Return(containerInfo, nil) - - _, err := kubelet.GetRawContainerInfo(containerPath, cadvisorReq, false) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - mockCadvisor.AssertExpectations(t) -} - -func TestGetRawContainerInfoSubcontainers(t *testing.T) { - containerPath := "/kubelet" - containerInfo := map[string]*cadvisorapi.ContainerInfo{ - containerPath: { - ContainerReference: cadvisorapi.ContainerReference{ - Name: containerPath, - }, - }, - "/kubelet/sub": { - ContainerReference: cadvisorapi.ContainerReference{ - Name: "/kubelet/sub", - }, - }, - } - testKubelet := newTestKubelet(t) - kubelet := testKubelet.kubelet - mockCadvisor := testKubelet.fakeCadvisor - cadvisorReq := &cadvisorapi.ContainerInfoRequest{} - mockCadvisor.On("SubcontainerInfo", containerPath, cadvisorReq).Return(containerInfo, nil) - - result, err := kubelet.GetRawContainerInfo(containerPath, cadvisorReq, true) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - if len(result) != 2 { - t.Errorf("Expected 2 elements, received: %+v", result) - } - mockCadvisor.AssertExpectations(t) -} - -func TestGetContainerInfoWhenCadvisorFailed(t *testing.T) { - containerID := "ab2cdf" - testKubelet := newTestKubelet(t) - kubelet := testKubelet.kubelet - mockCadvisor := testKubelet.fakeCadvisor - fakeRuntime := testKubelet.fakeRuntime - cadvisorApiFailure := fmt.Errorf("cAdvisor failure") - containerInfo := cadvisorapi.ContainerInfo{} - cadvisorReq := &cadvisorapi.ContainerInfoRequest{} - mockCadvisor.On("DockerContainer", containerID, cadvisorReq).Return(containerInfo, cadvisorApiFailure) - fakeRuntime.PodList = []*kubecontainer.Pod{ - { - ID: "uuid", - Name: "qux", - Namespace: "ns", - Containers: []*kubecontainer.Container{ - {Name: "foo", - ID: kubecontainer.ContainerID{Type: "test", ID: containerID}, - }, - }, - }, - } - stats, err := kubelet.GetContainerInfo("qux_ns", "uuid", "foo", cadvisorReq) - if stats != nil { - t.Errorf("non-nil stats on error") - } - if err == nil { - t.Errorf("expect error but received nil error") - return - } - if err.Error() != cadvisorApiFailure.Error() { - t.Errorf("wrong error message. expect %v, got %v", cadvisorApiFailure, err) - } - mockCadvisor.AssertExpectations(t) -} - -func TestGetContainerInfoOnNonExistContainer(t *testing.T) { - testKubelet := newTestKubelet(t) - kubelet := testKubelet.kubelet - mockCadvisor := testKubelet.fakeCadvisor - fakeRuntime := testKubelet.fakeRuntime - fakeRuntime.PodList = []*kubecontainer.Pod{} - - stats, _ := kubelet.GetContainerInfo("qux", "", "foo", nil) - if stats != nil { - t.Errorf("non-nil stats on non exist container") - } - mockCadvisor.AssertExpectations(t) -} - -func TestGetContainerInfoWhenContainerRuntimeFailed(t *testing.T) { - testKubelet := newTestKubelet(t) - kubelet := testKubelet.kubelet - mockCadvisor := testKubelet.fakeCadvisor - fakeRuntime := testKubelet.fakeRuntime - expectedErr := fmt.Errorf("List containers error") - fakeRuntime.Err = expectedErr - - stats, err := kubelet.GetContainerInfo("qux", "", "foo", nil) - if err == nil { - t.Errorf("expected error from dockertools, got none") - } - if err.Error() != expectedErr.Error() { - t.Errorf("expected error %v got %v", expectedErr.Error(), err.Error()) - } - if stats != nil { - t.Errorf("non-nil stats when dockertools failed") - } - mockCadvisor.AssertExpectations(t) -} - -func TestGetContainerInfoWithNoContainers(t *testing.T) { - testKubelet := newTestKubelet(t) - kubelet := testKubelet.kubelet - mockCadvisor := testKubelet.fakeCadvisor - - stats, err := kubelet.GetContainerInfo("qux_ns", "", "foo", nil) - if err == nil { - t.Errorf("expected error from cadvisor client, got none") - } - if err != kubecontainer.ErrContainerNotFound { - t.Errorf("expected error %v, got %v", kubecontainer.ErrContainerNotFound.Error(), err.Error()) - } - if stats != nil { - t.Errorf("non-nil stats when dockertools returned no containers") - } - mockCadvisor.AssertExpectations(t) -} - func TestNodeIPParam(t *testing.T) { testKubelet := newTestKubelet(t) kubelet := testKubelet.kubelet @@ -828,36 +651,6 @@ func TestNodeIPParam(t *testing.T) { } } -func TestGetContainerInfoWithNoMatchingContainers(t *testing.T) { - testKubelet := newTestKubelet(t) - fakeRuntime := testKubelet.fakeRuntime - kubelet := testKubelet.kubelet - mockCadvisor := testKubelet.fakeCadvisor - fakeRuntime.PodList = []*kubecontainer.Pod{ - { - ID: "12345678", - Name: "qux", - Namespace: "ns", - Containers: []*kubecontainer.Container{ - {Name: "bar", - ID: kubecontainer.ContainerID{Type: "test", ID: "fakeID"}, - }, - }}, - } - - stats, err := kubelet.GetContainerInfo("qux_ns", "", "foo", nil) - if err == nil { - t.Errorf("Expected error from cadvisor client, got none") - } - if err != kubecontainer.ErrContainerNotFound { - t.Errorf("Expected error %v, got %v", kubecontainer.ErrContainerNotFound.Error(), err.Error()) - } - if stats != nil { - t.Errorf("non-nil stats when dockertools returned no containers") - } - mockCadvisor.AssertExpectations(t) -} - type fakeContainerCommandRunner struct { Cmd []string ID kubecontainer.ContainerID