Supply volume fs metrics to server/stats/handler.go
* Metrics will not be expose until they are hooked up to a handler * Metrics are not cached and expose a dos vector, this must be fixed before release or the stats should not be exposed through an api endpoint
This commit is contained in:
@@ -20,16 +20,18 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"io/ioutil"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
"k8s.io/kubernetes/pkg/kubelet/server/stats"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Kubelet", func() {
|
||||
@@ -66,20 +68,16 @@ var _ = Describe("Kubelet", func() {
|
||||
})
|
||||
|
||||
It("it should print the output to logs", func() {
|
||||
errs := Retry(time.Minute, time.Second*4, func() error {
|
||||
Eventually(func() string {
|
||||
rc, err := cl.Pods(api.NamespaceDefault).GetLogs("busybox", &api.PodLogOptions{}).Stream()
|
||||
if err != nil {
|
||||
return err
|
||||
return ""
|
||||
}
|
||||
defer rc.Close()
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(rc)
|
||||
if buf.String() != "'Hello World'\n" {
|
||||
return fmt.Errorf("Expected %s to match 'Hello World'", buf.String())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
Expect(errs).To(BeEmpty(), fmt.Sprintf("Failed to get Logs"))
|
||||
return buf.String()
|
||||
}, time.Second*30, time.Second*4).Should(Equal("'Hello World'\n"))
|
||||
})
|
||||
|
||||
It("it should be possible to delete", func() {
|
||||
@@ -101,9 +99,16 @@ var _ = Describe("Kubelet", func() {
|
||||
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"},
|
||||
Command: []string{"sh", "-c", "echo 'Hello World' | tee ~/file | tee /test-empty-dir-mnt | sleep 60"},
|
||||
Name: podName + containerSuffix,
|
||||
VolumeMounts: []api.VolumeMount{
|
||||
{MountPath: "/test-empty-dir-mnt", Name: "test-empty-dir"},
|
||||
},
|
||||
},
|
||||
}, []api.Volume{
|
||||
// TODO: Test secret volumes
|
||||
// TODO: Test hostpath volumes
|
||||
{Name: "test-empty-dir", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -113,6 +118,7 @@ var _ = Describe("Kubelet", func() {
|
||||
|
||||
Context("when querying /stats/summary", func() {
|
||||
It("it should report resource usage through the stats api", func() {
|
||||
By("Returning stats summary")
|
||||
resp, err := http.Get(*kubeletAddress + "/stats/summary")
|
||||
now := time.Now()
|
||||
Expect(err).To(BeNil(), fmt.Sprintf("Failed to get /stats/summary"))
|
||||
@@ -124,57 +130,84 @@ var _ = Describe("Kubelet", func() {
|
||||
err = decoder.Decode(&summary)
|
||||
Expect(err).To(BeNil(), fmt.Sprintf("Failed to parse /stats/summary to go struct: %+v", resp))
|
||||
|
||||
// Verify Misc Stats
|
||||
By("Having the correct time")
|
||||
Expect(summary.Time.Time).To(BeTemporally("~", now, 20*time.Second))
|
||||
|
||||
// Verify Node Stats are present
|
||||
By("Having resources for node")
|
||||
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())
|
||||
Expect(summary.Node.CPU.UsageCoreNanoSeconds).NotTo(BeNil())
|
||||
Expect(*summary.Node.CPU.UsageCoreNanoSeconds).NotTo(BeZero())
|
||||
|
||||
Expect(summary.Node.Memory.UsageBytes).NotTo(BeNil())
|
||||
Expect(*summary.Node.Memory.UsageBytes).NotTo(BeZero())
|
||||
|
||||
Expect(summary.Node.Memory.WorkingSetBytes).NotTo(BeNil())
|
||||
Expect(*summary.Node.Memory.WorkingSetBytes).NotTo(BeZero())
|
||||
|
||||
Expect(summary.Node.Fs.AvailableBytes).NotTo(BeNil())
|
||||
Expect(*summary.Node.Fs.AvailableBytes).NotTo(BeZero())
|
||||
Expect(summary.Node.Fs.CapacityBytes).NotTo(BeNil())
|
||||
Expect(*summary.Node.Fs.CapacityBytes).NotTo(BeZero())
|
||||
Expect(summary.Node.Fs.UsedBytes).NotTo(BeNil())
|
||||
Expect(*summary.Node.Fs.UsedBytes).NotTo(BeZero())
|
||||
|
||||
By("Having resources for kubelet and runtime system containers")
|
||||
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())
|
||||
ExpectContainerStatsNotEmpty(&container)
|
||||
}
|
||||
Expect(sysContainersList).To(ConsistOf("kubelet", "runtime"))
|
||||
|
||||
// Verify Pods Stats are present
|
||||
podsList := []string{}
|
||||
By("Having resources for pods")
|
||||
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)
|
||||
|
||||
ExpectContainerStatsNotEmpty(&container)
|
||||
|
||||
// emptydir volume
|
||||
volumeNames := []string{}
|
||||
for _, vs := range pod.VolumeStats {
|
||||
Expect(vs.CapacityBytes).NotTo(BeZero())
|
||||
Expect(vs.AvailableBytes).NotTo(BeZero())
|
||||
Expect(vs.UsedBytes).NotTo(BeZero())
|
||||
if strings.HasPrefix(vs.Name, "default-token-") {
|
||||
volumeNames = append(volumeNames, "default-token-")
|
||||
} else {
|
||||
volumeNames = append(volumeNames, vs.Name)
|
||||
}
|
||||
}
|
||||
Expect(volumeNames).To(ConsistOf("default-token-", "test-empty-dir"))
|
||||
|
||||
// fs usage (not for system containers)
|
||||
Expect(container.Rootfs).NotTo(BeNil(), spew.Sdump(container))
|
||||
Expect(container.Rootfs.AvailableBytes).NotTo(BeNil(), spew.Sdump(container))
|
||||
Expect(*container.Rootfs.AvailableBytes).NotTo(BeZero(), spew.Sdump(container))
|
||||
Expect(container.Rootfs.CapacityBytes).NotTo(BeNil(), spew.Sdump(container))
|
||||
Expect(*container.Rootfs.CapacityBytes).NotTo(BeZero(), spew.Sdump(container))
|
||||
Expect(container.Rootfs.UsedBytes).NotTo(BeNil(), spew.Sdump(container))
|
||||
Expect(*container.Rootfs.UsedBytes).NotTo(BeZero(), spew.Sdump(container))
|
||||
Expect(container.Logs).NotTo(BeNil(), spew.Sdump(container))
|
||||
Expect(container.Logs.AvailableBytes).NotTo(BeNil(), spew.Sdump(container))
|
||||
Expect(*container.Logs.AvailableBytes).NotTo(BeZero(), spew.Sdump(container))
|
||||
Expect(container.Logs.CapacityBytes).NotTo(BeNil(), spew.Sdump(container))
|
||||
Expect(*container.Logs.CapacityBytes).NotTo(BeZero(), spew.Sdump(container))
|
||||
Expect(container.Logs.UsedBytes).NotTo(BeNil(), spew.Sdump(container))
|
||||
Expect(*container.Logs.UsedBytes).NotTo(BeZero(), spew.Sdump(container))
|
||||
|
||||
}
|
||||
Expect(podsList).To(ConsistOf(podNames))
|
||||
})
|
||||
@@ -189,11 +222,25 @@ var _ = Describe("Kubelet", func() {
|
||||
})
|
||||
})
|
||||
|
||||
func ExpectContainerStatsNotEmpty(container *stats.ContainerStats) {
|
||||
// TODO: Test Network
|
||||
|
||||
Expect(container.CPU).NotTo(BeNil(), spew.Sdump(container))
|
||||
Expect(container.CPU.UsageCoreNanoSeconds).NotTo(BeNil(), spew.Sdump(container))
|
||||
Expect(*container.CPU.UsageCoreNanoSeconds).NotTo(BeZero(), spew.Sdump(container))
|
||||
|
||||
Expect(container.Memory).NotTo(BeNil(), spew.Sdump(container))
|
||||
Expect(container.Memory.UsageBytes).NotTo(BeNil(), spew.Sdump(container))
|
||||
Expect(*container.Memory.UsageBytes).NotTo(BeZero(), spew.Sdump(container))
|
||||
Expect(container.Memory.WorkingSetBytes).NotTo(BeNil(), spew.Sdump(container))
|
||||
Expect(*container.Memory.WorkingSetBytes).NotTo(BeZero(), spew.Sdump(container))
|
||||
}
|
||||
|
||||
const (
|
||||
containerSuffix = "-c"
|
||||
)
|
||||
|
||||
func createPod(cl *client.Client, podName string, containers []api.Container) {
|
||||
func createPod(cl *client.Client, podName string, containers []api.Container, volumes []api.Volume) {
|
||||
pod := &api.Pod{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: podName,
|
||||
@@ -205,6 +252,7 @@ func createPod(cl *client.Client, podName string, containers []api.Container) {
|
||||
// Don't restart the Pod since it is expected to exit
|
||||
RestartPolicy: api.RestartPolicyNever,
|
||||
Containers: containers,
|
||||
Volumes: volumes,
|
||||
},
|
||||
}
|
||||
_, err := cl.Pods(api.NamespaceDefault).Create(pod)
|
||||
|
||||
Reference in New Issue
Block a user