mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Mirror pods for static pods may not be created immediately during node startup because either the node is not registered or node informer is not synced. They will be created eventually when static pods are resynced (every 1-1.5 minutes). However, during this delay of 1-1.5 mins, kube-scheduler might overcommit resources to the node and eventually cause kubelet to reject pods with OutOfCPU/OutOfMemory/OutOfPods error. To ensure kube-scheduler is aware of static pod resource usage faster, mirror pods are created as soon as the node registers.
		
			
				
	
	
		
			309 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			309 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2015 The Kubernetes Authors.
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
package pod
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"github.com/google/go-cmp/cmp"
 | 
						|
	"github.com/google/go-cmp/cmp/cmpopts"
 | 
						|
	"github.com/stretchr/testify/assert"
 | 
						|
 | 
						|
	v1 "k8s.io/api/core/v1"
 | 
						|
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						|
	"k8s.io/apimachinery/pkg/types"
 | 
						|
	kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	mirrorPodUID  = "mirror-pod-uid"
 | 
						|
	staticPodUID  = "static-pod-uid"
 | 
						|
	normalPodUID  = "normal-pod-uid"
 | 
						|
	mirrorPodName = "mirror-static-pod-name"
 | 
						|
	staticPodName = "mirror-static-pod-name"
 | 
						|
	normalPodName = "normal-pod-name"
 | 
						|
 | 
						|
	mirrorPod = &v1.Pod{
 | 
						|
		ObjectMeta: metav1.ObjectMeta{
 | 
						|
			UID:       types.UID(mirrorPodUID),
 | 
						|
			Name:      mirrorPodName,
 | 
						|
			Namespace: metav1.NamespaceDefault,
 | 
						|
			Annotations: map[string]string{
 | 
						|
				kubetypes.ConfigSourceAnnotationKey: "api",
 | 
						|
				kubetypes.ConfigMirrorAnnotationKey: "mirror",
 | 
						|
				kubetypes.ConfigHashAnnotationKey:   "mirror",
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	staticPod = &v1.Pod{
 | 
						|
		ObjectMeta: metav1.ObjectMeta{
 | 
						|
			UID:         types.UID(staticPodUID),
 | 
						|
			Name:        staticPodName,
 | 
						|
			Namespace:   metav1.NamespaceDefault,
 | 
						|
			Annotations: map[string]string{kubetypes.ConfigSourceAnnotationKey: "file"},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	normalPod = &v1.Pod{
 | 
						|
		ObjectMeta: metav1.ObjectMeta{
 | 
						|
			UID:         types.UID(normalPodUID),
 | 
						|
			Name:        normalPodName,
 | 
						|
			Namespace:   metav1.NamespaceDefault,
 | 
						|
			Annotations: map[string]string{},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	sortOpt = cmpopts.SortSlices(func(a, b *v1.Pod) bool { return a.Name < b.Name })
 | 
						|
)
 | 
						|
 | 
						|
func TestAddOrUpdatePod(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		name     string
 | 
						|
		isMirror bool
 | 
						|
		pod      *v1.Pod
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name:     "mirror pod",
 | 
						|
			pod:      mirrorPod,
 | 
						|
			isMirror: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:     "static pod",
 | 
						|
			pod:      staticPod,
 | 
						|
			isMirror: false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:     "normal pod",
 | 
						|
			pod:      normalPod,
 | 
						|
			isMirror: false,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, test := range tests {
 | 
						|
		t.Run(test.name, func(t *testing.T) {
 | 
						|
			pm := &basicManager{
 | 
						|
				podByUID:            make(map[kubetypes.ResolvedPodUID]*v1.Pod),
 | 
						|
				mirrorPodByUID:      make(map[kubetypes.MirrorPodUID]*v1.Pod),
 | 
						|
				podByFullName:       make(map[string]*v1.Pod),
 | 
						|
				mirrorPodByFullName: make(map[string]*v1.Pod),
 | 
						|
				translationByUID:    make(map[kubetypes.MirrorPodUID]kubetypes.ResolvedPodUID),
 | 
						|
			}
 | 
						|
			pm.AddPod(test.pod)
 | 
						|
			verify(t, pm, test.isMirror, test.pod)
 | 
						|
			test.pod.Annotations["testLabel"] = "updated"
 | 
						|
			pm.UpdatePod(test.pod)
 | 
						|
			verify(t, pm, test.isMirror, test.pod)
 | 
						|
		})
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
func verify(t *testing.T, pm *basicManager, isMirror bool, expectedPod *v1.Pod) {
 | 
						|
	fullName := fmt.Sprintf("%s_%s", expectedPod.Name, expectedPod.Namespace)
 | 
						|
	if isMirror {
 | 
						|
		inputPod, ok := pm.mirrorPodByUID[kubetypes.MirrorPodUID(expectedPod.UID)]
 | 
						|
		assert.True(t, ok)
 | 
						|
		assert.Empty(t, cmp.Diff(expectedPod, inputPod), "MirrorPodByUID map verification failed.")
 | 
						|
		inputPod, ok = pm.mirrorPodByFullName[fullName]
 | 
						|
		assert.True(t, ok)
 | 
						|
		assert.Empty(t, cmp.Diff(expectedPod, inputPod), "MirrorPodByFullName map verification failed.")
 | 
						|
	} else {
 | 
						|
		inputPod, ok := pm.podByUID[kubetypes.ResolvedPodUID(expectedPod.UID)]
 | 
						|
		assert.True(t, ok)
 | 
						|
		assert.Empty(t, cmp.Diff(expectedPod, inputPod), "PodByUID map verification failed.")
 | 
						|
		inputPod, ok = pm.podByFullName[fullName]
 | 
						|
		assert.True(t, ok)
 | 
						|
		assert.Empty(t, cmp.Diff(expectedPod, inputPod), "PodByFullName map verification failed.")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Tests that pods/maps are properly set after the pod update, and the basic
 | 
						|
// methods work correctly.
 | 
						|
func TestGetSetPods(t *testing.T) {
 | 
						|
	testCase := []struct {
 | 
						|
		name                 string
 | 
						|
		podList              []*v1.Pod
 | 
						|
		wantUID              types.UID
 | 
						|
		wantPod              *v1.Pod
 | 
						|
		isMirrorPod          bool
 | 
						|
		expectPods           []*v1.Pod
 | 
						|
		expectPod            *v1.Pod
 | 
						|
		expectedMirrorPod    *v1.Pod
 | 
						|
		expectUID            types.UID
 | 
						|
		expectPodToMirrorMap map[kubetypes.ResolvedPodUID]kubetypes.MirrorPodUID
 | 
						|
		expectMirrorToPodMap map[kubetypes.MirrorPodUID]kubetypes.ResolvedPodUID
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name:              "Get normal pod",
 | 
						|
			podList:           []*v1.Pod{mirrorPod, staticPod, normalPod},
 | 
						|
			wantUID:           types.UID("normal-pod-uid"),
 | 
						|
			wantPod:           normalPod,
 | 
						|
			isMirrorPod:       false,
 | 
						|
			expectedMirrorPod: nil,
 | 
						|
			expectPods:        []*v1.Pod{staticPod, normalPod},
 | 
						|
			expectPod:         normalPod,
 | 
						|
			expectUID:         types.UID("normal-pod-uid"),
 | 
						|
			expectPodToMirrorMap: map[kubetypes.ResolvedPodUID]kubetypes.MirrorPodUID{
 | 
						|
				kubetypes.ResolvedPodUID("static-pod-uid"): kubetypes.MirrorPodUID("mirror-pod-uid"),
 | 
						|
			},
 | 
						|
			expectMirrorToPodMap: map[kubetypes.MirrorPodUID]kubetypes.ResolvedPodUID{
 | 
						|
				kubetypes.MirrorPodUID("mirror-pod-uid"): kubetypes.ResolvedPodUID("static-pod-uid"),
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:              "Get static pod",
 | 
						|
			podList:           []*v1.Pod{mirrorPod, staticPod, normalPod},
 | 
						|
			wantUID:           types.UID("static-pod-uid"),
 | 
						|
			wantPod:           staticPod,
 | 
						|
			isMirrorPod:       false,
 | 
						|
			expectPods:        []*v1.Pod{staticPod, normalPod},
 | 
						|
			expectPod:         staticPod,
 | 
						|
			expectedMirrorPod: mirrorPod,
 | 
						|
			expectUID:         types.UID("static-pod-uid"),
 | 
						|
			expectPodToMirrorMap: map[kubetypes.ResolvedPodUID]kubetypes.MirrorPodUID{
 | 
						|
				kubetypes.ResolvedPodUID("static-pod-uid"): kubetypes.MirrorPodUID("mirror-pod-uid"),
 | 
						|
			},
 | 
						|
			expectMirrorToPodMap: map[kubetypes.MirrorPodUID]kubetypes.ResolvedPodUID{
 | 
						|
				kubetypes.MirrorPodUID("mirror-pod-uid"): kubetypes.ResolvedPodUID("static-pod-uid"),
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:              "Get mirror pod",
 | 
						|
			podList:           []*v1.Pod{mirrorPod, staticPod, normalPod},
 | 
						|
			wantUID:           types.UID("static-pod-uid"),
 | 
						|
			wantPod:           mirrorPod,
 | 
						|
			isMirrorPod:       true,
 | 
						|
			expectPods:        []*v1.Pod{staticPod, normalPod},
 | 
						|
			expectPod:         staticPod,
 | 
						|
			expectedMirrorPod: mirrorPod,
 | 
						|
			expectUID:         types.UID("static-pod-uid"),
 | 
						|
			expectPodToMirrorMap: map[kubetypes.ResolvedPodUID]kubetypes.MirrorPodUID{
 | 
						|
				kubetypes.ResolvedPodUID("static-pod-uid"): kubetypes.MirrorPodUID("mirror-pod-uid"),
 | 
						|
			},
 | 
						|
			expectMirrorToPodMap: map[kubetypes.MirrorPodUID]kubetypes.ResolvedPodUID{
 | 
						|
				kubetypes.MirrorPodUID("mirror-pod-uid"): kubetypes.ResolvedPodUID("static-pod-uid"),
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, test := range testCase {
 | 
						|
		t.Run(test.name, func(t *testing.T) {
 | 
						|
			podManager := NewBasicPodManager()
 | 
						|
			podManager.SetPods(test.podList)
 | 
						|
			actualPods := podManager.GetPods()
 | 
						|
			assert.Empty(t, cmp.Diff(test.expectPods, actualPods, sortOpt), "actualPods and expectPods differ")
 | 
						|
 | 
						|
			uid := podManager.TranslatePodUID(test.wantPod.UID)
 | 
						|
			assert.Equal(t, kubetypes.ResolvedPodUID(test.expectUID), uid, "unable to translate pod UID")
 | 
						|
 | 
						|
			fullName := fmt.Sprintf("%s_%s", test.wantPod.Name, test.wantPod.Namespace)
 | 
						|
			actualPod, ok := podManager.GetPodByFullName(fullName)
 | 
						|
			assert.True(t, ok)
 | 
						|
			assert.Empty(t, cmp.Diff(test.expectPod, actualPod), "actualPod by full name and expectGetPod differ")
 | 
						|
 | 
						|
			actualPod, ok = podManager.GetPodByName(test.wantPod.Namespace, test.wantPod.Name)
 | 
						|
			assert.True(t, ok)
 | 
						|
			assert.Empty(t, cmp.Diff(test.expectPod, actualPod), "actualPod by name and expectGetPod differ")
 | 
						|
 | 
						|
			actualPod, ok = podManager.GetPodByUID(test.wantUID)
 | 
						|
			assert.True(t, ok)
 | 
						|
			assert.Empty(t, cmp.Diff(test.expectPod, actualPod), "actualPod and expectGetPod differ")
 | 
						|
 | 
						|
			podToMirror, mirrorToPod := podManager.GetUIDTranslations()
 | 
						|
			assert.Empty(t, cmp.Diff(test.expectPodToMirrorMap, podToMirror), "podToMirror and expectPodToMirror differ")
 | 
						|
			assert.Empty(t, cmp.Diff(test.expectMirrorToPodMap, mirrorToPod), "mirrorToPod and expectMirrorToPod differ")
 | 
						|
 | 
						|
			actualPod, ok = podManager.GetMirrorPodByPod(test.wantPod)
 | 
						|
			assert.Equal(t, test.expectedMirrorPod != nil, ok)
 | 
						|
			assert.Empty(t, cmp.Diff(test.expectedMirrorPod, actualPod), "actualPod and expectShouldBeMirrorPod differ")
 | 
						|
 | 
						|
			actualPod, actualMirrorPod, isMirrorPod := podManager.GetPodAndMirrorPod(test.wantPod)
 | 
						|
			assert.Equal(t, test.isMirrorPod, isMirrorPod)
 | 
						|
			assert.Empty(t, cmp.Diff(test.expectPod, actualPod), "actualPod and expectGetPod differ")
 | 
						|
			assert.Empty(t, cmp.Diff(test.expectedMirrorPod, actualMirrorPod), "actualMirrorPod and shouldBeMirrorPod differ")
 | 
						|
 | 
						|
			isMirrorPod = IsMirrorPodOf(test.wantPod, mirrorPod)
 | 
						|
			assert.Equal(t, test.isMirrorPod, isMirrorPod)
 | 
						|
 | 
						|
			if test.isMirrorPod {
 | 
						|
				actualPod, ok = podManager.GetPodByMirrorPod(test.wantPod)
 | 
						|
				assert.Equal(t, test.expectedMirrorPod != nil, ok)
 | 
						|
				assert.Empty(t, cmp.Diff(test.expectPod, actualPod), "actualPod by name and expectGetPod differ")
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestRemovePods(t *testing.T) {
 | 
						|
	testCase := []struct {
 | 
						|
		name                             string
 | 
						|
		podList                          []*v1.Pod
 | 
						|
		needToRemovePod                  *v1.Pod
 | 
						|
		expectPods                       []*v1.Pod
 | 
						|
		expectMirrorPods                 []*v1.Pod
 | 
						|
		expectOrphanedMirrorPodFullnames []string
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name:             "Remove mirror pod",
 | 
						|
			podList:          []*v1.Pod{mirrorPod, staticPod, normalPod},
 | 
						|
			needToRemovePod:  mirrorPod,
 | 
						|
			expectPods:       []*v1.Pod{normalPod, staticPod},
 | 
						|
			expectMirrorPods: []*v1.Pod{},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:                             "Remove static pod",
 | 
						|
			podList:                          []*v1.Pod{mirrorPod, staticPod, normalPod},
 | 
						|
			needToRemovePod:                  staticPod,
 | 
						|
			expectPods:                       []*v1.Pod{normalPod},
 | 
						|
			expectMirrorPods:                 []*v1.Pod{mirrorPod},
 | 
						|
			expectOrphanedMirrorPodFullnames: []string{"mirror-static-pod-name_default"},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:             "Remove normal pod",
 | 
						|
			podList:          []*v1.Pod{mirrorPod, staticPod, normalPod},
 | 
						|
			needToRemovePod:  normalPod,
 | 
						|
			expectPods:       []*v1.Pod{staticPod},
 | 
						|
			expectMirrorPods: []*v1.Pod{mirrorPod},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, test := range testCase {
 | 
						|
		t.Run(test.name, func(t *testing.T) {
 | 
						|
			podManager := NewBasicPodManager()
 | 
						|
			podManager.SetPods(test.podList)
 | 
						|
			podManager.RemovePod(test.needToRemovePod)
 | 
						|
			actualPods1 := podManager.GetPods()
 | 
						|
			actualPods2, actualMirrorPods, orphanedMirrorPodFullnames := podManager.GetPodsAndMirrorPods()
 | 
						|
			// Check if the actual pods and mirror pods match the expected ones.
 | 
						|
			assert.Empty(t, cmp.Diff(actualPods1, actualPods2, sortOpt), "actualPods by GetPods() and GetPodsAndMirrorPods() differ")
 | 
						|
			assert.Empty(t, cmp.Diff(test.expectPods, actualPods1, sortOpt), "actualPods and expectPods differ")
 | 
						|
			assert.Empty(t, cmp.Diff(test.expectMirrorPods, actualMirrorPods, sortOpt), "actualMirrorPods and expectMirrorPods differ")
 | 
						|
			assert.Empty(t, cmp.Diff(test.expectOrphanedMirrorPodFullnames, orphanedMirrorPodFullnames), "orphanedMirrorPodFullnames and expectOrphanedMirrorPodFullnames differ")
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestGetStaticPodToMirrorPodMap(t *testing.T) {
 | 
						|
	podManager := NewBasicPodManager()
 | 
						|
	podManager.SetPods([]*v1.Pod{mirrorPod, staticPod, normalPod})
 | 
						|
	m := podManager.GetStaticPodToMirrorPodMap()
 | 
						|
	if len(m) != 1 {
 | 
						|
		t.Fatalf("GetStaticPodToMirrorPodMap(): got %d static pods, wanted 1 static pod", len(m))
 | 
						|
	}
 | 
						|
	if gotMirrorPod, ok := m[staticPod]; !ok || gotMirrorPod.UID != mirrorPod.UID {
 | 
						|
		t.Fatalf("GetStaticPodToMirrorPodMap() did not return the correct mirror pod UID %s, wanted mirror pod UID %s", gotMirrorPod.UID, mirrorPod.UID)
 | 
						|
	}
 | 
						|
}
 |