k8s.io/kubernetes@v1.29.3/pkg/kubelet/pleg/evented_test.go (about) 1 /* 2 Copyright 2015 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 pleg 18 19 import ( 20 "fmt" 21 "reflect" 22 "strings" 23 "testing" 24 "time" 25 26 "github.com/stretchr/testify/assert" 27 "github.com/stretchr/testify/require" 28 29 "k8s.io/apimachinery/pkg/types" 30 "k8s.io/component-base/metrics/testutil" 31 v1 "k8s.io/cri-api/pkg/apis/runtime/v1" 32 critest "k8s.io/cri-api/pkg/apis/testing" 33 kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" 34 containertest "k8s.io/kubernetes/pkg/kubelet/container/testing" 35 "k8s.io/kubernetes/pkg/kubelet/metrics" 36 testingclock "k8s.io/utils/clock/testing" 37 ) 38 39 func newTestEventedPLEG() *EventedPLEG { 40 return &EventedPLEG{ 41 runtime: &containertest.FakeRuntime{}, 42 clock: testingclock.NewFakeClock(time.Time{}), 43 cache: kubecontainer.NewCache(), 44 runtimeService: critest.NewFakeRuntimeService(), 45 eventChannel: make(chan *PodLifecycleEvent, 100), 46 } 47 } 48 49 func TestHealthyEventedPLEG(t *testing.T) { 50 metrics.Register() 51 pleg := newTestEventedPLEG() 52 53 _, _, events := createTestPodsStatusesAndEvents(100) 54 for _, event := range events[:5] { 55 pleg.eventChannel <- event 56 } 57 58 // test if healthy when event channel has 5 events 59 isHealthy, err := pleg.Healthy() 60 require.NoError(t, err) 61 assert.Equal(t, true, isHealthy) 62 63 // send remaining 95 events and make channel out of capacity 64 for _, event := range events[5:] { 65 pleg.eventChannel <- event 66 } 67 // pleg is unhealthy when channel is out of capacity 68 isHealthy, err = pleg.Healthy() 69 require.Error(t, err) 70 assert.Equal(t, false, isHealthy) 71 } 72 73 func TestUpdateRunningPodMetric(t *testing.T) { 74 metrics.Register() 75 pleg := newTestEventedPLEG() 76 77 podStatuses := make([]*kubecontainer.PodStatus, 5) 78 for i := range podStatuses { 79 id := fmt.Sprintf("test-pod-%d", i) 80 podStatuses[i] = &kubecontainer.PodStatus{ 81 ID: types.UID(id), 82 SandboxStatuses: []*v1.PodSandboxStatus{ 83 {Id: id}, 84 }, 85 ContainerStatuses: []*kubecontainer.Status{ 86 {ID: kubecontainer.ContainerID{ID: id}, State: kubecontainer.ContainerStateRunning}, 87 }, 88 } 89 90 pleg.updateRunningPodMetric(podStatuses[i]) 91 pleg.cache.Set(podStatuses[i].ID, podStatuses[i], nil, time.Now()) 92 93 } 94 pleg.cache.UpdateTime(time.Now()) 95 96 expectedMetric := ` 97 # HELP kubelet_running_pods [ALPHA] Number of pods that have a running pod sandbox 98 # TYPE kubelet_running_pods gauge 99 kubelet_running_pods 5 100 ` 101 testMetric(t, expectedMetric, metrics.RunningPodCount.FQName()) 102 103 // stop sandbox containers for first 2 pods 104 for _, podStatus := range podStatuses[:2] { 105 podId := string(podStatus.ID) 106 newPodStatus := kubecontainer.PodStatus{ 107 ID: podStatus.ID, 108 SandboxStatuses: []*v1.PodSandboxStatus{ 109 {Id: podId}, 110 }, 111 ContainerStatuses: []*kubecontainer.Status{ 112 // update state to container exited 113 {ID: kubecontainer.ContainerID{ID: podId}, State: kubecontainer.ContainerStateExited}, 114 }, 115 } 116 117 pleg.updateRunningPodMetric(&newPodStatus) 118 pleg.cache.Set(newPodStatus.ID, &newPodStatus, nil, time.Now()) 119 } 120 pleg.cache.UpdateTime(time.Now()) 121 122 expectedMetric = ` 123 # HELP kubelet_running_pods [ALPHA] Number of pods that have a running pod sandbox 124 # TYPE kubelet_running_pods gauge 125 kubelet_running_pods 3 126 ` 127 testMetric(t, expectedMetric, metrics.RunningPodCount.FQName()) 128 } 129 130 func testMetric(t *testing.T, expectedMetric string, metricName string) { 131 err := testutil.GatherAndCompare(metrics.GetGather(), strings.NewReader(expectedMetric), metricName) 132 if err != nil { 133 t.Fatal(err) 134 } 135 } 136 137 func TestEventedPLEG_getPodIPs(t *testing.T) { 138 cache := kubecontainer.NewCache() 139 type args struct { 140 pid types.UID 141 status *kubecontainer.PodStatus 142 } 143 tests := []struct { 144 name string 145 args args 146 oldstatus *kubecontainer.PodStatus 147 expected []string 148 }{ 149 { 150 name: "status ips is not empty", 151 args: args{ 152 pid: "62212", 153 status: &kubecontainer.PodStatus{ 154 IPs: []string{"10.0.0.10", "10.23.0.1"}, 155 }, 156 }, 157 oldstatus: &kubecontainer.PodStatus{ 158 IPs: []string{"192.168.0.10", "192.168.0.1"}, 159 }, 160 expected: []string{"10.0.0.10", "10.23.0.1"}, 161 }, 162 { 163 name: "status ips is empty and SandboxStatuses has PodSandboxState_SANDBOX_READY state", 164 args: args{ 165 pid: "62212", 166 status: &kubecontainer.PodStatus{ 167 SandboxStatuses: []*v1.PodSandboxStatus{ 168 { 169 Id: "sandboxID2", 170 Metadata: &v1.PodSandboxMetadata{Attempt: uint32(1)}, 171 State: v1.PodSandboxState_SANDBOX_READY, 172 }, 173 { 174 Id: "sandboxID1", 175 Metadata: &v1.PodSandboxMetadata{Attempt: uint32(0)}, 176 State: v1.PodSandboxState_SANDBOX_NOTREADY, 177 }, 178 }, 179 }, 180 }, 181 oldstatus: &kubecontainer.PodStatus{ 182 IPs: []string{"192.168.0.10", "192.168.0.1"}, 183 }, 184 expected: nil, 185 }, 186 { 187 name: "status and cache ips are empty", 188 args: args{ 189 pid: "62212", 190 status: &kubecontainer.PodStatus{}, 191 }, 192 oldstatus: &kubecontainer.PodStatus{ 193 IPs: []string{}, 194 }, 195 expected: nil, 196 }, 197 { 198 name: "sandbox state is no PodSandboxState_SANDBOX_READY", 199 args: args{ 200 pid: "62212", 201 status: &kubecontainer.PodStatus{ 202 SandboxStatuses: []*v1.PodSandboxStatus{ 203 { 204 Id: "sandboxID2", 205 Metadata: &v1.PodSandboxMetadata{Attempt: uint32(1)}, 206 State: v1.PodSandboxState_SANDBOX_NOTREADY, 207 }, 208 { 209 Id: "sandboxID1", 210 Metadata: &v1.PodSandboxMetadata{Attempt: uint32(0)}, 211 State: v1.PodSandboxState_SANDBOX_NOTREADY, 212 }, 213 }, 214 }, 215 }, 216 oldstatus: &kubecontainer.PodStatus{ 217 IPs: []string{"192.168.0.10", "192.168.0.1"}, 218 }, 219 expected: []string{"192.168.0.10", "192.168.0.1"}, 220 }, 221 } 222 for _, test := range tests { 223 cache.Set(test.args.pid, test.oldstatus, nil, time.Time{}) 224 e := &EventedPLEG{ 225 cache: cache, 226 } 227 t.Run(test.name, func(t *testing.T) { 228 if got := e.getPodIPs(test.args.pid, test.args.status); !reflect.DeepEqual(got, test.expected) { 229 t.Errorf("EventedPLEG.getPodIPs() = %v, expected %v", got, test.expected) 230 } 231 }) 232 } 233 }