...

Source file src/k8s.io/kubernetes/pkg/volume/csi/csi_metrics_test.go

Documentation: k8s.io/kubernetes/pkg/volume/csi

     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 csi
    18  
    19  import (
    20  	"io"
    21  	"reflect"
    22  	"testing"
    23  
    24  	csipbv1 "github.com/container-storage-interface/spec/lib/go/csi"
    25  	"k8s.io/apimachinery/pkg/api/resource"
    26  	"k8s.io/kubernetes/pkg/volume"
    27  	"k8s.io/kubernetes/pkg/volume/csi/fake"
    28  	volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
    29  )
    30  
    31  func TestGetMetrics(t *testing.T) {
    32  	tests := []struct {
    33  		name          string
    34  		volumeID      string
    35  		targetPath    string
    36  		expectSuccess bool
    37  	}{
    38  		{
    39  			name:          "with valid name and volume id",
    40  			expectSuccess: true,
    41  			volumeID:      "foobar",
    42  			targetPath:    "/mnt/foo",
    43  		},
    44  	}
    45  
    46  	for _, tc := range tests {
    47  		metricsGetter := &metricsCsi{volumeID: tc.volumeID, targetPath: tc.targetPath}
    48  		metricsGetter.csiClient = &csiDriverClient{
    49  			driverName: "com.google.gcepd",
    50  			nodeV1ClientCreator: func(addr csiAddr, m *MetricsManager) (csipbv1.NodeClient, io.Closer, error) {
    51  				nodeClient := fake.NewNodeClientWithVolumeStats(true /* VolumeStatsCapable */)
    52  				fakeCloser := fake.NewCloser(t)
    53  				nodeClient.SetNodeVolumeStatsResp(getRawVolumeInfo())
    54  				return nodeClient, fakeCloser, nil
    55  			},
    56  		}
    57  		metrics, err := metricsGetter.GetMetrics()
    58  		if err != nil {
    59  			t.Fatalf("for %s: unexpected error : %v", tc.name, err)
    60  		}
    61  		if metrics == nil {
    62  			t.Fatalf("unexpected nil metrics")
    63  		}
    64  		expectedMetrics := getRawVolumeInfo()
    65  		for _, usage := range expectedMetrics.Usage {
    66  			if usage.Unit == csipbv1.VolumeUsage_BYTES {
    67  				availableBytes := resource.NewQuantity(usage.Available, resource.BinarySI)
    68  				totalBytes := resource.NewQuantity(usage.Total, resource.BinarySI)
    69  				usedBytes := resource.NewQuantity(usage.Used, resource.BinarySI)
    70  				if metrics.Available.Cmp(*availableBytes) != 0 {
    71  					t.Fatalf("for %s: error: expected :%v , got: %v", tc.name, *availableBytes, *(metrics.Available))
    72  				}
    73  				if metrics.Capacity.Cmp(*totalBytes) != 0 {
    74  					t.Fatalf("for %s: error: expected :%v , got: %v", tc.name, *totalBytes, *(metrics.Capacity))
    75  				}
    76  				if metrics.Used.Cmp(*usedBytes) != 0 {
    77  					t.Fatalf("for %s: error: expected :%v , got: %v", tc.name, *usedBytes, *(metrics.Used))
    78  				}
    79  			}
    80  
    81  			if usage.Unit == csipbv1.VolumeUsage_INODES {
    82  				freeInodes := resource.NewQuantity(usage.Available, resource.BinarySI)
    83  				inodes := resource.NewQuantity(usage.Total, resource.BinarySI)
    84  				usedInodes := resource.NewQuantity(usage.Used, resource.BinarySI)
    85  				if metrics.InodesFree.Cmp(*freeInodes) != 0 {
    86  					t.Fatalf("for %s: error: expected :%v , got: %v", tc.name, *freeInodes, *(metrics.InodesFree))
    87  				}
    88  				if metrics.Inodes.Cmp(*inodes) != 0 {
    89  					t.Fatalf("for %s: error: expected :%v , got: %v", tc.name, *inodes, *(metrics.Inodes))
    90  				}
    91  				if metrics.InodesUsed.Cmp(*usedInodes) != 0 {
    92  					t.Fatalf("for %s: error: expected :%v , got: %v", tc.name, *usedInodes, *(metrics.InodesUsed))
    93  				}
    94  			}
    95  		}
    96  	}
    97  }
    98  
    99  // test GetMetrics with a volume that does not support stats
   100  func TestGetMetricsDriverNotSupportStats(t *testing.T) {
   101  	tests := []struct {
   102  		name          string
   103  		volumeID      string
   104  		targetPath    string
   105  		expectSuccess bool
   106  	}{
   107  		{
   108  			name:          "volume created by simple driver",
   109  			expectSuccess: true,
   110  			volumeID:      "foobar",
   111  			targetPath:    "/mnt/foo",
   112  		},
   113  	}
   114  
   115  	for _, tc := range tests {
   116  		metricsGetter := &metricsCsi{volumeID: tc.volumeID, targetPath: tc.targetPath}
   117  		metricsGetter.csiClient = &csiDriverClient{
   118  			driverName: "com.simple.SimpleDriver",
   119  			nodeV1ClientCreator: func(addr csiAddr, m *MetricsManager) (csipbv1.NodeClient, io.Closer, error) {
   120  				nodeClient := fake.NewNodeClientWithVolumeStats(false /* VolumeStatsCapable */)
   121  				fakeCloser := fake.NewCloser(t)
   122  				nodeClient.SetNodeVolumeStatsResp(getRawVolumeInfo())
   123  				return nodeClient, fakeCloser, nil
   124  			},
   125  		}
   126  		metrics, err := metricsGetter.GetMetrics()
   127  		if err == nil {
   128  			t.Fatalf("for %s: expected error, but got nil error", tc.name)
   129  		}
   130  
   131  		if !volume.IsNotSupported(err) {
   132  			t.Fatalf("for %s, expected not supported error but got: %v", tc.name, err)
   133  		}
   134  
   135  		if metrics != nil {
   136  			t.Fatalf("for %s, expected nil metrics, but got: %v", tc.name, metrics)
   137  		}
   138  	}
   139  
   140  }
   141  
   142  // test GetMetrics with a volume that does not support stats
   143  func TestGetMetricsDriverNotFound(t *testing.T) {
   144  	transientError := volumetypes.NewTransientOperationFailure("")
   145  	tests := []struct {
   146  		name       string
   147  		volumeID   string
   148  		targetPath string
   149  		exitError  error
   150  	}{
   151  		{
   152  			name:       "volume with no driver",
   153  			volumeID:   "foobar",
   154  			targetPath: "/mnt/foo",
   155  			exitError:  transientError,
   156  		},
   157  	}
   158  
   159  	for _, tc := range tests {
   160  		metricsGetter := &metricsCsi{volumeID: tc.volumeID, targetPath: tc.targetPath}
   161  		metricsGetter.driverName = "unknown-driver"
   162  		_, err := metricsGetter.GetMetrics()
   163  		if err == nil {
   164  			t.Errorf("test should fail, but no error occurred")
   165  		} else if reflect.TypeOf(tc.exitError) != reflect.TypeOf(err) {
   166  			t.Fatalf("expected exitError type: %v got: %v (%v)", reflect.TypeOf(transientError), reflect.TypeOf(err), err)
   167  		}
   168  	}
   169  
   170  }
   171  
   172  func getRawVolumeInfo() *csipbv1.NodeGetVolumeStatsResponse {
   173  	return &csipbv1.NodeGetVolumeStatsResponse{
   174  		Usage: []*csipbv1.VolumeUsage{
   175  			{
   176  				Available: int64(10),
   177  				Total:     int64(10),
   178  				Used:      int64(2),
   179  				Unit:      csipbv1.VolumeUsage_BYTES,
   180  			},
   181  			{
   182  				Available: int64(100),
   183  				Total:     int64(100),
   184  				Used:      int64(20),
   185  				Unit:      csipbv1.VolumeUsage_INODES,
   186  			},
   187  		},
   188  	}
   189  }
   190  

View as plain text