Skip to content

Commit 2603cc1

Browse files
authored
Merge pull request kubernetes#94835 from zshihang/upgrade
upgrade test for BoundServiceAccountTokenVolume
2 parents 1ebf64d + 637235e commit 2603cc1

File tree

5 files changed

+204
-22
lines changed

5 files changed

+204
-22
lines changed

test/e2e/auth/service_accounts.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ var _ = SIGDescribe("ServiceAccounts", func() {
631631
framework.Logf("Error pulling logs: %v", err)
632632
return false, nil
633633
}
634-
tokenCount, err := parseInClusterClientLogs(logs)
634+
tokenCount, err := ParseInClusterClientLogs(logs)
635635
if err != nil {
636636
return false, fmt.Errorf("inclusterclient reported an error: %v", err)
637637
}
@@ -832,7 +832,8 @@ var _ = SIGDescribe("ServiceAccounts", func() {
832832

833833
var reportLogsParser = regexp.MustCompile("([a-zA-Z0-9-_]*)=([a-zA-Z0-9-_]*)$")
834834

835-
func parseInClusterClientLogs(logs string) (int, error) {
835+
// ParseInClusterClientLogs parses logs of pods using inclusterclient.
836+
func ParseInClusterClientLogs(logs string) (int, error) {
836837
seenTokens := map[string]struct{}{}
837838

838839
lines := strings.Split(logs, "\n")

test/e2e/cloud/gcp/cluster_upgrade.go

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,15 @@ var kubeProxyDowngradeTests = []upgrades.Test{
8989
&upgrades.ServiceUpgradeTest{},
9090
}
9191

92+
var serviceaccountAdmissionControllerMigrationTests = []upgrades.Test{
93+
&upgrades.ServiceAccountAdmissionControllerMigrationTest{},
94+
}
95+
9296
// masterUpgrade upgrades master node on GCE/GKE.
93-
func masterUpgrade(f *framework.Framework, v string) error {
97+
func masterUpgrade(f *framework.Framework, v string, extraEnvs []string) error {
9498
switch framework.TestContext.Provider {
9599
case "gce":
96-
return masterUpgradeGCE(v, false)
100+
return masterUpgradeGCE(v, extraEnvs)
97101
case "gke":
98102
return framework.MasterUpgradeGKE(f.Namespace.Name, v)
99103
default:
@@ -104,12 +108,11 @@ func masterUpgrade(f *framework.Framework, v string) error {
104108
// masterUpgradeGCEWithKubeProxyDaemonSet upgrades master node on GCE with enabling/disabling the daemon set of kube-proxy.
105109
// TODO(mrhohn): Remove this function when kube-proxy is run as a DaemonSet by default.
106110
func masterUpgradeGCEWithKubeProxyDaemonSet(v string, enableKubeProxyDaemonSet bool) error {
107-
return masterUpgradeGCE(v, enableKubeProxyDaemonSet)
111+
return masterUpgradeGCE(v, []string{fmt.Sprintf("KUBE_PROXY_DAEMONSET=%v", enableKubeProxyDaemonSet)})
108112
}
109113

110-
// TODO(mrhohn): Remove 'enableKubeProxyDaemonSet' when kube-proxy is run as a DaemonSet by default.
111-
func masterUpgradeGCE(rawV string, enableKubeProxyDaemonSet bool) error {
112-
env := append(os.Environ(), fmt.Sprintf("KUBE_PROXY_DAEMONSET=%v", enableKubeProxyDaemonSet))
114+
func masterUpgradeGCE(rawV string, extraEnvs []string) error {
115+
env := append(os.Environ(), extraEnvs...)
113116
// TODO: Remove these variables when they're no longer needed for downgrades.
114117
if framework.TestContext.EtcdUpgradeVersion != "" && framework.TestContext.EtcdUpgradeStorage != "" {
115118
env = append(env,
@@ -149,7 +152,7 @@ var _ = SIGDescribe("Upgrade [Feature:Upgrade]", func() {
149152
start := time.Now()
150153
defer finalizeUpgradeTest(start, masterUpgradeTest)
151154
target := upgCtx.Versions[1].Version.String()
152-
framework.ExpectNoError(masterUpgrade(f, target))
155+
framework.ExpectNoError(masterUpgrade(f, target, nil))
153156
framework.ExpectNoError(checkMasterVersion(f.ClientSet, target))
154157
}
155158
runUpgradeSuite(f, upgradeTests, testFrameworks, testSuite, upgrades.MasterUpgrade, upgradeFunc)
@@ -190,7 +193,7 @@ var _ = SIGDescribe("Upgrade [Feature:Upgrade]", func() {
190193
start := time.Now()
191194
defer finalizeUpgradeTest(start, clusterUpgradeTest)
192195
target := upgCtx.Versions[1].Version.String()
193-
framework.ExpectNoError(masterUpgrade(f, target))
196+
framework.ExpectNoError(masterUpgrade(f, target, nil))
194197
framework.ExpectNoError(checkMasterVersion(f.ClientSet, target))
195198
framework.ExpectNoError(nodeUpgrade(f, target, *upgradeImage))
196199
framework.ExpectNoError(checkNodesVersions(f.ClientSet, target))
@@ -223,7 +226,7 @@ var _ = SIGDescribe("Downgrade [Feature:Downgrade]", func() {
223226
target := upgCtx.Versions[1].Version.String()
224227
framework.ExpectNoError(nodeUpgrade(f, target, *upgradeImage))
225228
framework.ExpectNoError(checkNodesVersions(f.ClientSet, target))
226-
framework.ExpectNoError(masterUpgrade(f, target))
229+
framework.ExpectNoError(masterUpgrade(f, target, nil))
227230
framework.ExpectNoError(checkMasterVersion(f.ClientSet, target))
228231
}
229232
runUpgradeSuite(f, upgradeTests, testFrameworks, testSuite, upgrades.ClusterUpgrade, upgradeFunc)
@@ -271,7 +274,7 @@ var _ = SIGDescribe("gpu Upgrade [Feature:GPUUpgrade]", func() {
271274
start := time.Now()
272275
defer finalizeUpgradeTest(start, gpuUpgradeTest)
273276
target := upgCtx.Versions[1].Version.String()
274-
framework.ExpectNoError(masterUpgrade(f, target))
277+
framework.ExpectNoError(masterUpgrade(f, target, nil))
275278
framework.ExpectNoError(checkMasterVersion(f.ClientSet, target))
276279
}
277280
runUpgradeSuite(f, gpuUpgradeTests, testFrameworks, testSuite, upgrades.MasterUpgrade, upgradeFunc)
@@ -289,7 +292,7 @@ var _ = SIGDescribe("gpu Upgrade [Feature:GPUUpgrade]", func() {
289292
start := time.Now()
290293
defer finalizeUpgradeTest(start, gpuUpgradeTest)
291294
target := upgCtx.Versions[1].Version.String()
292-
framework.ExpectNoError(masterUpgrade(f, target))
295+
framework.ExpectNoError(masterUpgrade(f, target, nil))
293296
framework.ExpectNoError(checkMasterVersion(f.ClientSet, target))
294297
framework.ExpectNoError(nodeUpgrade(f, target, *upgradeImage))
295298
framework.ExpectNoError(checkNodesVersions(f.ClientSet, target))
@@ -311,7 +314,7 @@ var _ = SIGDescribe("gpu Upgrade [Feature:GPUUpgrade]", func() {
311314
target := upgCtx.Versions[1].Version.String()
312315
framework.ExpectNoError(nodeUpgrade(f, target, *upgradeImage))
313316
framework.ExpectNoError(checkNodesVersions(f.ClientSet, target))
314-
framework.ExpectNoError(masterUpgrade(f, target))
317+
framework.ExpectNoError(masterUpgrade(f, target, nil))
315318
framework.ExpectNoError(checkMasterVersion(f.ClientSet, target))
316319
}
317320
runUpgradeSuite(f, gpuUpgradeTests, testFrameworks, testSuite, upgrades.ClusterUpgrade, upgradeFunc)
@@ -337,7 +340,7 @@ var _ = ginkgo.Describe("[sig-apps] stateful Upgrade [Feature:StatefulUpgrade]",
337340
start := time.Now()
338341
defer finalizeUpgradeTest(start, statefulUpgradeTest)
339342
target := upgCtx.Versions[1].Version.String()
340-
framework.ExpectNoError(masterUpgrade(f, target))
343+
framework.ExpectNoError(masterUpgrade(f, target, nil))
341344
framework.ExpectNoError(checkMasterVersion(f.ClientSet, target))
342345
framework.ExpectNoError(nodeUpgrade(f, target, *upgradeImage))
343346
framework.ExpectNoError(checkNodesVersions(f.ClientSet, target))
@@ -410,6 +413,33 @@ var _ = SIGDescribe("kube-proxy migration [Feature:KubeProxyDaemonSetMigration]"
410413
})
411414
})
412415

416+
var _ = SIGDescribe("[sig-auth] ServiceAccount admission controller migration [Feature:BoundServiceAccountTokenVolume]", func() {
417+
f := framework.NewDefaultFramework("serviceaccount-admission-controller-migration")
418+
419+
testFrameworks := createUpgradeFrameworks(serviceaccountAdmissionControllerMigrationTests)
420+
ginkgo.Describe("master upgrade", func() {
421+
ginkgo.It("should maintain a functioning cluster", func() {
422+
upgCtx, err := getUpgradeContext(f.ClientSet.Discovery(), *upgradeTarget)
423+
framework.ExpectNoError(err)
424+
425+
testSuite := &junit.TestSuite{Name: "ServiceAccount admission controller migration"}
426+
serviceaccountAdmissionControllerMigrationTest := &junit.TestCase{
427+
Name: "[sig-auth] serviceaccount-admission-controller-migration",
428+
Classname: "upgrade_tests",
429+
}
430+
testSuite.TestCases = append(testSuite.TestCases, serviceaccountAdmissionControllerMigrationTest)
431+
432+
upgradeFunc := func() {
433+
start := time.Now()
434+
defer finalizeUpgradeTest(start, serviceaccountAdmissionControllerMigrationTest)
435+
target := upgCtx.Versions[1].Version.String()
436+
framework.ExpectNoError(masterUpgrade(f, target, []string{"KUBE_FEATURE_GATES=BoundServiceAccountTokenVolume=true"}))
437+
}
438+
runUpgradeSuite(f, serviceaccountAdmissionControllerMigrationTests, testFrameworks, testSuite, upgrades.MasterUpgrade, upgradeFunc)
439+
})
440+
})
441+
})
442+
413443
type chaosMonkeyAdapter struct {
414444
test upgrades.Test
415445
testReport *junit.TestCase

test/e2e/framework/pod/resource.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -533,25 +533,33 @@ func checkPodsCondition(c clientset.Interface, ns string, podNames []string, tim
533533

534534
// GetPodLogs returns the logs of the specified container (namespace/pod/container).
535535
func GetPodLogs(c clientset.Interface, namespace, podName, containerName string) (string, error) {
536-
return getPodLogsInternal(c, namespace, podName, containerName, false)
536+
return getPodLogsInternal(c, namespace, podName, containerName, false, nil)
537+
}
538+
539+
// GetPodLogsSince returns the logs of the specified container (namespace/pod/container) since a timestamp.
540+
func GetPodLogsSince(c clientset.Interface, namespace, podName, containerName string, since time.Time) (string, error) {
541+
sinceTime := metav1.NewTime(since)
542+
return getPodLogsInternal(c, namespace, podName, containerName, false, &sinceTime)
537543
}
538544

539545
// GetPreviousPodLogs returns the logs of the previous instance of the
540546
// specified container (namespace/pod/container).
541547
func GetPreviousPodLogs(c clientset.Interface, namespace, podName, containerName string) (string, error) {
542-
return getPodLogsInternal(c, namespace, podName, containerName, true)
548+
return getPodLogsInternal(c, namespace, podName, containerName, true, nil)
543549
}
544550

545551
// utility function for gomega Eventually
546-
func getPodLogsInternal(c clientset.Interface, namespace, podName, containerName string, previous bool) (string, error) {
547-
logs, err := c.CoreV1().RESTClient().Get().
552+
func getPodLogsInternal(c clientset.Interface, namespace, podName, containerName string, previous bool, sinceTime *metav1.Time) (string, error) {
553+
request := c.CoreV1().RESTClient().Get().
548554
Resource("pods").
549555
Namespace(namespace).
550556
Name(podName).SubResource("log").
551557
Param("container", containerName).
552-
Param("previous", strconv.FormatBool(previous)).
553-
Do(context.TODO()).
554-
Raw()
558+
Param("previous", strconv.FormatBool(previous))
559+
if sinceTime != nil {
560+
request.Param("sinceTime", sinceTime.Format(time.RFC3339))
561+
}
562+
logs, err := request.Do(context.TODO()).Raw()
555563
if err != nil {
556564
return "", err
557565
}

test/e2e/upgrades/BUILD

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

0 commit comments

Comments
 (0)