...

Source file src/k8s.io/kubernetes/pkg/kubelet/metrics/collectors/resource_metrics_test.go

Documentation: k8s.io/kubernetes/pkg/kubelet/metrics/collectors

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package collectors
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"strings"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/golang/mock/gomock"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"k8s.io/component-base/metrics/testutil"
    29  	statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
    30  	summaryprovidertest "k8s.io/kubernetes/pkg/kubelet/server/stats/testing"
    31  )
    32  
    33  func TestCollectResourceMetrics(t *testing.T) {
    34  	// a static timestamp: 2021-06-23 05:11:18.302091597 +0800
    35  	staticTimestamp := time.Unix(0, 1624396278302091597)
    36  	testTime := metav1.NewTime(staticTimestamp)
    37  	interestedMetrics := []string{
    38  		"scrape_error",
    39  		"resource_scrape_error",
    40  		"node_cpu_usage_seconds_total",
    41  		"node_memory_working_set_bytes",
    42  		"node_swap_usage_bytes",
    43  		"container_cpu_usage_seconds_total",
    44  		"container_memory_working_set_bytes",
    45  		"container_swap_usage_bytes",
    46  		"container_start_time_seconds",
    47  		"pod_cpu_usage_seconds_total",
    48  		"pod_memory_working_set_bytes",
    49  		"pod_swap_usage_bytes",
    50  	}
    51  	mockCtrl := gomock.NewController(t)
    52  	defer mockCtrl.Finish()
    53  
    54  	tests := []struct {
    55  		name            string
    56  		summary         *statsapi.Summary
    57  		summaryErr      error
    58  		expectedMetrics string
    59  	}{
    60  		{
    61  			name:       "error getting summary",
    62  			summary:    nil,
    63  			summaryErr: fmt.Errorf("failed to get summary"),
    64  			expectedMetrics: `
    65  				# HELP scrape_error [ALPHA] 1 if there was an error while getting container metrics, 0 otherwise
    66  				# TYPE scrape_error gauge
    67  				scrape_error 1
    68  				# HELP resource_scrape_error [STABLE] 1 if there was an error while getting container metrics, 0 otherwise
    69  				# TYPE resource_scrape_error gauge
    70  				resource_scrape_error 1
    71  			`,
    72  		},
    73  		{
    74  			name: "arbitrary node metrics",
    75  			summary: &statsapi.Summary{
    76  				Node: statsapi.NodeStats{
    77  					CPU: &statsapi.CPUStats{
    78  						Time:                 testTime,
    79  						UsageCoreNanoSeconds: uint64Ptr(10000000000),
    80  					},
    81  					Memory: &statsapi.MemoryStats{
    82  						Time:            testTime,
    83  						WorkingSetBytes: uint64Ptr(1000),
    84  					},
    85  					Swap: &statsapi.SwapStats{
    86  						Time:           testTime,
    87  						SwapUsageBytes: uint64Ptr(500),
    88  					},
    89  				},
    90  			},
    91  			summaryErr: nil,
    92  			expectedMetrics: `
    93  				# HELP node_cpu_usage_seconds_total [STABLE] Cumulative cpu time consumed by the node in core-seconds
    94  				# TYPE node_cpu_usage_seconds_total counter
    95  				node_cpu_usage_seconds_total 10 1624396278302
    96  				# HELP node_memory_working_set_bytes [STABLE] Current working set of the node in bytes
    97  				# TYPE node_memory_working_set_bytes gauge
    98  				node_memory_working_set_bytes 1000 1624396278302
    99  				# HELP node_swap_usage_bytes [ALPHA] Current swap usage of the node in bytes. Reported only on non-windows systems
   100  				# TYPE node_swap_usage_bytes gauge
   101  				node_swap_usage_bytes 500 1624396278302
   102  				# HELP scrape_error [ALPHA] 1 if there was an error while getting container metrics, 0 otherwise
   103  				# TYPE scrape_error gauge
   104  				scrape_error 0
   105  				# HELP resource_scrape_error [STABLE] 1 if there was an error while getting container metrics, 0 otherwise
   106  				# TYPE resource_scrape_error gauge
   107  				resource_scrape_error 0
   108  			`,
   109  		},
   110  		{
   111  			name: "nil node metrics",
   112  			summary: &statsapi.Summary{
   113  				Node: statsapi.NodeStats{
   114  					CPU: &statsapi.CPUStats{
   115  						Time:                 testTime,
   116  						UsageCoreNanoSeconds: nil,
   117  					},
   118  					Memory: &statsapi.MemoryStats{
   119  						Time:            testTime,
   120  						WorkingSetBytes: nil,
   121  					},
   122  				},
   123  			},
   124  			summaryErr: nil,
   125  			expectedMetrics: `
   126  				# HELP scrape_error [ALPHA] 1 if there was an error while getting container metrics, 0 otherwise
   127  				# TYPE scrape_error gauge
   128  				scrape_error 0
   129  				# HELP resource_scrape_error [STABLE] 1 if there was an error while getting container metrics, 0 otherwise
   130  				# TYPE resource_scrape_error gauge
   131  				resource_scrape_error 0
   132  			`,
   133  		},
   134  		{
   135  			name: "arbitrary container metrics for different container, pods and namespaces",
   136  			summary: &statsapi.Summary{
   137  				Pods: []statsapi.PodStats{
   138  					{
   139  						PodRef: statsapi.PodReference{
   140  							Name:      "pod_a",
   141  							Namespace: "namespace_a",
   142  						},
   143  						Containers: []statsapi.ContainerStats{
   144  							{
   145  								Name:      "container_a",
   146  								StartTime: metav1.NewTime(staticTimestamp.Add(-30 * time.Second)),
   147  								CPU: &statsapi.CPUStats{
   148  									Time:                 testTime,
   149  									UsageCoreNanoSeconds: uint64Ptr(10000000000),
   150  								},
   151  								Memory: &statsapi.MemoryStats{
   152  									Time:            testTime,
   153  									WorkingSetBytes: uint64Ptr(1000),
   154  								},
   155  								Swap: &statsapi.SwapStats{
   156  									Time:           testTime,
   157  									SwapUsageBytes: uint64Ptr(1000),
   158  								},
   159  							},
   160  							{
   161  								Name:      "container_b",
   162  								StartTime: metav1.NewTime(staticTimestamp.Add(-2 * time.Minute)),
   163  								CPU: &statsapi.CPUStats{
   164  									Time:                 testTime,
   165  									UsageCoreNanoSeconds: uint64Ptr(10000000000),
   166  								},
   167  								Memory: &statsapi.MemoryStats{
   168  									Time:            testTime,
   169  									WorkingSetBytes: uint64Ptr(1000),
   170  								},
   171  							},
   172  						},
   173  					},
   174  					{
   175  						PodRef: statsapi.PodReference{
   176  							Name:      "pod_b",
   177  							Namespace: "namespace_b",
   178  						},
   179  						Containers: []statsapi.ContainerStats{
   180  							{
   181  								Name:      "container_a",
   182  								StartTime: metav1.NewTime(staticTimestamp.Add(-10 * time.Minute)),
   183  								CPU: &statsapi.CPUStats{
   184  									Time:                 testTime,
   185  									UsageCoreNanoSeconds: uint64Ptr(10000000000),
   186  								},
   187  								Memory: &statsapi.MemoryStats{
   188  									Time:            testTime,
   189  									WorkingSetBytes: uint64Ptr(1000),
   190  								},
   191  							},
   192  						},
   193  					},
   194  				},
   195  			},
   196  			summaryErr: nil,
   197  			expectedMetrics: `
   198  				# HELP scrape_error [ALPHA] 1 if there was an error while getting container metrics, 0 otherwise
   199  				# TYPE scrape_error gauge
   200  				scrape_error 0
   201  				# HELP resource_scrape_error [STABLE] 1 if there was an error while getting container metrics, 0 otherwise
   202  				# TYPE resource_scrape_error gauge
   203  				resource_scrape_error 0
   204  				# HELP container_cpu_usage_seconds_total [STABLE] Cumulative cpu time consumed by the container in core-seconds
   205  				# TYPE container_cpu_usage_seconds_total counter
   206  				container_cpu_usage_seconds_total{container="container_a",namespace="namespace_a",pod="pod_a"} 10 1624396278302
   207  				container_cpu_usage_seconds_total{container="container_a",namespace="namespace_b",pod="pod_b"} 10 1624396278302
   208  				container_cpu_usage_seconds_total{container="container_b",namespace="namespace_a",pod="pod_a"} 10 1624396278302
   209  				# HELP container_memory_working_set_bytes [STABLE] Current working set of the container in bytes
   210  				# TYPE container_memory_working_set_bytes gauge
   211  				container_memory_working_set_bytes{container="container_a",namespace="namespace_a",pod="pod_a"} 1000 1624396278302
   212  				container_memory_working_set_bytes{container="container_a",namespace="namespace_b",pod="pod_b"} 1000 1624396278302
   213  				container_memory_working_set_bytes{container="container_b",namespace="namespace_a",pod="pod_a"} 1000 1624396278302
   214  				# HELP container_start_time_seconds [STABLE] Start time of the container since unix epoch in seconds
   215  				# TYPE container_start_time_seconds gauge
   216  				container_start_time_seconds{container="container_a",namespace="namespace_a",pod="pod_a"} 1.6243962483020916e+09
   217  				container_start_time_seconds{container="container_a",namespace="namespace_b",pod="pod_b"} 1.6243956783020916e+09
   218  				container_start_time_seconds{container="container_b",namespace="namespace_a",pod="pod_a"} 1.6243961583020916e+09
   219          		# HELP container_swap_usage_bytes [ALPHA] Current amount of the container swap usage in bytes. Reported only on non-windows systems
   220          		# TYPE container_swap_usage_bytes gauge
   221          		container_swap_usage_bytes{container="container_a",namespace="namespace_a",pod="pod_a"} 1000 1624396278302
   222  			`,
   223  		},
   224  		{
   225  			name: "arbitrary container metrics for negative StartTime",
   226  			summary: &statsapi.Summary{
   227  				Pods: []statsapi.PodStats{
   228  					{
   229  						PodRef: statsapi.PodReference{
   230  							Name:      "pod_a",
   231  							Namespace: "namespace_a",
   232  						},
   233  						Containers: []statsapi.ContainerStats{
   234  							{
   235  								Name:      "container_a",
   236  								StartTime: metav1.NewTime(time.Unix(0, -1624396278302091597)),
   237  								CPU: &statsapi.CPUStats{
   238  									Time:                 testTime,
   239  									UsageCoreNanoSeconds: uint64Ptr(10000000000),
   240  								},
   241  								Memory: &statsapi.MemoryStats{
   242  									Time:            testTime,
   243  									WorkingSetBytes: uint64Ptr(1000),
   244  								},
   245  							},
   246  						},
   247  					},
   248  				},
   249  			},
   250  			summaryErr: nil,
   251  			expectedMetrics: `
   252  				# HELP scrape_error [ALPHA] 1 if there was an error while getting container metrics, 0 otherwise
   253  				# TYPE scrape_error gauge
   254  				scrape_error 0
   255  				# HELP resource_scrape_error [STABLE] 1 if there was an error while getting container metrics, 0 otherwise
   256  				# TYPE resource_scrape_error gauge
   257  				resource_scrape_error 0
   258  				# HELP container_cpu_usage_seconds_total [STABLE] Cumulative cpu time consumed by the container in core-seconds
   259  				# TYPE container_cpu_usage_seconds_total counter
   260  				container_cpu_usage_seconds_total{container="container_a",namespace="namespace_a",pod="pod_a"} 10 1624396278302
   261  				# HELP container_memory_working_set_bytes [STABLE] Current working set of the container in bytes
   262  				# TYPE container_memory_working_set_bytes gauge
   263  				container_memory_working_set_bytes{container="container_a",namespace="namespace_a",pod="pod_a"} 1000 1624396278302
   264  			`,
   265  		},
   266  		{
   267  			name: "nil container metrics",
   268  			summary: &statsapi.Summary{
   269  				Pods: []statsapi.PodStats{
   270  					{
   271  						PodRef: statsapi.PodReference{
   272  							Name:      "pod_a",
   273  							Namespace: "namespace_a",
   274  						},
   275  						Containers: []statsapi.ContainerStats{
   276  							{
   277  								Name:      "container_a",
   278  								StartTime: metav1.NewTime(staticTimestamp.Add(-30 * time.Second)),
   279  								CPU: &statsapi.CPUStats{
   280  									Time:                 testTime,
   281  									UsageCoreNanoSeconds: nil,
   282  								},
   283  								Memory: &statsapi.MemoryStats{
   284  									Time:            testTime,
   285  									WorkingSetBytes: nil,
   286  								},
   287  							},
   288  						},
   289  					},
   290  					{
   291  						PodRef: statsapi.PodReference{
   292  							Name:      "pod_b",
   293  							Namespace: "namespace_b",
   294  						},
   295  						Containers: []statsapi.ContainerStats{
   296  							{
   297  								Name:      "container_a",
   298  								StartTime: metav1.NewTime(staticTimestamp.Add(-10 * time.Minute)),
   299  								CPU: &statsapi.CPUStats{
   300  									Time:                 testTime,
   301  									UsageCoreNanoSeconds: uint64Ptr(10000000000),
   302  								},
   303  								Memory: &statsapi.MemoryStats{
   304  									Time:            testTime,
   305  									WorkingSetBytes: uint64Ptr(1000),
   306  								},
   307  							},
   308  						},
   309  					},
   310  				},
   311  			},
   312  			summaryErr: nil,
   313  			expectedMetrics: `
   314  				# HELP container_cpu_usage_seconds_total [STABLE] Cumulative cpu time consumed by the container in core-seconds
   315  				# TYPE container_cpu_usage_seconds_total counter
   316  				container_cpu_usage_seconds_total{container="container_a",namespace="namespace_b",pod="pod_b"} 10 1624396278302
   317  				# HELP container_memory_working_set_bytes [STABLE] Current working set of the container in bytes
   318  				# TYPE container_memory_working_set_bytes gauge
   319  				container_memory_working_set_bytes{container="container_a",namespace="namespace_b",pod="pod_b"} 1000 1624396278302
   320  				# HELP container_start_time_seconds [STABLE] Start time of the container since unix epoch in seconds
   321  				# TYPE container_start_time_seconds gauge
   322  				container_start_time_seconds{container="container_a",namespace="namespace_a",pod="pod_a"} 1.6243962483020916e+09
   323  				container_start_time_seconds{container="container_a",namespace="namespace_b",pod="pod_b"} 1.6243956783020916e+09
   324  				# HELP scrape_error [ALPHA] 1 if there was an error while getting container metrics, 0 otherwise
   325  				# TYPE scrape_error gauge
   326  				scrape_error 0
   327  				# HELP resource_scrape_error [STABLE] 1 if there was an error while getting container metrics, 0 otherwise
   328  				# TYPE resource_scrape_error gauge
   329  				resource_scrape_error 0
   330  			`,
   331  		},
   332  		{
   333  			name: "arbitrary pod metrics",
   334  			summary: &statsapi.Summary{
   335  				Pods: []statsapi.PodStats{
   336  					{
   337  						PodRef: statsapi.PodReference{
   338  							Name:      "pod_a",
   339  							Namespace: "namespace_a",
   340  						},
   341  						CPU: &statsapi.CPUStats{
   342  							Time:                 testTime,
   343  							UsageCoreNanoSeconds: uint64Ptr(10000000000),
   344  						},
   345  						Memory: &statsapi.MemoryStats{
   346  							Time:            testTime,
   347  							WorkingSetBytes: uint64Ptr(1000),
   348  						},
   349  						Swap: &statsapi.SwapStats{
   350  							Time:           testTime,
   351  							SwapUsageBytes: uint64Ptr(5000),
   352  						},
   353  					},
   354  				},
   355  			},
   356  			summaryErr: nil,
   357  			expectedMetrics: `
   358  				# HELP scrape_error [ALPHA] 1 if there was an error while getting container metrics, 0 otherwise
   359  				# TYPE scrape_error gauge
   360  				scrape_error 0
   361  				# HELP resource_scrape_error [STABLE] 1 if there was an error while getting container metrics, 0 otherwise
   362  				# TYPE resource_scrape_error gauge
   363  				resource_scrape_error 0
   364  				# HELP pod_cpu_usage_seconds_total [STABLE] Cumulative cpu time consumed by the pod in core-seconds
   365  				# TYPE pod_cpu_usage_seconds_total counter
   366  				pod_cpu_usage_seconds_total{namespace="namespace_a",pod="pod_a"} 10 1624396278302
   367  				# HELP pod_memory_working_set_bytes [STABLE] Current working set of the pod in bytes
   368  				# TYPE pod_memory_working_set_bytes gauge
   369  				pod_memory_working_set_bytes{namespace="namespace_a",pod="pod_a"} 1000 1624396278302
   370  				# HELP pod_swap_usage_bytes [ALPHA] Current amount of the pod swap usage in bytes. Reported only on non-windows systems
   371  				# TYPE pod_swap_usage_bytes gauge
   372  				pod_swap_usage_bytes{namespace="namespace_a",pod="pod_a"} 5000 1624396278302
   373  			`,
   374  		},
   375  		{
   376  			name: "nil pod metrics",
   377  			summary: &statsapi.Summary{
   378  				Pods: []statsapi.PodStats{
   379  					{
   380  						PodRef: statsapi.PodReference{
   381  							Name:      "pod_a",
   382  							Namespace: "namespace_a",
   383  						},
   384  						CPU: &statsapi.CPUStats{
   385  							Time:                 testTime,
   386  							UsageCoreNanoSeconds: nil,
   387  						},
   388  						Memory: &statsapi.MemoryStats{
   389  							Time:            testTime,
   390  							WorkingSetBytes: nil,
   391  						},
   392  					},
   393  				},
   394  			},
   395  			summaryErr: nil,
   396  			expectedMetrics: `
   397  				# HELP scrape_error [ALPHA] 1 if there was an error while getting container metrics, 0 otherwise
   398  				# TYPE scrape_error gauge
   399  				scrape_error 0
   400  				# HELP resource_scrape_error [STABLE] 1 if there was an error while getting container metrics, 0 otherwise
   401  				# TYPE resource_scrape_error gauge
   402  				resource_scrape_error 0
   403  			`,
   404  		},
   405  	}
   406  
   407  	for _, test := range tests {
   408  		tc := test
   409  		t.Run(tc.name, func(t *testing.T) {
   410  			ctx := context.Background()
   411  			provider := summaryprovidertest.NewMockSummaryProvider(mockCtrl)
   412  			provider.EXPECT().GetCPUAndMemoryStats(ctx).Return(tc.summary, tc.summaryErr).AnyTimes()
   413  			collector := NewResourceMetricsCollector(provider)
   414  
   415  			if err := testutil.CustomCollectAndCompare(collector, strings.NewReader(tc.expectedMetrics), interestedMetrics...); err != nil {
   416  				t.Fatal(err)
   417  			}
   418  		})
   419  	}
   420  }
   421  
   422  func uint64Ptr(u uint64) *uint64 {
   423  	return &u
   424  }
   425  

View as plain text