k8s.io/kubernetes@v1.29.3/test/e2e/upgrades/auth/serviceaccount_admission_controller_migration.go (about) 1 /* 2 Copyright 2017 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 auth 18 19 import ( 20 "context" 21 "fmt" 22 "time" 23 24 "github.com/onsi/ginkgo/v2" 25 v1 "k8s.io/api/core/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/util/wait" 28 e2eauth "k8s.io/kubernetes/test/e2e/auth" 29 "k8s.io/kubernetes/test/e2e/framework" 30 e2epod "k8s.io/kubernetes/test/e2e/framework/pod" 31 "k8s.io/kubernetes/test/e2e/upgrades" 32 imageutils "k8s.io/kubernetes/test/utils/image" 33 ) 34 35 const ( 36 podBeforeMigrationName = "pod-before-migration" 37 podAfterMigrationName = "pod-after-migration" 38 ) 39 40 // ServiceAccountAdmissionControllerMigrationTest test that a pod is functioning before and after 41 // a cluster upgrade. 42 type ServiceAccountAdmissionControllerMigrationTest struct { 43 pod *v1.Pod 44 } 45 46 // Name returns the tracking name of the test. 47 func (ServiceAccountAdmissionControllerMigrationTest) Name() string { 48 return "[sig-auth] serviceaccount-admission-controller-migration" 49 } 50 51 // Setup creates pod-before-migration which has legacy service account token. 52 func (t *ServiceAccountAdmissionControllerMigrationTest) Setup(ctx context.Context, f *framework.Framework) { 53 t.pod = createPod(ctx, f, podBeforeMigrationName) 54 inClusterClientMustWork(ctx, f, t.pod) 55 } 56 57 // Test waits for the upgrade to complete, and then verifies pod-before-migration 58 // and pod-after-migration are able to make requests using in cluster config. 59 func (t *ServiceAccountAdmissionControllerMigrationTest) Test(ctx context.Context, f *framework.Framework, done <-chan struct{}, upgrade upgrades.UpgradeType) { 60 ginkgo.By("Waiting for upgrade to finish") 61 <-done 62 63 ginkgo.By("Starting post-upgrade check") 64 ginkgo.By("Checking pod-before-migration makes successful requests using in cluster config") 65 podBeforeMigration, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Get(ctx, podBeforeMigrationName, metav1.GetOptions{}) 66 framework.ExpectNoError(err) 67 if podBeforeMigration.GetUID() != t.pod.GetUID() { 68 framework.Failf("Pod %q GetUID() = %q, want %q.", podBeforeMigration.Name, podBeforeMigration.GetUID(), t.pod.GetUID()) 69 } 70 if podBeforeMigration.Status.ContainerStatuses[0].RestartCount != 0 { 71 framework.Failf("Pod %q RestartCount = %d, want 0.", podBeforeMigration.Name, podBeforeMigration.Status.ContainerStatuses[0].RestartCount) 72 } 73 inClusterClientMustWork(ctx, f, podBeforeMigration) 74 75 ginkgo.By("Checking pod-after-migration makes successful requests using in cluster config") 76 podAfterMigration := createPod(ctx, f, podAfterMigrationName) 77 if len(podAfterMigration.Spec.Volumes) != 1 || podAfterMigration.Spec.Volumes[0].Projected == nil { 78 framework.Failf("Pod %q Volumes[0].Projected.Sources = nil, want non-nil.", podAfterMigration.Name) 79 } 80 inClusterClientMustWork(ctx, f, podAfterMigration) 81 82 ginkgo.By("Finishing post-upgrade check") 83 } 84 85 // Teardown cleans up any remaining resources. 86 func (t *ServiceAccountAdmissionControllerMigrationTest) Teardown(ctx context.Context, f *framework.Framework) { 87 // rely on the namespace deletion to clean up everything 88 } 89 90 func inClusterClientMustWork(ctx context.Context, f *framework.Framework, pod *v1.Pod) { 91 var logs string 92 since := time.Now() 93 if err := wait.PollImmediate(15*time.Second, 5*time.Minute, func() (done bool, err error) { 94 framework.Logf("Polling logs") 95 logs, err = e2epod.GetPodLogsSince(ctx, f.ClientSet, pod.Namespace, pod.Name, "inclusterclient", since) 96 if err != nil { 97 framework.Logf("Error pulling logs: %v", err) 98 return false, nil 99 } 100 numTokens, err := e2eauth.ParseInClusterClientLogs(logs) 101 if err != nil { 102 framework.Logf("Error parsing inclusterclient logs: %v", err) 103 return false, fmt.Errorf("inclusterclient reported an error: %w", err) 104 } 105 if numTokens == 0 { 106 framework.Logf("No authenticated API calls found") 107 return false, nil 108 } 109 return true, nil 110 }); err != nil { 111 framework.Failf("Unexpected error: %v\n%s", err, logs) 112 } 113 } 114 115 // createPod creates a pod. 116 func createPod(ctx context.Context, f *framework.Framework, podName string) *v1.Pod { 117 pod := &v1.Pod{ 118 ObjectMeta: metav1.ObjectMeta{ 119 Name: podName, 120 Namespace: f.Namespace.Name, 121 }, 122 Spec: v1.PodSpec{ 123 Containers: []v1.Container{{ 124 Name: "inclusterclient", 125 Image: imageutils.GetE2EImage(imageutils.Agnhost), 126 Args: []string{"inclusterclient", "--poll-interval=5"}, 127 }}, 128 RestartPolicy: v1.RestartPolicyNever, 129 }, 130 } 131 132 createdPod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(ctx, pod, metav1.CreateOptions{}) 133 framework.ExpectNoError(err) 134 framework.Logf("Created pod %s", podName) 135 136 if !e2epod.CheckPodsRunningReady(ctx, f.ClientSet, f.Namespace.Name, []string{pod.Name}, time.Minute) { 137 framework.Failf("Pod %q/%q never became ready", createdPod.Namespace, createdPod.Name) 138 } 139 140 return createdPod 141 }