k8s.io/kubernetes@v1.29.3/pkg/kubelet/stats/cri_stats_provider_windows_test.go (about)

     1  /*
     2  Copyright 2021 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 stats
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/Microsoft/hcsshim"
    25  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
    27  	testingclock "k8s.io/utils/clock/testing"
    28  )
    29  
    30  type fakeNetworkStatsProvider struct {
    31  	containers []containerStats
    32  }
    33  
    34  type containerStats struct {
    35  	container hcsshim.ContainerProperties
    36  	hcsStats  []hcsshim.NetworkStats
    37  }
    38  
    39  func (s fakeNetworkStatsProvider) GetHNSEndpointStats(endpointName string) (*hcsshim.HNSEndpointStats, error) {
    40  	eps := hcsshim.HNSEndpointStats{}
    41  	for _, c := range s.containers {
    42  		for _, stat := range c.hcsStats {
    43  			if endpointName == stat.InstanceId {
    44  				eps = hcsshim.HNSEndpointStats{
    45  					EndpointID:      stat.EndpointId,
    46  					BytesSent:       stat.BytesSent,
    47  					BytesReceived:   stat.BytesReceived,
    48  					PacketsReceived: stat.PacketsReceived,
    49  					PacketsSent:     stat.PacketsSent,
    50  				}
    51  			}
    52  		}
    53  	}
    54  
    55  	return &eps, nil
    56  }
    57  
    58  func (s fakeNetworkStatsProvider) HNSListEndpointRequest() ([]hcsshim.HNSEndpoint, error) {
    59  	uniqueEndpoints := map[string]*hcsshim.HNSEndpoint{}
    60  
    61  	for _, c := range s.containers {
    62  		for _, stat := range c.hcsStats {
    63  			e, found := uniqueEndpoints[stat.EndpointId]
    64  			if found {
    65  				// add the container
    66  				e.SharedContainers = append(e.SharedContainers, c.container.ID)
    67  				continue
    68  			}
    69  
    70  			uniqueEndpoints[stat.EndpointId] = &hcsshim.HNSEndpoint{
    71  				Name:             stat.EndpointId,
    72  				Id:               stat.EndpointId,
    73  				SharedContainers: []string{c.container.ID},
    74  			}
    75  		}
    76  	}
    77  
    78  	eps := []hcsshim.HNSEndpoint{}
    79  	for _, ep := range uniqueEndpoints {
    80  		eps = append(eps, *ep)
    81  	}
    82  
    83  	return eps, nil
    84  }
    85  
    86  func Test_criStatsProvider_listContainerNetworkStats(t *testing.T) {
    87  	fakeClock := testingclock.NewFakeClock(time.Time{})
    88  	tests := []struct {
    89  		name    string
    90  		fields  fakeNetworkStatsProvider
    91  		want    map[string]*statsapi.NetworkStats
    92  		wantErr bool
    93  		skipped bool
    94  	}{
    95  		{
    96  			name: "basic example",
    97  			fields: fakeNetworkStatsProvider{
    98  				containers: []containerStats{
    99  					{
   100  						container: hcsshim.ContainerProperties{
   101  							ID: "c1",
   102  						}, hcsStats: []hcsshim.NetworkStats{
   103  							{
   104  								BytesReceived: 1,
   105  								BytesSent:     10,
   106  								EndpointId:    "test",
   107  								InstanceId:    "test",
   108  							},
   109  						},
   110  					},
   111  					{
   112  						container: hcsshim.ContainerProperties{
   113  							ID: "c2",
   114  						}, hcsStats: []hcsshim.NetworkStats{
   115  							{
   116  								BytesReceived: 2,
   117  								BytesSent:     20,
   118  								EndpointId:    "test2",
   119  								InstanceId:    "test2",
   120  							},
   121  						},
   122  					},
   123  				},
   124  			},
   125  			want: map[string]*statsapi.NetworkStats{
   126  				"c1": {
   127  					Time: v1.NewTime(fakeClock.Now()),
   128  					InterfaceStats: statsapi.InterfaceStats{
   129  						Name:    "test",
   130  						RxBytes: toP(1),
   131  						TxBytes: toP(10),
   132  					},
   133  					Interfaces: []statsapi.InterfaceStats{
   134  						{
   135  							Name:    "test",
   136  							RxBytes: toP(1),
   137  
   138  							TxBytes: toP(10),
   139  						},
   140  					},
   141  				},
   142  				"c2": {
   143  					Time: v1.Time{},
   144  					InterfaceStats: statsapi.InterfaceStats{
   145  						Name:    "test2",
   146  						RxBytes: toP(2),
   147  						TxBytes: toP(20),
   148  					},
   149  					Interfaces: []statsapi.InterfaceStats{
   150  						{
   151  							Name:    "test2",
   152  							RxBytes: toP(2),
   153  							TxBytes: toP(20),
   154  						},
   155  					},
   156  				},
   157  			},
   158  			wantErr: false,
   159  		},
   160  		{
   161  			name: "multiple containers same endpoint",
   162  			fields: fakeNetworkStatsProvider{
   163  				containers: []containerStats{
   164  					{
   165  						container: hcsshim.ContainerProperties{
   166  							ID: "c1",
   167  						}, hcsStats: []hcsshim.NetworkStats{
   168  							{
   169  								BytesReceived: 1,
   170  								BytesSent:     10,
   171  								EndpointId:    "test",
   172  								InstanceId:    "test",
   173  							},
   174  						},
   175  					},
   176  					{
   177  						container: hcsshim.ContainerProperties{
   178  							ID: "c2",
   179  						}, hcsStats: []hcsshim.NetworkStats{
   180  							{
   181  								BytesReceived: 2,
   182  								BytesSent:     20,
   183  								EndpointId:    "test2",
   184  								InstanceId:    "test2",
   185  							},
   186  						},
   187  					},
   188  					{
   189  						container: hcsshim.ContainerProperties{
   190  							ID: "c3",
   191  						}, hcsStats: []hcsshim.NetworkStats{
   192  							{
   193  								BytesReceived: 3,
   194  								BytesSent:     30,
   195  								EndpointId:    "test2",
   196  								InstanceId:    "test3",
   197  							},
   198  						},
   199  					},
   200  				},
   201  			},
   202  			want: map[string]*statsapi.NetworkStats{
   203  				"c1": {
   204  					Time: v1.NewTime(fakeClock.Now()),
   205  					InterfaceStats: statsapi.InterfaceStats{
   206  						Name:    "test",
   207  						RxBytes: toP(1),
   208  						TxBytes: toP(10),
   209  					},
   210  					Interfaces: []statsapi.InterfaceStats{
   211  						{
   212  							Name:    "test",
   213  							RxBytes: toP(1),
   214  
   215  							TxBytes: toP(10),
   216  						},
   217  					},
   218  				},
   219  				"c2": {
   220  					Time: v1.Time{},
   221  					InterfaceStats: statsapi.InterfaceStats{
   222  						Name:    "test2",
   223  						RxBytes: toP(2),
   224  						TxBytes: toP(20),
   225  					},
   226  					Interfaces: []statsapi.InterfaceStats{
   227  						{
   228  							Name:    "test2",
   229  							RxBytes: toP(2),
   230  							TxBytes: toP(20),
   231  						},
   232  					},
   233  				},
   234  				"c3": {
   235  					Time: v1.Time{},
   236  					InterfaceStats: statsapi.InterfaceStats{
   237  						Name:    "test2",
   238  						RxBytes: toP(2),
   239  						TxBytes: toP(20),
   240  					},
   241  					Interfaces: []statsapi.InterfaceStats{
   242  						{
   243  							Name:    "test2",
   244  							RxBytes: toP(2),
   245  							TxBytes: toP(20),
   246  						},
   247  					},
   248  				},
   249  			},
   250  			wantErr: false,
   251  		},
   252  		{
   253  			name: "multiple stats instances of same interface only picks up first",
   254  			fields: fakeNetworkStatsProvider{
   255  				containers: []containerStats{
   256  					{
   257  						container: hcsshim.ContainerProperties{
   258  							ID: "c1",
   259  						}, hcsStats: []hcsshim.NetworkStats{
   260  							{
   261  								BytesReceived: 1,
   262  								BytesSent:     10,
   263  								EndpointId:    "test",
   264  								InstanceId:    "test",
   265  							},
   266  							{
   267  								BytesReceived: 3,
   268  								BytesSent:     30,
   269  								EndpointId:    "test",
   270  								InstanceId:    "test3",
   271  							},
   272  						},
   273  					},
   274  					{
   275  						container: hcsshim.ContainerProperties{
   276  							ID: "c2",
   277  						}, hcsStats: []hcsshim.NetworkStats{
   278  							{
   279  								BytesReceived: 2,
   280  								BytesSent:     20,
   281  								EndpointId:    "test2",
   282  								InstanceId:    "test2",
   283  							},
   284  						},
   285  					},
   286  				},
   287  			},
   288  			want: map[string]*statsapi.NetworkStats{
   289  				"c1": {
   290  					Time: v1.NewTime(fakeClock.Now()),
   291  					InterfaceStats: statsapi.InterfaceStats{
   292  						Name:    "test",
   293  						RxBytes: toP(1),
   294  						TxBytes: toP(10),
   295  					},
   296  					Interfaces: []statsapi.InterfaceStats{
   297  						{
   298  							Name:    "test",
   299  							RxBytes: toP(1),
   300  
   301  							TxBytes: toP(10),
   302  						},
   303  					},
   304  				},
   305  				"c2": {
   306  					Time: v1.Time{},
   307  					InterfaceStats: statsapi.InterfaceStats{
   308  						Name:    "test2",
   309  						RxBytes: toP(2),
   310  						TxBytes: toP(20),
   311  					},
   312  					Interfaces: []statsapi.InterfaceStats{
   313  						{
   314  							Name:    "test2",
   315  							RxBytes: toP(2),
   316  							TxBytes: toP(20),
   317  						},
   318  					},
   319  				},
   320  			},
   321  			wantErr: false,
   322  		},
   323  		{
   324  			name: "multiple endpoints per container",
   325  			fields: fakeNetworkStatsProvider{
   326  				containers: []containerStats{
   327  					{
   328  						container: hcsshim.ContainerProperties{
   329  							ID: "c1",
   330  						}, hcsStats: []hcsshim.NetworkStats{
   331  							{
   332  								BytesReceived: 1,
   333  								BytesSent:     10,
   334  								EndpointId:    "test",
   335  								InstanceId:    "test",
   336  							},
   337  							{
   338  								BytesReceived: 3,
   339  								BytesSent:     30,
   340  								EndpointId:    "test3",
   341  								InstanceId:    "test3",
   342  							},
   343  						},
   344  					},
   345  					{
   346  						container: hcsshim.ContainerProperties{
   347  							ID: "c2",
   348  						}, hcsStats: []hcsshim.NetworkStats{
   349  							{
   350  								BytesReceived: 2,
   351  								BytesSent:     20,
   352  								EndpointId:    "test2",
   353  								InstanceId:    "test2",
   354  							},
   355  						},
   356  					},
   357  				},
   358  			},
   359  			want: map[string]*statsapi.NetworkStats{
   360  				"c1": {
   361  					Time: v1.NewTime(fakeClock.Now()),
   362  					InterfaceStats: statsapi.InterfaceStats{
   363  						Name:    "test",
   364  						RxBytes: toP(1),
   365  						TxBytes: toP(10),
   366  					},
   367  					Interfaces: []statsapi.InterfaceStats{
   368  						{
   369  							Name:    "test",
   370  							RxBytes: toP(1),
   371  
   372  							TxBytes: toP(10),
   373  						},
   374  						{
   375  							Name:    "test3",
   376  							RxBytes: toP(3),
   377  
   378  							TxBytes: toP(30),
   379  						},
   380  					},
   381  				},
   382  				"c2": {
   383  					Time: v1.Time{},
   384  					InterfaceStats: statsapi.InterfaceStats{
   385  						Name:    "test2",
   386  						RxBytes: toP(2),
   387  						TxBytes: toP(20),
   388  					},
   389  					Interfaces: []statsapi.InterfaceStats{
   390  						{
   391  							Name:    "test2",
   392  							RxBytes: toP(2),
   393  							TxBytes: toP(20),
   394  						},
   395  					},
   396  				},
   397  			},
   398  			wantErr: false,
   399  			skipped: true,
   400  		},
   401  	}
   402  	for _, tt := range tests {
   403  		t.Run(tt.name, func(t *testing.T) {
   404  			// TODO: Remove skip once https://github.com/kubernetes/kubernetes/issues/116692 is fixed.
   405  			if tt.skipped {
   406  				t.Skip("Test temporarily skipped.")
   407  			}
   408  			p := &criStatsProvider{
   409  				windowsNetworkStatsProvider: fakeNetworkStatsProvider{
   410  					containers: tt.fields.containers,
   411  				},
   412  				clock: fakeClock,
   413  			}
   414  			got, err := p.listContainerNetworkStats()
   415  			if (err != nil) != tt.wantErr {
   416  				t.Errorf("listContainerNetworkStats() error = %v, wantErr %v", err, tt.wantErr)
   417  				return
   418  			}
   419  			if !reflect.DeepEqual(got, tt.want) {
   420  				t.Errorf("listContainerNetworkStats() got = %v, want %v", got, tt.want)
   421  			}
   422  		})
   423  	}
   424  }
   425  
   426  func toP(i uint64) *uint64 {
   427  	return &i
   428  }