...

Source file src/k8s.io/kubernetes/pkg/kubelet/util/node_startup_latency_tracker_test.go

Documentation: k8s.io/kubernetes/pkg/kubelet/util

     1  /*
     2  Copyright 2023 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 util
    18  
    19  import (
    20  	"strings"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/stretchr/testify/assert"
    25  
    26  	"k8s.io/component-base/metrics/testutil"
    27  	"k8s.io/kubernetes/pkg/kubelet/metrics"
    28  	"k8s.io/utils/clock"
    29  	testingclock "k8s.io/utils/clock/testing"
    30  )
    31  
    32  const (
    33  	metricsNameNodeStartupPreKubelet       = "kubelet_node_startup_pre_kubelet_duration_seconds"
    34  	metricsNameNodeStartupPreRegistration  = "kubelet_node_startup_pre_registration_duration_seconds"
    35  	metricsNameNodeStartupRegistration     = "kubelet_node_startup_registration_duration_seconds"
    36  	metricsNameNodeStartupPostRegistration = "kubelet_node_startup_post_registration_duration_seconds"
    37  	metricsNameNodeStartup                 = "kubelet_node_startup_duration_seconds"
    38  )
    39  
    40  func TestNodeStartupLatencyNoEvents(t *testing.T) {
    41  	t.Run("metrics registered; no incoming events", func(t *testing.T) {
    42  		metrics.Register()
    43  		defer clearMetrics()
    44  
    45  		tracker := &basicNodeStartupLatencyTracker{
    46  			bootTime:         frozenTime.Add(-100 * time.Millisecond),
    47  			kubeletStartTime: frozenTime,
    48  			clock:            clock.RealClock{},
    49  		}
    50  
    51  		wants := `
    52  		# HELP kubelet_node_startup_duration_seconds [ALPHA] Duration in seconds of node startup in total.
    53          # TYPE kubelet_node_startup_duration_seconds gauge
    54          kubelet_node_startup_duration_seconds 0
    55          # HELP kubelet_node_startup_post_registration_duration_seconds [ALPHA] Duration in seconds of node startup after registration.
    56          # TYPE kubelet_node_startup_post_registration_duration_seconds gauge
    57          kubelet_node_startup_post_registration_duration_seconds 0
    58          # HELP kubelet_node_startup_pre_kubelet_duration_seconds [ALPHA] Duration in seconds of node startup before kubelet starts.
    59          # TYPE kubelet_node_startup_pre_kubelet_duration_seconds gauge
    60          kubelet_node_startup_pre_kubelet_duration_seconds 0
    61          # HELP kubelet_node_startup_pre_registration_duration_seconds [ALPHA] Duration in seconds of node startup before registration.
    62          # TYPE kubelet_node_startup_pre_registration_duration_seconds gauge
    63          kubelet_node_startup_pre_registration_duration_seconds 0
    64          # HELP kubelet_node_startup_registration_duration_seconds [ALPHA] Duration in seconds of node startup during registration.
    65          # TYPE kubelet_node_startup_registration_duration_seconds gauge
    66          kubelet_node_startup_registration_duration_seconds 0
    67  		`
    68  		if err := testutil.GatherAndCompare(metrics.GetGather(), strings.NewReader(wants),
    69  			metricsNameNodeStartupPreKubelet,
    70  			metricsNameNodeStartupPreRegistration,
    71  			metricsNameNodeStartupRegistration,
    72  			metricsNameNodeStartupPostRegistration,
    73  			metricsNameNodeStartup,
    74  		); err != nil {
    75  			t.Error(err)
    76  		}
    77  
    78  		assert.Equal(t, frozenTime.Add(-100*time.Millisecond), tracker.bootTime)
    79  		assert.Equal(t, frozenTime, tracker.kubeletStartTime)
    80  		assert.True(t, tracker.firstRegistrationAttemptTime.IsZero())
    81  		assert.True(t, tracker.firstRegisteredNewNodeTime.IsZero())
    82  		assert.True(t, tracker.firstNodeReadyTime.IsZero())
    83  	})
    84  }
    85  
    86  func TestRecordAllTimestamps(t *testing.T) {
    87  	t.Run("all timestamps are recorded", func(t *testing.T) {
    88  		metrics.Register()
    89  		defer clearMetrics()
    90  
    91  		fakeClock := testingclock.NewFakeClock(frozenTime)
    92  		tracker := &basicNodeStartupLatencyTracker{
    93  			bootTime:         frozenTime.Add(-100 * time.Millisecond),
    94  			kubeletStartTime: frozenTime,
    95  			clock:            fakeClock,
    96  		}
    97  
    98  		fakeClock.Step(800 * time.Millisecond)
    99  		tracker.RecordAttemptRegisterNode()
   100  
   101  		assert.Equal(t, frozenTime.Add(800*time.Millisecond), tracker.firstRegistrationAttemptTime)
   102  
   103  		fakeClock.Step(400 * time.Millisecond)
   104  		tracker.RecordRegisteredNewNode()
   105  
   106  		assert.Equal(t, frozenTime.Add(1200*time.Millisecond), tracker.firstRegisteredNewNodeTime)
   107  
   108  		fakeClock.Step(1100 * time.Millisecond)
   109  		tracker.RecordNodeReady()
   110  
   111  		assert.Equal(t, frozenTime.Add(2300*time.Millisecond), tracker.firstNodeReadyTime)
   112  
   113  		wants := `
   114  		# HELP kubelet_node_startup_duration_seconds [ALPHA] Duration in seconds of node startup in total.
   115          # TYPE kubelet_node_startup_duration_seconds gauge
   116          kubelet_node_startup_duration_seconds 2.4
   117          # HELP kubelet_node_startup_post_registration_duration_seconds [ALPHA] Duration in seconds of node startup after registration.
   118          # TYPE kubelet_node_startup_post_registration_duration_seconds gauge
   119          kubelet_node_startup_post_registration_duration_seconds 1.1
   120          # HELP kubelet_node_startup_pre_kubelet_duration_seconds [ALPHA] Duration in seconds of node startup before kubelet starts.
   121          # TYPE kubelet_node_startup_pre_kubelet_duration_seconds gauge
   122          kubelet_node_startup_pre_kubelet_duration_seconds 0.1
   123          # HELP kubelet_node_startup_pre_registration_duration_seconds [ALPHA] Duration in seconds of node startup before registration.
   124          # TYPE kubelet_node_startup_pre_registration_duration_seconds gauge
   125          kubelet_node_startup_pre_registration_duration_seconds 0.8
   126          # HELP kubelet_node_startup_registration_duration_seconds [ALPHA] Duration in seconds of node startup during registration.
   127          # TYPE kubelet_node_startup_registration_duration_seconds gauge
   128          kubelet_node_startup_registration_duration_seconds 0.4
   129  		`
   130  		if err := testutil.GatherAndCompare(metrics.GetGather(), strings.NewReader(wants),
   131  			metricsNameNodeStartupPreKubelet,
   132  			metricsNameNodeStartupPreRegistration,
   133  			metricsNameNodeStartupRegistration,
   134  			metricsNameNodeStartupPostRegistration,
   135  			metricsNameNodeStartup,
   136  		); err != nil {
   137  			t.Error(err)
   138  		}
   139  	})
   140  }
   141  
   142  func TestRecordAttemptRegister(t *testing.T) {
   143  	t.Run("record attempt register node", func(t *testing.T) {
   144  		metrics.Register()
   145  		defer clearMetrics()
   146  
   147  		fakeClock := testingclock.NewFakeClock(frozenTime)
   148  		tracker := &basicNodeStartupLatencyTracker{
   149  			bootTime:         frozenTime.Add(-100 * time.Millisecond),
   150  			kubeletStartTime: frozenTime,
   151  			clock:            fakeClock,
   152  		}
   153  
   154  		fakeClock.Step(600 * time.Millisecond)
   155  		tracker.RecordAttemptRegisterNode()
   156  
   157  		assert.Equal(t, frozenTime.Add(600*time.Millisecond), tracker.firstRegistrationAttemptTime)
   158  		assert.True(t, tracker.firstRegisteredNewNodeTime.IsZero())
   159  		assert.True(t, tracker.firstNodeReadyTime.IsZero())
   160  
   161  		wants := `
   162  		# HELP kubelet_node_startup_duration_seconds [ALPHA] Duration in seconds of node startup in total.
   163          # TYPE kubelet_node_startup_duration_seconds gauge
   164          kubelet_node_startup_duration_seconds 0
   165          # HELP kubelet_node_startup_post_registration_duration_seconds [ALPHA] Duration in seconds of node startup after registration.
   166          # TYPE kubelet_node_startup_post_registration_duration_seconds gauge
   167          kubelet_node_startup_post_registration_duration_seconds 0
   168          # HELP kubelet_node_startup_pre_kubelet_duration_seconds [ALPHA] Duration in seconds of node startup before kubelet starts.
   169          # TYPE kubelet_node_startup_pre_kubelet_duration_seconds gauge
   170          kubelet_node_startup_pre_kubelet_duration_seconds 0
   171          # HELP kubelet_node_startup_pre_registration_duration_seconds [ALPHA] Duration in seconds of node startup before registration.
   172          # TYPE kubelet_node_startup_pre_registration_duration_seconds gauge
   173          kubelet_node_startup_pre_registration_duration_seconds 0
   174          # HELP kubelet_node_startup_registration_duration_seconds [ALPHA] Duration in seconds of node startup during registration.
   175          # TYPE kubelet_node_startup_registration_duration_seconds gauge
   176          kubelet_node_startup_registration_duration_seconds 0
   177  				`
   178  		if err := testutil.GatherAndCompare(metrics.GetGather(), strings.NewReader(wants),
   179  			metricsNameNodeStartupPreKubelet,
   180  			metricsNameNodeStartupPreRegistration,
   181  			metricsNameNodeStartupRegistration,
   182  			metricsNameNodeStartupPostRegistration,
   183  			metricsNameNodeStartup,
   184  		); err != nil {
   185  			t.Error(err)
   186  		}
   187  	})
   188  }
   189  
   190  func TestRecordAttemptRegisterTwice(t *testing.T) {
   191  	t.Run("record attempt register node twice", func(t *testing.T) {
   192  		metrics.Register()
   193  		defer clearMetrics()
   194  
   195  		fakeClock := testingclock.NewFakeClock(frozenTime)
   196  		tracker := &basicNodeStartupLatencyTracker{
   197  			bootTime:         frozenTime.Add(-100 * time.Millisecond),
   198  			kubeletStartTime: frozenTime,
   199  			clock:            fakeClock,
   200  		}
   201  
   202  		fakeClock.Step(600 * time.Millisecond)
   203  		tracker.RecordAttemptRegisterNode()
   204  
   205  		fakeClock.Step(300 * time.Millisecond)
   206  		tracker.RecordAttemptRegisterNode()
   207  
   208  		assert.Equal(t, frozenTime.Add(600*time.Millisecond), tracker.firstRegistrationAttemptTime)
   209  		assert.True(t, tracker.firstRegisteredNewNodeTime.IsZero())
   210  		assert.True(t, tracker.firstNodeReadyTime.IsZero())
   211  	})
   212  }
   213  
   214  func TestSkippingRecordRegisteredNewNode(t *testing.T) {
   215  	t.Run("record register new node twice", func(t *testing.T) {
   216  		metrics.Register()
   217  		defer clearMetrics()
   218  
   219  		fakeClock := testingclock.NewFakeClock(frozenTime)
   220  		tracker := &basicNodeStartupLatencyTracker{
   221  			bootTime:         frozenTime.Add(-100 * time.Millisecond),
   222  			kubeletStartTime: frozenTime,
   223  			clock:            fakeClock,
   224  		}
   225  
   226  		fakeClock.Step(100 * time.Millisecond)
   227  		tracker.RecordAttemptRegisterNode()
   228  
   229  		fakeClock.Step(500 * time.Millisecond)
   230  		tracker.RecordRegisteredNewNode()
   231  
   232  		fakeClock.Step(300 * time.Millisecond)
   233  		tracker.RecordRegisteredNewNode()
   234  
   235  		assert.Equal(t, frozenTime.Add(600*time.Millisecond), tracker.firstRegisteredNewNodeTime)
   236  
   237  		wants := `
   238  		# HELP kubelet_node_startup_duration_seconds [ALPHA] Duration in seconds of node startup in total.
   239          # TYPE kubelet_node_startup_duration_seconds gauge
   240          kubelet_node_startup_duration_seconds 0
   241          # HELP kubelet_node_startup_post_registration_duration_seconds [ALPHA] Duration in seconds of node startup after registration.
   242          # TYPE kubelet_node_startup_post_registration_duration_seconds gauge
   243          kubelet_node_startup_post_registration_duration_seconds 0
   244          # HELP kubelet_node_startup_pre_kubelet_duration_seconds [ALPHA] Duration in seconds of node startup before kubelet starts.
   245          # TYPE kubelet_node_startup_pre_kubelet_duration_seconds gauge
   246          kubelet_node_startup_pre_kubelet_duration_seconds 0.1
   247          # HELP kubelet_node_startup_pre_registration_duration_seconds [ALPHA] Duration in seconds of node startup before registration.
   248          # TYPE kubelet_node_startup_pre_registration_duration_seconds gauge
   249          kubelet_node_startup_pre_registration_duration_seconds 0.1
   250          # HELP kubelet_node_startup_registration_duration_seconds [ALPHA] Duration in seconds of node startup during registration.
   251          # TYPE kubelet_node_startup_registration_duration_seconds gauge
   252          kubelet_node_startup_registration_duration_seconds 0.5
   253  		`
   254  		if err := testutil.GatherAndCompare(metrics.GetGather(), strings.NewReader(wants),
   255  			metricsNameNodeStartupPreKubelet,
   256  			metricsNameNodeStartupPreRegistration,
   257  			metricsNameNodeStartupRegistration,
   258  			metricsNameNodeStartupPostRegistration,
   259  			metricsNameNodeStartup,
   260  		); err != nil {
   261  			t.Error(err)
   262  		}
   263  	})
   264  
   265  	t.Run("record register new node without previous step", func(t *testing.T) {
   266  		metrics.Register()
   267  		defer clearMetrics()
   268  
   269  		fakeClock := testingclock.NewFakeClock(frozenTime)
   270  		tracker := &basicNodeStartupLatencyTracker{
   271  			bootTime:         frozenTime.Add(-100 * time.Millisecond),
   272  			kubeletStartTime: frozenTime,
   273  			clock:            fakeClock,
   274  		}
   275  
   276  		fakeClock.Step(700 * time.Millisecond)
   277  		tracker.RecordRegisteredNewNode()
   278  
   279  		assert.True(t, tracker.firstRegisteredNewNodeTime.IsZero())
   280  
   281  		wants := `
   282  		# HELP kubelet_node_startup_duration_seconds [ALPHA] Duration in seconds of node startup in total.
   283          # TYPE kubelet_node_startup_duration_seconds gauge
   284          kubelet_node_startup_duration_seconds 0
   285          # HELP kubelet_node_startup_post_registration_duration_seconds [ALPHA] Duration in seconds of node startup after registration.
   286          # TYPE kubelet_node_startup_post_registration_duration_seconds gauge
   287          kubelet_node_startup_post_registration_duration_seconds 0
   288          # HELP kubelet_node_startup_pre_kubelet_duration_seconds [ALPHA] Duration in seconds of node startup before kubelet starts.
   289          # TYPE kubelet_node_startup_pre_kubelet_duration_seconds gauge
   290          kubelet_node_startup_pre_kubelet_duration_seconds 0
   291          # HELP kubelet_node_startup_pre_registration_duration_seconds [ALPHA] Duration in seconds of node startup before registration.
   292          # TYPE kubelet_node_startup_pre_registration_duration_seconds gauge
   293          kubelet_node_startup_pre_registration_duration_seconds 0
   294          # HELP kubelet_node_startup_registration_duration_seconds [ALPHA] Duration in seconds of node startup during registration.
   295          # TYPE kubelet_node_startup_registration_duration_seconds gauge
   296          kubelet_node_startup_registration_duration_seconds 0
   297  		`
   298  		if err := testutil.GatherAndCompare(metrics.GetGather(), strings.NewReader(wants),
   299  			metricsNameNodeStartupPreKubelet,
   300  			metricsNameNodeStartupPreRegistration,
   301  			metricsNameNodeStartupRegistration,
   302  			metricsNameNodeStartupPostRegistration,
   303  			metricsNameNodeStartup,
   304  		); err != nil {
   305  			t.Error(err)
   306  		}
   307  	})
   308  }
   309  
   310  func TestSkippingRecordNodeReady(t *testing.T) {
   311  	t.Run("record node ready twice", func(t *testing.T) {
   312  		metrics.Register()
   313  		defer clearMetrics()
   314  
   315  		fakeClock := testingclock.NewFakeClock(frozenTime)
   316  		tracker := &basicNodeStartupLatencyTracker{
   317  			bootTime:         frozenTime.Add(-100 * time.Millisecond),
   318  			kubeletStartTime: frozenTime,
   319  			clock:            fakeClock,
   320  		}
   321  
   322  		fakeClock.Step(100 * time.Millisecond)
   323  		tracker.RecordAttemptRegisterNode()
   324  
   325  		fakeClock.Step(200 * time.Millisecond)
   326  		tracker.RecordRegisteredNewNode()
   327  
   328  		fakeClock.Step(300 * time.Millisecond)
   329  		tracker.RecordNodeReady()
   330  
   331  		fakeClock.Step(700 * time.Millisecond)
   332  		tracker.RecordNodeReady()
   333  
   334  		assert.Equal(t, frozenTime.Add(600*time.Millisecond), tracker.firstNodeReadyTime)
   335  
   336  		wants := `
   337  		# HELP kubelet_node_startup_duration_seconds [ALPHA] Duration in seconds of node startup in total.
   338          # TYPE kubelet_node_startup_duration_seconds gauge
   339          kubelet_node_startup_duration_seconds 0.7
   340          # HELP kubelet_node_startup_post_registration_duration_seconds [ALPHA] Duration in seconds of node startup after registration.
   341          # TYPE kubelet_node_startup_post_registration_duration_seconds gauge
   342          kubelet_node_startup_post_registration_duration_seconds 0.3
   343          # HELP kubelet_node_startup_pre_kubelet_duration_seconds [ALPHA] Duration in seconds of node startup before kubelet starts.
   344          # TYPE kubelet_node_startup_pre_kubelet_duration_seconds gauge
   345          kubelet_node_startup_pre_kubelet_duration_seconds 0.1
   346          # HELP kubelet_node_startup_pre_registration_duration_seconds [ALPHA] Duration in seconds of node startup before registration.
   347          # TYPE kubelet_node_startup_pre_registration_duration_seconds gauge
   348          kubelet_node_startup_pre_registration_duration_seconds 0.1
   349          # HELP kubelet_node_startup_registration_duration_seconds [ALPHA] Duration in seconds of node startup during registration.
   350          # TYPE kubelet_node_startup_registration_duration_seconds gauge
   351          kubelet_node_startup_registration_duration_seconds 0.2
   352  		`
   353  		if err := testutil.GatherAndCompare(metrics.GetGather(), strings.NewReader(wants),
   354  			metricsNameNodeStartupPreKubelet,
   355  			metricsNameNodeStartupPreRegistration,
   356  			metricsNameNodeStartupRegistration,
   357  			metricsNameNodeStartupPostRegistration,
   358  			metricsNameNodeStartup,
   359  		); err != nil {
   360  			t.Error(err)
   361  		}
   362  	})
   363  
   364  	t.Run("record node ready without previous step", func(t *testing.T) {
   365  		metrics.Register()
   366  		defer clearMetrics()
   367  
   368  		fakeClock := testingclock.NewFakeClock(frozenTime)
   369  		tracker := &basicNodeStartupLatencyTracker{
   370  			bootTime:         frozenTime.Add(-100 * time.Millisecond),
   371  			kubeletStartTime: frozenTime,
   372  			clock:            fakeClock,
   373  		}
   374  
   375  		fakeClock.Step(100 * time.Millisecond)
   376  		tracker.RecordAttemptRegisterNode()
   377  
   378  		fakeClock.Step(700 * time.Millisecond)
   379  		tracker.RecordNodeReady()
   380  
   381  		assert.True(t, tracker.firstNodeReadyTime.IsZero())
   382  
   383  		wants := `
   384  		# HELP kubelet_node_startup_duration_seconds [ALPHA] Duration in seconds of node startup in total.
   385          # TYPE kubelet_node_startup_duration_seconds gauge
   386          kubelet_node_startup_duration_seconds 0
   387          # HELP kubelet_node_startup_post_registration_duration_seconds [ALPHA] Duration in seconds of node startup after registration.
   388          # TYPE kubelet_node_startup_post_registration_duration_seconds gauge
   389          kubelet_node_startup_post_registration_duration_seconds 0
   390          # HELP kubelet_node_startup_pre_kubelet_duration_seconds [ALPHA] Duration in seconds of node startup before kubelet starts.
   391          # TYPE kubelet_node_startup_pre_kubelet_duration_seconds gauge
   392          kubelet_node_startup_pre_kubelet_duration_seconds 0
   393          # HELP kubelet_node_startup_pre_registration_duration_seconds [ALPHA] Duration in seconds of node startup before registration.
   394          # TYPE kubelet_node_startup_pre_registration_duration_seconds gauge
   395          kubelet_node_startup_pre_registration_duration_seconds 0
   396          # HELP kubelet_node_startup_registration_duration_seconds [ALPHA] Duration in seconds of node startup during registration.
   397          # TYPE kubelet_node_startup_registration_duration_seconds gauge
   398          kubelet_node_startup_registration_duration_seconds 0
   399  		`
   400  		if err := testutil.GatherAndCompare(metrics.GetGather(), strings.NewReader(wants),
   401  			metricsNameNodeStartupPreKubelet,
   402  			metricsNameNodeStartupPreRegistration,
   403  			metricsNameNodeStartupRegistration,
   404  			metricsNameNodeStartupPostRegistration,
   405  			metricsNameNodeStartup,
   406  		); err != nil {
   407  			t.Error(err)
   408  		}
   409  	})
   410  }
   411  
   412  func clearMetrics() {
   413  	metrics.NodeStartupPreKubeletDuration.Set(0)
   414  	metrics.NodeStartupPreRegistrationDuration.Set(0)
   415  	metrics.NodeStartupRegistrationDuration.Set(0)
   416  	metrics.NodeStartupPostRegistrationDuration.Set(0)
   417  	metrics.NodeStartupDuration.Set(0)
   418  }
   419  

View as plain text