...

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

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

     1  /*
     2  Copyright 2018 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  	"strings"
    22  	"testing"
    23  
    24  	"github.com/golang/mock/gomock"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/component-base/metrics/testutil"
    27  	statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
    28  	statstest "k8s.io/kubernetes/pkg/kubelet/server/stats/testing"
    29  )
    30  
    31  func newUint64Pointer(i uint64) *uint64 {
    32  	return &i
    33  }
    34  
    35  func TestVolumeStatsCollector(t *testing.T) {
    36  	ctx := context.Background()
    37  	// Fixed metadata on type and help text. We prepend this to every expected
    38  	// output so we only have to modify a single place when doing adjustments.
    39  	const metadata = `
    40  		# HELP kubelet_volume_stats_available_bytes [ALPHA] Number of available bytes in the volume
    41  		# TYPE kubelet_volume_stats_available_bytes gauge
    42  		# HELP kubelet_volume_stats_capacity_bytes [ALPHA] Capacity in bytes of the volume
    43  		# TYPE kubelet_volume_stats_capacity_bytes gauge
    44  		# HELP kubelet_volume_stats_inodes [ALPHA] Maximum number of inodes in the volume
    45  		# TYPE kubelet_volume_stats_inodes gauge
    46  		# HELP kubelet_volume_stats_inodes_free [ALPHA] Number of free inodes in the volume
    47  		# TYPE kubelet_volume_stats_inodes_free gauge
    48  		# HELP kubelet_volume_stats_inodes_used [ALPHA] Number of used inodes in the volume
    49  		# TYPE kubelet_volume_stats_inodes_used gauge
    50  		# HELP kubelet_volume_stats_used_bytes [ALPHA] Number of used bytes in the volume
    51  		# TYPE kubelet_volume_stats_used_bytes gauge
    52  		# HELP kubelet_volume_stats_health_status_abnormal [ALPHA] Abnormal volume health status. The count is either 1 or 0. 1 indicates the volume is unhealthy, 0 indicates volume is healthy
    53  		# TYPE kubelet_volume_stats_health_status_abnormal gauge
    54  	`
    55  
    56  	var (
    57  		podStats = []statsapi.PodStats{
    58  			{
    59  				PodRef:    statsapi.PodReference{Name: "test-pod", Namespace: "test-namespace", UID: "UID_test-pod"},
    60  				StartTime: metav1.Now(),
    61  				VolumeStats: []statsapi.VolumeStats{
    62  					{
    63  						FsStats: statsapi.FsStats{
    64  							Time:           metav1.Now(),
    65  							AvailableBytes: newUint64Pointer(5.663154176e+09),
    66  							CapacityBytes:  newUint64Pointer(1.0434699264e+10),
    67  							UsedBytes:      newUint64Pointer(4.21789696e+09),
    68  							InodesFree:     newUint64Pointer(655344),
    69  							Inodes:         newUint64Pointer(655360),
    70  							InodesUsed:     newUint64Pointer(16),
    71  						},
    72  						Name:   "test",
    73  						PVCRef: nil,
    74  					},
    75  					{
    76  						FsStats: statsapi.FsStats{
    77  							Time:           metav1.Now(),
    78  							AvailableBytes: newUint64Pointer(5.663154176e+09),
    79  							CapacityBytes:  newUint64Pointer(1.0434699264e+10),
    80  							UsedBytes:      newUint64Pointer(4.21789696e+09),
    81  							InodesFree:     newUint64Pointer(655344),
    82  							Inodes:         newUint64Pointer(655360),
    83  							InodesUsed:     newUint64Pointer(16),
    84  						},
    85  						Name: "test",
    86  						PVCRef: &statsapi.PVCReference{
    87  							Name:      "testpvc",
    88  							Namespace: "testns",
    89  						},
    90  						VolumeHealthStats: &statsapi.VolumeHealthStats{
    91  							Abnormal: true,
    92  						},
    93  					},
    94  				},
    95  			},
    96  			{
    97  				// Another pod references the same PVC (test-namespace/testpvc).
    98  				PodRef:    statsapi.PodReference{Name: "test-pod-2", Namespace: "test-namespace", UID: "UID_test-pod"},
    99  				StartTime: metav1.Now(),
   100  				VolumeStats: []statsapi.VolumeStats{
   101  					{
   102  						FsStats: statsapi.FsStats{
   103  							Time:           metav1.Now(),
   104  							AvailableBytes: newUint64Pointer(5.663154176e+09),
   105  							CapacityBytes:  newUint64Pointer(1.0434699264e+10),
   106  							UsedBytes:      newUint64Pointer(4.21789696e+09),
   107  							InodesFree:     newUint64Pointer(655344),
   108  							Inodes:         newUint64Pointer(655360),
   109  							InodesUsed:     newUint64Pointer(16),
   110  						},
   111  						Name: "test",
   112  						PVCRef: &statsapi.PVCReference{
   113  							Name:      "testpvc",
   114  							Namespace: "testns",
   115  						},
   116  						VolumeHealthStats: &statsapi.VolumeHealthStats{
   117  							Abnormal: true,
   118  						},
   119  					},
   120  				},
   121  			},
   122  		}
   123  
   124  		want = metadata + `
   125  			kubelet_volume_stats_available_bytes{namespace="testns",persistentvolumeclaim="testpvc"} 5.663154176e+09
   126  			kubelet_volume_stats_capacity_bytes{namespace="testns",persistentvolumeclaim="testpvc"} 1.0434699264e+10
   127  			kubelet_volume_stats_inodes{namespace="testns",persistentvolumeclaim="testpvc"} 655360
   128  			kubelet_volume_stats_inodes_free{namespace="testns",persistentvolumeclaim="testpvc"} 655344
   129  			kubelet_volume_stats_inodes_used{namespace="testns",persistentvolumeclaim="testpvc"} 16
   130  			kubelet_volume_stats_used_bytes{namespace="testns",persistentvolumeclaim="testpvc"} 4.21789696e+09
   131  			kubelet_volume_stats_health_status_abnormal{namespace="testns",persistentvolumeclaim="testpvc"} 1
   132  			`
   133  
   134  		metrics = []string{
   135  			"kubelet_volume_stats_available_bytes",
   136  			"kubelet_volume_stats_capacity_bytes",
   137  			"kubelet_volume_stats_inodes",
   138  			"kubelet_volume_stats_inodes_free",
   139  			"kubelet_volume_stats_inodes_used",
   140  			"kubelet_volume_stats_used_bytes",
   141  			"kubelet_volume_stats_health_status_abnormal",
   142  		}
   143  	)
   144  
   145  	mockCtrl := gomock.NewController(t)
   146  	defer mockCtrl.Finish()
   147  	mockStatsProvider := statstest.NewMockProvider(mockCtrl)
   148  
   149  	mockStatsProvider.EXPECT().ListPodStats(ctx).Return(podStats, nil).AnyTimes()
   150  	mockStatsProvider.EXPECT().ListPodStatsAndUpdateCPUNanoCoreUsage(ctx).Return(podStats, nil).AnyTimes()
   151  	if err := testutil.CustomCollectAndCompare(&volumeStatsCollector{statsProvider: mockStatsProvider}, strings.NewReader(want), metrics...); err != nil {
   152  		t.Errorf("unexpected collecting result:\n%s", err)
   153  	}
   154  }
   155  
   156  func TestVolumeStatsCollectorWithNullVolumeStatus(t *testing.T) {
   157  	ctx := context.Background()
   158  	// Fixed metadata on type and help text. We prepend this to every expected
   159  	// output so we only have to modify a single place when doing adjustments.
   160  	const metadata = `
   161  		# HELP kubelet_volume_stats_available_bytes [ALPHA] Number of available bytes in the volume
   162  		# TYPE kubelet_volume_stats_available_bytes gauge
   163  		# HELP kubelet_volume_stats_capacity_bytes [ALPHA] Capacity in bytes of the volume
   164  		# TYPE kubelet_volume_stats_capacity_bytes gauge
   165  		# HELP kubelet_volume_stats_inodes [ALPHA] Maximum number of inodes in the volume
   166  		# TYPE kubelet_volume_stats_inodes gauge
   167  		# HELP kubelet_volume_stats_inodes_free [ALPHA] Number of free inodes in the volume
   168  		# TYPE kubelet_volume_stats_inodes_free gauge
   169  		# HELP kubelet_volume_stats_inodes_used [ALPHA] Number of used inodes in the volume
   170  		# TYPE kubelet_volume_stats_inodes_used gauge
   171  		# HELP kubelet_volume_stats_used_bytes [ALPHA] Number of used bytes in the volume
   172  		# TYPE kubelet_volume_stats_used_bytes gauge
   173  	`
   174  
   175  	var (
   176  		podStats = []statsapi.PodStats{
   177  			{
   178  				PodRef:    statsapi.PodReference{Name: "test-pod", Namespace: "test-namespace", UID: "UID_test-pod"},
   179  				StartTime: metav1.Now(),
   180  				VolumeStats: []statsapi.VolumeStats{
   181  					{
   182  						FsStats: statsapi.FsStats{
   183  							Time:           metav1.Now(),
   184  							AvailableBytes: newUint64Pointer(5.663154176e+09),
   185  							CapacityBytes:  newUint64Pointer(1.0434699264e+10),
   186  							UsedBytes:      newUint64Pointer(4.21789696e+09),
   187  							InodesFree:     newUint64Pointer(655344),
   188  							Inodes:         newUint64Pointer(655360),
   189  							InodesUsed:     newUint64Pointer(16),
   190  						},
   191  						Name:   "test",
   192  						PVCRef: nil,
   193  					},
   194  					{
   195  						FsStats: statsapi.FsStats{
   196  							Time:           metav1.Now(),
   197  							AvailableBytes: newUint64Pointer(5.663154176e+09),
   198  							CapacityBytes:  newUint64Pointer(1.0434699264e+10),
   199  							UsedBytes:      newUint64Pointer(4.21789696e+09),
   200  							InodesFree:     newUint64Pointer(655344),
   201  							Inodes:         newUint64Pointer(655360),
   202  							InodesUsed:     newUint64Pointer(16),
   203  						},
   204  						Name: "test",
   205  						PVCRef: &statsapi.PVCReference{
   206  							Name:      "testpvc",
   207  							Namespace: "testns",
   208  						},
   209  					},
   210  				},
   211  			},
   212  		}
   213  
   214  		want = metadata + `
   215  			kubelet_volume_stats_available_bytes{namespace="testns",persistentvolumeclaim="testpvc"} 5.663154176e+09
   216  			kubelet_volume_stats_capacity_bytes{namespace="testns",persistentvolumeclaim="testpvc"} 1.0434699264e+10
   217  			kubelet_volume_stats_inodes{namespace="testns",persistentvolumeclaim="testpvc"} 655360
   218  			kubelet_volume_stats_inodes_free{namespace="testns",persistentvolumeclaim="testpvc"} 655344
   219  			kubelet_volume_stats_inodes_used{namespace="testns",persistentvolumeclaim="testpvc"} 16
   220  			kubelet_volume_stats_used_bytes{namespace="testns",persistentvolumeclaim="testpvc"} 4.21789696e+09
   221  			`
   222  
   223  		metrics = []string{
   224  			"kubelet_volume_stats_available_bytes",
   225  			"kubelet_volume_stats_capacity_bytes",
   226  			"kubelet_volume_stats_inodes",
   227  			"kubelet_volume_stats_inodes_free",
   228  			"kubelet_volume_stats_inodes_used",
   229  			"kubelet_volume_stats_used_bytes",
   230  		}
   231  	)
   232  
   233  	mockCtrl := gomock.NewController(t)
   234  	defer mockCtrl.Finish()
   235  	mockStatsProvider := statstest.NewMockProvider(mockCtrl)
   236  
   237  	mockStatsProvider.EXPECT().ListPodStats(ctx).Return(podStats, nil).AnyTimes()
   238  	mockStatsProvider.EXPECT().ListPodStatsAndUpdateCPUNanoCoreUsage(ctx).Return(podStats, nil).AnyTimes()
   239  	if err := testutil.CustomCollectAndCompare(&volumeStatsCollector{statsProvider: mockStatsProvider}, strings.NewReader(want), metrics...); err != nil {
   240  		t.Errorf("unexpected collecting result:\n%s", err)
   241  	}
   242  }
   243  

View as plain text