Commit ba5be345 authored by Phillip Wittrock's avatar Phillip Wittrock

Kubelet Metrics Summary Api Implementation

parent ad9fa30e
...@@ -36,6 +36,10 @@ func (c *Fake) ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) ...@@ -36,6 +36,10 @@ func (c *Fake) ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest)
return new(cadvisorapi.ContainerInfo), nil return new(cadvisorapi.ContainerInfo), nil
} }
func (c *Fake) ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) {
return map[string]cadvisorapiv2.ContainerInfo{}, nil
}
func (c *Fake) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) { func (c *Fake) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) {
return map[string]*cadvisorapi.ContainerInfo{}, nil return map[string]*cadvisorapi.ContainerInfo{}, nil
} }
......
...@@ -137,6 +137,10 @@ func (cc *cadvisorClient) ContainerInfo(name string, req *cadvisorapi.ContainerI ...@@ -137,6 +137,10 @@ func (cc *cadvisorClient) ContainerInfo(name string, req *cadvisorapi.ContainerI
return cc.GetContainerInfo(name, req) return cc.GetContainerInfo(name, req)
} }
func (cc *cadvisorClient) ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) {
return cc.GetContainerInfoV2(name, options)
}
func (cc *cadvisorClient) VersionInfo() (*cadvisorapi.VersionInfo, error) { func (cc *cadvisorClient) VersionInfo() (*cadvisorapi.VersionInfo, error) {
return cc.GetVersionInfo() return cc.GetVersionInfo()
} }
......
...@@ -40,6 +40,12 @@ func (c *Mock) ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) ...@@ -40,6 +40,12 @@ func (c *Mock) ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest)
return args.Get(0).(*cadvisorapi.ContainerInfo), args.Error(1) return args.Get(0).(*cadvisorapi.ContainerInfo), args.Error(1)
} }
// ContainerInfoV2 is a mock implementation of Interface.ContainerInfoV2.
func (c *Mock) ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) {
args := c.Called(name, options)
return args.Get(0).(map[string]cadvisorapiv2.ContainerInfo), args.Error(1)
}
func (c *Mock) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) { func (c *Mock) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) {
args := c.Called(name, req) args := c.Called(name, req)
return args.Get(0).(map[string]*cadvisorapi.ContainerInfo), args.Error(1) return args.Get(0).(map[string]*cadvisorapi.ContainerInfo), args.Error(1)
......
...@@ -49,6 +49,10 @@ func (cu *cadvisorUnsupported) ContainerInfo(name string, req *cadvisorapi.Conta ...@@ -49,6 +49,10 @@ func (cu *cadvisorUnsupported) ContainerInfo(name string, req *cadvisorapi.Conta
return nil, unsupportedErr return nil, unsupportedErr
} }
func (cu *cadvisorUnsupported) ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) {
return nil, unsupportedErr
}
func (cu *cadvisorUnsupported) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) { func (cu *cadvisorUnsupported) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) {
return nil, unsupportedErr return nil, unsupportedErr
} }
......
...@@ -27,6 +27,7 @@ type Interface interface { ...@@ -27,6 +27,7 @@ type Interface interface {
Start() error Start() error
DockerContainer(name string, req *cadvisorapi.ContainerInfoRequest) (cadvisorapi.ContainerInfo, error) DockerContainer(name string, req *cadvisorapi.ContainerInfoRequest) (cadvisorapi.ContainerInfo, error)
ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error)
ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error)
SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error)
MachineInfo() (*cadvisorapi.MachineInfo, error) MachineInfo() (*cadvisorapi.MachineInfo, error)
......
...@@ -64,6 +64,22 @@ type labelledContainerInfo struct { ...@@ -64,6 +64,22 @@ type labelledContainerInfo struct {
PreStopHandler *api.Handler PreStopHandler *api.Handler
} }
func GetContainerName(labels map[string]string) string {
return labels[kubernetesContainerNameLabel]
}
func GetPodName(labels map[string]string) string {
return labels[kubernetesPodNameLabel]
}
func GetPodUID(labels map[string]string) string {
return labels[kubernetesPodUIDLabel]
}
func GetPodNamespace(labels map[string]string) string {
return labels[kubernetesPodNamespaceLabel]
}
func newLabels(container *api.Container, pod *api.Pod, restartCount int) map[string]string { func newLabels(container *api.Container, pod *api.Pod, restartCount int) map[string]string {
labels := map[string]string{} labels := map[string]string{}
labels[kubernetesPodNameLabel] = pod.Name labels[kubernetesPodNameLabel] = pod.Name
......
...@@ -34,6 +34,7 @@ import ( ...@@ -34,6 +34,7 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
cadvisorapi "github.com/google/cadvisor/info/v1" cadvisorapi "github.com/google/cadvisor/info/v1"
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
apierrors "k8s.io/kubernetes/pkg/api/errors" apierrors "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/resource"
...@@ -3413,6 +3414,19 @@ func (kl *Kubelet) GetContainerInfo(podFullName string, podUID types.UID, contai ...@@ -3413,6 +3414,19 @@ func (kl *Kubelet) GetContainerInfo(podFullName string, podUID types.UID, contai
return &ci, nil 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)
}
func (kl *Kubelet) DockerImagesFsInfo() (cadvisorapiv2.FsInfo, error) {
return kl.cadvisor.DockerImagesFsInfo()
}
func (kl *Kubelet) RootFsInfo() (cadvisorapiv2.FsInfo, error) {
return kl.cadvisor.RootFsInfo()
}
// Returns stats (from Cadvisor) for a non-Kubernetes container. // 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) { func (kl *Kubelet) GetRawContainerInfo(containerName string, req *cadvisorapi.ContainerInfoRequest, subcontainers bool) (map[string]*cadvisorapi.ContainerInfo, error) {
if subcontainers { if subcontainers {
...@@ -3468,6 +3482,9 @@ func (kl *Kubelet) updatePodCIDR(cidr string) { ...@@ -3468,6 +3482,9 @@ func (kl *Kubelet) updatePodCIDR(cidr string) {
kl.networkPlugin.Event(network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE, details) kl.networkPlugin.Event(network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE, details)
} }
} }
func (kl *Kubelet) GetNodeConfig() cm.NodeConfig {
return kl.nodeConfig
}
var minRsrc = resource.MustParse("1k") var minRsrc = resource.MustParse("1k")
var maxRsrc = resource.MustParse("1P") var maxRsrc = resource.MustParse("1P")
......
...@@ -33,6 +33,7 @@ import ( ...@@ -33,6 +33,7 @@ import (
restful "github.com/emicklei/go-restful" restful "github.com/emicklei/go-restful"
"github.com/golang/glog" "github.com/golang/glog"
cadvisorapi "github.com/google/cadvisor/info/v1" cadvisorapi "github.com/google/cadvisor/info/v1"
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
...@@ -45,6 +46,7 @@ import ( ...@@ -45,6 +46,7 @@ import (
"k8s.io/kubernetes/pkg/client/unversioned/remotecommand" "k8s.io/kubernetes/pkg/client/unversioned/remotecommand"
"k8s.io/kubernetes/pkg/healthz" "k8s.io/kubernetes/pkg/healthz"
"k8s.io/kubernetes/pkg/httplog" "k8s.io/kubernetes/pkg/httplog"
"k8s.io/kubernetes/pkg/kubelet/cm"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
"k8s.io/kubernetes/pkg/kubelet/server/portforward" "k8s.io/kubernetes/pkg/kubelet/server/portforward"
"k8s.io/kubernetes/pkg/kubelet/server/stats" "k8s.io/kubernetes/pkg/kubelet/server/stats"
...@@ -140,6 +142,7 @@ type AuthInterface interface { ...@@ -140,6 +142,7 @@ type AuthInterface interface {
// For testablitiy. // For testablitiy.
type HostInterface interface { type HostInterface interface {
GetContainerInfo(podFullName string, uid types.UID, containerName string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) GetContainerInfo(podFullName string, uid types.UID, containerName string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error)
GetContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error)
GetRawContainerInfo(containerName string, req *cadvisorapi.ContainerInfoRequest, subcontainers bool) (map[string]*cadvisorapi.ContainerInfo, error) GetRawContainerInfo(containerName string, req *cadvisorapi.ContainerInfoRequest, subcontainers bool) (map[string]*cadvisorapi.ContainerInfo, error)
GetCachedMachineInfo() (*cadvisorapi.MachineInfo, error) GetCachedMachineInfo() (*cadvisorapi.MachineInfo, error)
GetPods() []*api.Pod GetPods() []*api.Pod
...@@ -154,7 +157,11 @@ type HostInterface interface { ...@@ -154,7 +157,11 @@ type HostInterface interface {
StreamingConnectionIdleTimeout() time.Duration StreamingConnectionIdleTimeout() time.Duration
ResyncInterval() time.Duration ResyncInterval() time.Duration
GetHostname() string GetHostname() string
GetNode() (*api.Node, error)
GetNodeConfig() cm.NodeConfig
LatestLoopEntryTime() time.Time LatestLoopEntryTime() time.Time
DockerImagesFsInfo() (cadvisorapiv2.FsInfo, error)
RootFsInfo() (cadvisorapiv2.FsInfo, error)
} }
// NewServer initializes and configures a kubelet.Server object to handle HTTP requests. // NewServer initializes and configures a kubelet.Server object to handle HTTP requests.
......
...@@ -34,10 +34,12 @@ import ( ...@@ -34,10 +34,12 @@ import (
"time" "time"
cadvisorapi "github.com/google/cadvisor/info/v1" cadvisorapi "github.com/google/cadvisor/info/v1"
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
apierrs "k8s.io/kubernetes/pkg/api/errors" apierrs "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/auth/authorizer" "k8s.io/kubernetes/pkg/auth/authorizer"
"k8s.io/kubernetes/pkg/auth/user" "k8s.io/kubernetes/pkg/auth/user"
"k8s.io/kubernetes/pkg/kubelet/cm"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
kubetypes "k8s.io/kubernetes/pkg/kubelet/types" kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
"k8s.io/kubernetes/pkg/types" "k8s.io/kubernetes/pkg/types"
...@@ -129,6 +131,22 @@ func (fk *fakeKubelet) StreamingConnectionIdleTimeout() time.Duration { ...@@ -129,6 +131,22 @@ func (fk *fakeKubelet) StreamingConnectionIdleTimeout() time.Duration {
return fk.streamingConnectionIdleTimeoutFunc() return fk.streamingConnectionIdleTimeoutFunc()
} }
// Unused functions
func (_ *fakeKubelet) GetContainerInfoV2(_ string, _ cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) {
return nil, nil
}
func (_ *fakeKubelet) DockerImagesFsInfo() (cadvisorapiv2.FsInfo, error) {
return cadvisorapiv2.FsInfo{}, fmt.Errorf("Unsupported Operation DockerImagesFsInfo")
}
func (_ *fakeKubelet) RootFsInfo() (cadvisorapiv2.FsInfo, error) {
return cadvisorapiv2.FsInfo{}, fmt.Errorf("Unsupport Operation RootFsInfo")
}
func (_ *fakeKubelet) GetNode() (*api.Node, error) { return nil, nil }
func (_ *fakeKubelet) GetNodeConfig() cm.NodeConfig { return cm.NodeConfig{} }
type fakeAuth struct { type fakeAuth struct {
authenticateFunc func(*http.Request) (user.Info, bool, error) authenticateFunc func(*http.Request) (user.Info, bool, error)
attributesFunc func(user.Info, *http.Request) authorizer.Attributes attributesFunc func(user.Info, *http.Request) authorizer.Attributes
......
...@@ -27,8 +27,10 @@ import ( ...@@ -27,8 +27,10 @@ import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"github.com/golang/glog" "github.com/golang/glog"
cadvisorapi "github.com/google/cadvisor/info/v1" cadvisorapi "github.com/google/cadvisor/info/v1"
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/kubelet/cm"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
"k8s.io/kubernetes/pkg/types" "k8s.io/kubernetes/pkg/types"
) )
...@@ -36,16 +38,22 @@ import ( ...@@ -36,16 +38,22 @@ import (
// Host methods required by stats handlers. // Host methods required by stats handlers.
type StatsProvider interface { type StatsProvider interface {
GetContainerInfo(podFullName string, uid types.UID, containerName string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) GetContainerInfo(podFullName string, uid types.UID, containerName string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error)
GetContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error)
GetRawContainerInfo(containerName string, req *cadvisorapi.ContainerInfoRequest, subcontainers bool) (map[string]*cadvisorapi.ContainerInfo, error) GetRawContainerInfo(containerName string, req *cadvisorapi.ContainerInfoRequest, subcontainers bool) (map[string]*cadvisorapi.ContainerInfo, error)
GetPodByName(namespace, name string) (*api.Pod, bool) GetPodByName(namespace, name string) (*api.Pod, bool)
GetNode() (*api.Node, error)
GetNodeConfig() cm.NodeConfig
DockerImagesFsInfo() (cadvisorapiv2.FsInfo, error)
RootFsInfo() (cadvisorapiv2.FsInfo, error)
} }
type handler struct { type handler struct {
provider StatsProvider provider StatsProvider
summaryProvider SummaryProvider
} }
func CreateHandlers(provider StatsProvider) *restful.WebService { func CreateHandlers(provider StatsProvider) *restful.WebService {
h := &handler{provider} h := &handler{provider, NewSummaryProvider(provider)}
ws := &restful.WebService{} ws := &restful.WebService{}
ws.Path("/stats/"). ws.Path("/stats/").
...@@ -137,11 +145,12 @@ func (h *handler) handleStats(request *restful.Request, response *restful.Respon ...@@ -137,11 +145,12 @@ func (h *handler) handleStats(request *restful.Request, response *restful.Respon
// Handles stats summary requests to /stats/summary // Handles stats summary requests to /stats/summary
func (h *handler) handleSummary(request *restful.Request, response *restful.Response) { func (h *handler) handleSummary(request *restful.Request, response *restful.Response) {
summary := Summary{} summary, err := h.summaryProvider.Get()
if err != nil {
// TODO(timstclair): Fill in summary from cAdvisor v2 endpoint. handleError(response, err)
} else {
writeResponse(response, summary) writeResponse(response, summary)
}
} }
// Handles non-kubernetes container stats requests to /stats/container/ // Handles non-kubernetes container stats requests to /stats/container/
......
...@@ -91,7 +91,7 @@ type ContainerStats struct { ...@@ -91,7 +91,7 @@ type ContainerStats struct {
// Stats pertaining to container logs usage of filesystem resources. // Stats pertaining to container logs usage of filesystem resources.
// Logs.UsedBytes is the number of bytes used for the container logs. // Logs.UsedBytes is the number of bytes used for the container logs.
Logs *FsStats `json:"logs,omitempty"` Logs *FsStats `json:"logs,omitempty"`
// User defined metrics are arbitrary metrics exposed by containers in pods. // User defined metrics that are exposed by containers in the pod. Typically, we expect only one container in the pod to be exposing user defined metrics. In the event of multiple containers exposing metrics, they will be combined here.
UserDefinedMetrics []UserDefinedMetric `json:"userDefinedMetrics,omitmepty" patchStrategy:"merge" patchMergeKey:"name"` UserDefinedMetrics []UserDefinedMetric `json:"userDefinedMetrics,omitmepty" patchStrategy:"merge" patchMergeKey:"name"`
} }
......
...@@ -15,7 +15,8 @@ limitations under the License. ...@@ -15,7 +15,8 @@ limitations under the License.
*/ */
// To run tests in this suite // To run tests in this suite
// `$ ginkgo -- --node-name node-e2e-test-1 --api-server-address <serveraddress> --logtostderr` // Local: `$ ginkgo -- --logtostderr -v 2`
// Remote: `$ ginkgo -- --node-name <hostname> --api-server-address=<hostname:api_port> --kubelet-address=<hostname=kubelet_port> --logtostderr -v 2`
package e2e_node package e2e_node
import ( import (
...@@ -26,9 +27,9 @@ import ( ...@@ -26,9 +27,9 @@ import (
"testing" "testing"
) )
var kubeletAddress = flag.String("kubelet-address", "localhost:10250", "Host and port of the kubelet") var kubeletAddress = flag.String("kubelet-address", "http://127.0.0.1:10255", "Host and port of the kubelet")
var apiServerAddress = flag.String("api-server-address", "localhost:8080", "Host and port of the api server") var apiServerAddress = flag.String("api-server-address", "http://127.0.0.1:8080", "Host and port of the api server")
var nodeName = flag.String("node-name", "", "Name of the node") var nodeName = flag.String("node-name", "127.0.0.1", "Name of the node")
func TestE2eNode(t *testing.T) { func TestE2eNode(t *testing.T) {
flag.Parse() flag.Parse()
......
...@@ -18,13 +18,18 @@ package e2e_node ...@@ -18,13 +18,18 @@ package e2e_node
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"net/http"
"strings"
"time" "time"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"io/ioutil"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
client "k8s.io/kubernetes/pkg/client/unversioned" client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/kubelet/server/stats"
) )
var _ = Describe("Kubelet", func() { var _ = Describe("Kubelet", func() {
...@@ -49,10 +54,9 @@ var _ = Describe("Kubelet", func() { ...@@ -49,10 +54,9 @@ var _ = Describe("Kubelet", func() {
RestartPolicy: api.RestartPolicyNever, RestartPolicy: api.RestartPolicyNever,
Containers: []api.Container{ Containers: []api.Container{
{ {
Image: "gcr.io/google_containers/busybox", Image: "gcr.io/google_containers/busybox",
Name: "busybox", Name: "busybox",
Command: []string{"echo", "'Hello World'"}, Command: []string{"echo", "'Hello World'"},
ImagePullPolicy: api.PullIfNotPresent,
}, },
}, },
}, },
...@@ -84,4 +88,125 @@ var _ = Describe("Kubelet", func() { ...@@ -84,4 +88,125 @@ var _ = Describe("Kubelet", func() {
}) })
}) })
}) })
Describe("metrics api", func() {
statsPrefix := "stats-busybox-"
podNames := []string{}
podCount := 2
for i := 0; i < podCount; i++ {
podNames = append(podNames, fmt.Sprintf("%s%v", statsPrefix, i))
}
BeforeEach(func() {
for _, podName := range podNames {
createPod(cl, podName, []api.Container{
{
Image: "gcr.io/google_containers/busybox",
Command: []string{"sh", "-c", "echo 'Hello World' | tee ~/file | tee -a ~/file | tee /test-empty-dir | sleep 60"},
Name: podName + containerSuffix,
},
})
}
// Sleep long enough for cadvisor to see the pod and calculate all of its metrics
time.Sleep(60 * time.Second)
})
Context("when querying /stats/summary", func() {
It("it should report resource usage through the stats api", func() {
resp, err := http.Get(*kubeletAddress + "/stats/summary")
now := time.Now()
Expect(err).To(BeNil(), fmt.Sprintf("Failed to get /stats/summary"))
summary := stats.Summary{}
contentsBytes, err := ioutil.ReadAll(resp.Body)
Expect(err).To(BeNil(), fmt.Sprintf("Failed to read /stats/summary: %+v", resp))
contents := string(contentsBytes)
decoder := json.NewDecoder(strings.NewReader(contents))
err = decoder.Decode(&summary)
Expect(err).To(BeNil(), fmt.Sprintf("Failed to parse /stats/summary to go struct: %+v", resp))
// Verify Misc Stats
Expect(summary.Time.Time).To(BeTemporally("~", now, 20*time.Second))
// Verify Node Stats are present
Expect(summary.Node.NodeName).To(Equal(*nodeName))
Expect(summary.Node.CPU.UsageCoreNanoSeconds).NotTo(BeZero())
Expect(summary.Node.Memory.UsageBytes).NotTo(BeZero())
Expect(summary.Node.Memory.WorkingSetBytes).NotTo(BeZero())
Expect(summary.Node.Fs.UsedBytes).NotTo(BeZero())
Expect(summary.Node.Fs.CapacityBytes).NotTo(BeZero())
Expect(summary.Node.Fs.AvailableBytes).NotTo(BeZero())
sysContainers := map[string]stats.ContainerStats{}
sysContainersList := []string{}
for _, container := range summary.Node.SystemContainers {
sysContainers[container.Name] = container
sysContainersList = append(sysContainersList, container.Name)
Expect(container.CPU.UsageCoreNanoSeconds).NotTo(BeZero())
// TODO: Test Network
Expect(container.Memory.UsageBytes).NotTo(BeZero())
Expect(container.Memory.WorkingSetBytes).NotTo(BeZero())
Expect(container.Rootfs.CapacityBytes).NotTo(BeZero())
Expect(container.Rootfs.AvailableBytes).NotTo(BeZero())
Expect(container.Logs.CapacityBytes).NotTo(BeZero())
Expect(container.Logs.AvailableBytes).NotTo(BeZero())
}
Expect(sysContainersList).To(ConsistOf("kubelet", "runtime"))
// Verify Pods Stats are present
podsList := []string{}
for _, pod := range summary.Pods {
if !strings.HasPrefix(pod.PodRef.Name, statsPrefix) {
// Ignore pods created outside this test
continue
}
// TODO: Test network
podsList = append(podsList, pod.PodRef.Name)
Expect(pod.Containers).To(HaveLen(1))
container := pod.Containers[0]
Expect(container.Name).To(Equal(pod.PodRef.Name + containerSuffix))
Expect(container.CPU.UsageCoreNanoSeconds).NotTo(BeZero())
Expect(container.Memory.UsageBytes).NotTo(BeZero())
Expect(container.Memory.WorkingSetBytes).NotTo(BeZero())
Expect(container.Rootfs.CapacityBytes).NotTo(BeZero())
Expect(container.Rootfs.AvailableBytes).NotTo(BeZero())
Expect(*container.Rootfs.UsedBytes).NotTo(BeZero(), contents)
Expect(container.Logs.CapacityBytes).NotTo(BeZero())
Expect(container.Logs.AvailableBytes).NotTo(BeZero())
Expect(*container.Logs.UsedBytes).NotTo(BeZero(), contents)
}
Expect(podsList).To(ConsistOf(podNames))
})
})
AfterEach(func() {
for _, podName := range podNames {
err := cl.Pods(api.NamespaceDefault).Delete(podName, &api.DeleteOptions{})
Expect(err).To(BeNil(), fmt.Sprintf("Error deleting Pod %v", podName))
}
})
})
}) })
const (
containerSuffix = "-c"
)
func createPod(cl *client.Client, podName string, containers []api.Container) {
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: podName,
Namespace: api.NamespaceDefault,
},
Spec: api.PodSpec{
// Force the Pod to schedule to the node without a scheduler running
NodeName: *nodeName,
// Don't restart the Pod since it is expected to exit
RestartPolicy: api.RestartPolicyNever,
Containers: containers,
},
}
_, err := cl.Pods(api.NamespaceDefault).Create(pod)
Expect(err).To(BeNil(), fmt.Sprintf("Error creating Pod %v", err))
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment