diff --git a/pkg/kubelet/eviction/BUILD b/pkg/kubelet/eviction/BUILD index 84ee858eafe..a8727ecc7a4 100644 --- a/pkg/kubelet/eviction/BUILD +++ b/pkg/kubelet/eviction/BUILD @@ -59,7 +59,6 @@ go_library( "//pkg/kubelet/server/stats:go_default_library", "//pkg/kubelet/types:go_default_library", "//pkg/kubelet/util/format:go_default_library", - "//pkg/volume/util:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/kubelet/eviction/helpers.go b/pkg/kubelet/eviction/helpers.go index 55ddb368aea..322f618bf1b 100644 --- a/pkg/kubelet/eviction/helpers.go +++ b/pkg/kubelet/eviction/helpers.go @@ -31,7 +31,6 @@ import ( v1resource "k8s.io/kubernetes/pkg/api/v1/resource" evictionapi "k8s.io/kubernetes/pkg/kubelet/eviction/api" kubetypes "k8s.io/kubernetes/pkg/kubelet/types" - volumeutils "k8s.io/kubernetes/pkg/volume/util" ) const ( @@ -412,38 +411,6 @@ func podDiskUsage(podStats statsapi.PodStats, pod *v1.Pod, statsToMeasure []fsSt }, nil } -// localEphemeralVolumeNames returns the set of ephemeral volumes for the pod that are local -func localEphemeralVolumeNames(pod *v1.Pod) []string { - result := []string{} - for _, volume := range pod.Spec.Volumes { - if volumeutils.IsLocalEphemeralVolume(volume) { - result = append(result, volume.Name) - } - } - return result -} - -// podLocalEphemeralStorageUsage aggregates pod local ephemeral storage usage and inode consumption for the specified stats to measure. -func podLocalEphemeralStorageUsage(podStats statsapi.PodStats, pod *v1.Pod, statsToMeasure []fsStatsType) (v1.ResourceList, error) { - disk := resource.Quantity{Format: resource.BinarySI} - inodes := resource.Quantity{Format: resource.DecimalSI} - - containerUsageList := containerUsage(podStats, statsToMeasure) - disk.Add(containerUsageList[v1.ResourceEphemeralStorage]) - inodes.Add(containerUsageList[resourceInodes]) - - if hasFsStatsType(statsToMeasure, fsStatsLocalVolumeSource) { - volumeNames := localEphemeralVolumeNames(pod) - podLocalVolumeUsageList := podLocalVolumeUsage(volumeNames, podStats) - disk.Add(podLocalVolumeUsageList[v1.ResourceEphemeralStorage]) - inodes.Add(podLocalVolumeUsageList[resourceInodes]) - } - return v1.ResourceList{ - v1.ResourceEphemeralStorage: disk, - resourceInodes: inodes, - }, nil -} - // formatThreshold formats a threshold for logging. func formatThreshold(threshold evictionapi.Threshold) string { return fmt.Sprintf("threshold(signal=%v, operator=%v, value=%v, gracePeriod=%v)", threshold.Signal, threshold.Operator, evictionapi.ThresholdValue(threshold.Value), threshold.GracePeriod) diff --git a/pkg/kubelet/stats/BUILD b/pkg/kubelet/stats/BUILD index 6ae531b74f4..437761ab716 100644 --- a/pkg/kubelet/stats/BUILD +++ b/pkg/kubelet/stats/BUILD @@ -8,7 +8,8 @@ go_library( "cri_stats_provider_others.go", "cri_stats_provider_windows.go", "helper.go", - "log_metrics_provider.go", + "host_stats_provider.go", + "host_stats_provider_fake.go", "provider.go", ], importpath = "k8s.io/kubernetes/pkg/kubelet/stats", @@ -17,6 +18,7 @@ go_library( "//pkg/kubelet/cadvisor:go_default_library", "//pkg/kubelet/cm:go_default_library", "//pkg/kubelet/container:go_default_library", + "//pkg/kubelet/container/testing:go_default_library", "//pkg/kubelet/kuberuntime:go_default_library", "//pkg/kubelet/leaky:go_default_library", "//pkg/kubelet/pod:go_default_library", @@ -66,7 +68,6 @@ go_test( "cadvisor_stats_provider_test.go", "cri_stats_provider_test.go", "helper_test.go", - "log_metrics_provider_test.go", "provider_test.go", ], embed = [":go_default_library"], diff --git a/pkg/kubelet/stats/cri_stats_provider_test.go b/pkg/kubelet/stats/cri_stats_provider_test.go index c506b9b611b..d5cefec1306 100644 --- a/pkg/kubelet/stats/cri_stats_provider_test.go +++ b/pkg/kubelet/stats/cri_stats_provider_test.go @@ -230,7 +230,7 @@ func TestCRIListPodStats(t *testing.T) { mockRuntimeCache, fakeRuntimeService, fakeImageService, - NewFakeHostStatsProviderWithData(fakeStats), + NewFakeHostStatsProviderWithData(fakeStats, fakeOS), ) stats, err := provider.ListPodStats() diff --git a/pkg/kubelet/stats/host_stats_provider.go b/pkg/kubelet/stats/host_stats_provider.go index 2bf32950a79..9c03fb542a4 100644 --- a/pkg/kubelet/stats/host_stats_provider.go +++ b/pkg/kubelet/stats/host_stats_provider.go @@ -29,7 +29,7 @@ import ( "k8s.io/kubernetes/pkg/volume" ) -// PodEtcHostsFunc is a function to fetch a etc hosts path by pod uid. +// PodEtcHostsPathFunc is a function to fetch a etc hosts path by pod uid. type PodEtcHostsPathFunc func(podUID types.UID) string // metricsProviderByPath maps a path to its metrics provider @@ -52,7 +52,7 @@ type hostStatsProvider struct { podEtcHostsPathFunc PodEtcHostsPathFunc } -// NewLogMetricsService returns a new LogMetricsService type struct. +// NewHostStatsProvider returns a new HostStatsProvider type struct. func NewHostStatsProvider(osInterface kubecontainer.OSInterface, podEtcHostsPathFunc PodEtcHostsPathFunc) HostStatsProvider { return hostStatsProvider{ osInterface: osInterface, diff --git a/pkg/kubelet/stats/host_stats_provider_fake.go b/pkg/kubelet/stats/host_stats_provider_fake.go index 961349e94e0..3d68e36badd 100644 --- a/pkg/kubelet/stats/host_stats_provider_fake.go +++ b/pkg/kubelet/stats/host_stats_provider_fake.go @@ -18,61 +18,78 @@ package stats import ( "fmt" + "path/filepath" cadvisorapiv2 "github.com/google/cadvisor/info/v2" "k8s.io/apimachinery/pkg/types" statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1" + kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" + kubecontainertest "k8s.io/kubernetes/pkg/kubelet/container/testing" "k8s.io/kubernetes/pkg/kubelet/kuberuntime" "k8s.io/kubernetes/pkg/volume" ) type fakeHostStatsProvider struct { - fakeStats map[string]*volume.Metrics + fakeStats map[string]*volume.Metrics + osInterface kubecontainer.OSInterface } +// NewFakeHostStatsProvider provides a way to test with fake host statistics func NewFakeHostStatsProvider() HostStatsProvider { - return &fakeHostStatsProvider{} + return &fakeHostStatsProvider{ + osInterface: &kubecontainertest.FakeOS{}, + } } -func NewFakeHostStatsProviderWithData(fakeStats map[string]*volume.Metrics) HostStatsProvider { +// NewFakeHostStatsProviderWithData provides a way to test with fake host statistics +func NewFakeHostStatsProviderWithData(fakeStats map[string]*volume.Metrics, osInterface kubecontainer.OSInterface) HostStatsProvider { return &fakeHostStatsProvider{ - fakeStats: fakeStats, + fakeStats: fakeStats, + osInterface: osInterface, } } func (f *fakeHostStatsProvider) getPodLogStats(podNamespace, podName string, podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) { path := kuberuntime.BuildPodLogsDirectory(podNamespace, podName, podUID) - if _, found := f.fakeStats[path]; found { - fmt.Printf("P PATH: %s found\n", path) + files, err := f.osInterface.ReadDir(path) + if err != nil { + return nil, err } - metricsProvider := NewFakeMetricsDu(path, f.fakeStats[path]) - return fakeMetricsProviderToStats(metricsProvider, rootFsInfo) + var results []volume.MetricsProvider + for _, file := range files { + if file.IsDir() { + continue + } + // Only include *files* under pod log directory. + fpath := filepath.Join(path, file.Name()) + results = append(results, NewFakeMetricsDu(fpath, f.fakeStats[fpath])) + } + return fakeMetricsProvidersToStats(results, rootFsInfo) } func (f *fakeHostStatsProvider) getPodContainerLogStats(podNamespace, podName string, podUID types.UID, containerName string, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) { path := kuberuntime.BuildContainerLogsDirectory(podNamespace, podName, podUID, containerName) - if _, found := f.fakeStats[path]; found { - fmt.Printf("C PATH: %s found\n", path) - } metricsProvider := NewFakeMetricsDu(path, f.fakeStats[path]) - return fakeMetricsProviderToStats(metricsProvider, rootFsInfo) + return fakeMetricsProvidersToStats([]volume.MetricsProvider{metricsProvider}, rootFsInfo) } func (f *fakeHostStatsProvider) getPodEtcHostsStats(podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) { return nil, fmt.Errorf("not implemented") } -func fakeMetricsProviderToStats(metricsProvider volume.MetricsProvider, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) { - hostMetrics, err := metricsProvider.GetMetrics() - if err != nil { - return nil, fmt.Errorf("failed to get stats %v", err) - } +func fakeMetricsProvidersToStats(metricsProviders []volume.MetricsProvider, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) { result := rootFsInfoToFsStats(rootFsInfo) - usedBytes := uint64(hostMetrics.Used.Value()) - inodesUsed := uint64(hostMetrics.InodesUsed.Value()) - result.UsedBytes = addUsage(result.UsedBytes, &usedBytes) - result.InodesUsed = addUsage(result.InodesUsed, &inodesUsed) - result.Time = maxUpdateTime(&result.Time, &hostMetrics.Time) + for i, metricsProvider := range metricsProviders { + hostMetrics, err := metricsProvider.GetMetrics() + if err != nil { + return nil, fmt.Errorf("failed to get stats for item %d: %v", i, err) + } + usedBytes := uint64(hostMetrics.Used.Value()) + inodesUsed := uint64(hostMetrics.InodesUsed.Value()) + result.UsedBytes = addUsage(result.UsedBytes, &usedBytes) + result.InodesUsed = addUsage(result.InodesUsed, &inodesUsed) + result.Time = maxUpdateTime(&result.Time, &hostMetrics.Time) + } return result, nil } @@ -80,6 +97,7 @@ type fakeMetricsDu struct { fakeStats *volume.Metrics } +// NewFakeMetricsDu inserts fake statistics when asked for metrics func NewFakeMetricsDu(path string, stats *volume.Metrics) volume.MetricsProvider { return &fakeMetricsDu{fakeStats: stats} }