From 23d4367cff8c38ad5666788f73acc28abd0c9ab1 Mon Sep 17 00:00:00 2001 From: Caleb Woodbine Date: Thu, 16 Apr 2020 16:34:59 +1200 Subject: [PATCH 1/4] Add ServiceAccount resource lifecycle test --- test/e2e/auth/service_accounts.go | 89 +++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/test/e2e/auth/service_accounts.go b/test/e2e/auth/service_accounts.go index 926f63241e9..52200122d12 100644 --- a/test/e2e/auth/service_accounts.go +++ b/test/e2e/auth/service_accounts.go @@ -18,6 +18,7 @@ package auth import ( "context" + "encoding/json" "fmt" "path" "regexp" @@ -29,9 +30,11 @@ import ( rbacv1 "k8s.io/api/rbac/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/uuid" "k8s.io/apimachinery/pkg/util/wait" + watch "k8s.io/apimachinery/pkg/watch" "k8s.io/kubernetes/plugin/pkg/admission/serviceaccount" "k8s.io/kubernetes/test/e2e/framework" e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl" @@ -621,6 +624,92 @@ var _ = SIGDescribe("ServiceAccounts", func() { framework.ExpectNoError(podErr) framework.Logf("completed pod") }) + + ginkgo.It("should run through the lifecycle of a ServiceAccount", func() { + testNamespaceName := f.Namespace.Name + testServiceAccountName := "testserviceaccount" + testSecretName := "testsecret" + testServiceAccountStaticLabels := map[string]string{"test-serviceaccount-static": "true"} + testServiceAccountStaticLabelsFlat := "test-serviceaccount-static=true" + + ginkgo.By("creating a ServiceAccount") + testServiceAccount := v1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: testServiceAccountName, + Labels: testServiceAccountStaticLabels, + }, + } + _, err := f.ClientSet.CoreV1().ServiceAccounts(testNamespaceName).Create(context.TODO(), &testServiceAccount, metav1.CreateOptions{}) + framework.ExpectNoError(err, "failed to create a ServiceAccount") + ginkgo.By("creating a Secret") + testSecret := v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: testSecretName, + }, + Data: map[string][]byte{ + "test-field": []byte("test-value"), + }, + Type: "Opaque", + } + _, err = f.ClientSet.CoreV1().Secrets(testNamespaceName).Create(context.TODO(), &testSecret, metav1.CreateOptions{}) + framework.ExpectNoError(err, "failed to create a Secret") + + fmt.Println("watching for the ServiceAccount to be added") + resourceWatchTimeoutSeconds := int64(180) + resourceWatch, err := f.ClientSet.CoreV1().ServiceAccounts(testNamespaceName).Watch(context.TODO(), metav1.ListOptions{LabelSelector: testServiceAccountStaticLabelsFlat, TimeoutSeconds: &resourceWatchTimeoutSeconds}) + if err != nil { + fmt.Println(err, "failed to setup watch on newly created ServiceAccount") + return + } + + resourceWatchChan := resourceWatch.ResultChan() + for watchEvent := range resourceWatchChan { + if watchEvent.Type == watch.Added { + break + } + } + + defer func() { + ginkgo.By("deleting the ServiceAccount") + err = f.ClientSet.CoreV1().ServiceAccounts(testNamespaceName).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{}) + framework.ExpectNoError(err, "failed to delete the ServiceAccount by Collection") + for watchEvent := range resourceWatchChan { + if watchEvent.Type == watch.Deleted { + break + } + } + + ginkgo.By("deleting the Secret") + err = f.ClientSet.CoreV1().Secrets(testNamespaceName).Delete(context.TODO(), testSecretName, metav1.DeleteOptions{}) + framework.ExpectNoError(err, "failed to delete the Secret") + }() + + ginkgo.By("patching the ServiceAccount") + testServiceAccountPatchData, err := json.Marshal(map[string]interface{}{ + "secrets": []map[string]interface{}{{ + "name": testSecretName, + }}, + }) + framework.ExpectNoError(err, "failed to marshal JSON patch for the ServiceAccount") + _, err = f.ClientSet.CoreV1().ServiceAccounts(testNamespaceName).Patch(context.TODO(), testServiceAccountName, types.StrategicMergePatchType, []byte(testServiceAccountPatchData), metav1.PatchOptions{}) + framework.ExpectNoError(err, "failed to patch the ServiceAccount") + for watchEvent := range resourceWatchChan { + if watchEvent.Type == watch.Modified { + break + } + } + + ginkgo.By("finding ServiceAccount in list of all ServiceAccounts (by LabelSelector)") + serviceAccountList, err := f.ClientSet.CoreV1().ServiceAccounts("").List(context.TODO(), metav1.ListOptions{LabelSelector: testServiceAccountStaticLabelsFlat}) + foundServiceAccount := false + for _, serviceAccountItem := range serviceAccountList.Items { + if serviceAccountItem.ObjectMeta.Name == testServiceAccountName && serviceAccountItem.ObjectMeta.Namespace == testNamespaceName && serviceAccountItem.Secrets[0].Name == testSecretName { + foundServiceAccount = true + break + } + } + framework.ExpectEqual(foundServiceAccount, true, "failed to find the created ServiceAccount") + }) }) var reportLogsParser = regexp.MustCompile("([a-zA-Z0-9-_]*)=([a-zA-Z0-9-_]*)$") From e31baf82dab1bf600333e408acede9d8fa6a233b Mon Sep 17 00:00:00 2001 From: Caleb Woodbine Date: Thu, 16 Apr 2020 17:52:10 +1200 Subject: [PATCH 2/4] Fix build --- test/e2e/auth/BUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/test/e2e/auth/BUILD b/test/e2e/auth/BUILD index d7e53155b88..91aeabb0312 100644 --- a/test/e2e/auth/BUILD +++ b/test/e2e/auth/BUILD @@ -39,6 +39,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library", "//staging/src/k8s.io/apiserver/pkg/apis/audit:go_default_library", "//staging/src/k8s.io/apiserver/pkg/apis/audit/v1:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/serviceaccount:go_default_library", From c6e1701bdad123a21940af2c0c110ff64f9a8a08 Mon Sep 17 00:00:00 2001 From: Caleb Woodbine Date: Wed, 22 Apr 2020 10:45:17 +1200 Subject: [PATCH 3/4] Add checks to watches; Update to patch different subproperty --- test/e2e/auth/service_accounts.go | 57 +++++++++++++------------------ 1 file changed, 23 insertions(+), 34 deletions(-) diff --git a/test/e2e/auth/service_accounts.go b/test/e2e/auth/service_accounts.go index 52200122d12..3add729b83e 100644 --- a/test/e2e/auth/service_accounts.go +++ b/test/e2e/auth/service_accounts.go @@ -628,7 +628,6 @@ var _ = SIGDescribe("ServiceAccounts", func() { ginkgo.It("should run through the lifecycle of a ServiceAccount", func() { testNamespaceName := f.Namespace.Name testServiceAccountName := "testserviceaccount" - testSecretName := "testsecret" testServiceAccountStaticLabels := map[string]string{"test-serviceaccount-static": "true"} testServiceAccountStaticLabelsFlat := "test-serviceaccount-static=true" @@ -641,20 +640,8 @@ var _ = SIGDescribe("ServiceAccounts", func() { } _, err := f.ClientSet.CoreV1().ServiceAccounts(testNamespaceName).Create(context.TODO(), &testServiceAccount, metav1.CreateOptions{}) framework.ExpectNoError(err, "failed to create a ServiceAccount") - ginkgo.By("creating a Secret") - testSecret := v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: testSecretName, - }, - Data: map[string][]byte{ - "test-field": []byte("test-value"), - }, - Type: "Opaque", - } - _, err = f.ClientSet.CoreV1().Secrets(testNamespaceName).Create(context.TODO(), &testSecret, metav1.CreateOptions{}) - framework.ExpectNoError(err, "failed to create a Secret") - fmt.Println("watching for the ServiceAccount to be added") + ginkgo.By("watching for the ServiceAccount to be added") resourceWatchTimeoutSeconds := int64(180) resourceWatch, err := f.ClientSet.CoreV1().ServiceAccounts(testNamespaceName).Watch(context.TODO(), metav1.ListOptions{LabelSelector: testServiceAccountStaticLabelsFlat, TimeoutSeconds: &resourceWatchTimeoutSeconds}) if err != nil { @@ -663,52 +650,54 @@ var _ = SIGDescribe("ServiceAccounts", func() { } resourceWatchChan := resourceWatch.ResultChan() + eventFound := false for watchEvent := range resourceWatchChan { if watchEvent.Type == watch.Added { + eventFound = true break } } - - defer func() { - ginkgo.By("deleting the ServiceAccount") - err = f.ClientSet.CoreV1().ServiceAccounts(testNamespaceName).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{}) - framework.ExpectNoError(err, "failed to delete the ServiceAccount by Collection") - for watchEvent := range resourceWatchChan { - if watchEvent.Type == watch.Deleted { - break - } - } - - ginkgo.By("deleting the Secret") - err = f.ClientSet.CoreV1().Secrets(testNamespaceName).Delete(context.TODO(), testSecretName, metav1.DeleteOptions{}) - framework.ExpectNoError(err, "failed to delete the Secret") - }() + framework.ExpectEqual(eventFound, true, "failed to find %v event", watch.Added) ginkgo.By("patching the ServiceAccount") - testServiceAccountPatchData, err := json.Marshal(map[string]interface{}{ - "secrets": []map[string]interface{}{{ - "name": testSecretName, - }}, + boolFalse := false + testServiceAccountPatchData, err := json.Marshal(v1.ServiceAccount{ + AutomountServiceAccountToken: &boolFalse, }) framework.ExpectNoError(err, "failed to marshal JSON patch for the ServiceAccount") _, err = f.ClientSet.CoreV1().ServiceAccounts(testNamespaceName).Patch(context.TODO(), testServiceAccountName, types.StrategicMergePatchType, []byte(testServiceAccountPatchData), metav1.PatchOptions{}) framework.ExpectNoError(err, "failed to patch the ServiceAccount") + eventFound = false for watchEvent := range resourceWatchChan { if watchEvent.Type == watch.Modified { + eventFound = true break } } + framework.ExpectEqual(eventFound, true, "failed to find %v event", watch.Modified) ginkgo.By("finding ServiceAccount in list of all ServiceAccounts (by LabelSelector)") serviceAccountList, err := f.ClientSet.CoreV1().ServiceAccounts("").List(context.TODO(), metav1.ListOptions{LabelSelector: testServiceAccountStaticLabelsFlat}) foundServiceAccount := false for _, serviceAccountItem := range serviceAccountList.Items { - if serviceAccountItem.ObjectMeta.Name == testServiceAccountName && serviceAccountItem.ObjectMeta.Namespace == testNamespaceName && serviceAccountItem.Secrets[0].Name == testSecretName { + if serviceAccountItem.ObjectMeta.Name == testServiceAccountName && serviceAccountItem.ObjectMeta.Namespace == testNamespaceName && *serviceAccountItem.AutomountServiceAccountToken == boolFalse { foundServiceAccount = true break } } framework.ExpectEqual(foundServiceAccount, true, "failed to find the created ServiceAccount") + + ginkgo.By("deleting the ServiceAccount") + err = f.ClientSet.CoreV1().ServiceAccounts(testNamespaceName).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{}) + framework.ExpectNoError(err, "failed to delete the ServiceAccount by Collection") + eventFound = false + for watchEvent := range resourceWatchChan { + if watchEvent.Type == watch.Deleted { + eventFound = true + break + } + } + framework.ExpectEqual(eventFound, true, "failed to find %v event", watch.Deleted) }) }) From 9a53b0ec571fafc309ec09f539a7253d9805dded Mon Sep 17 00:00:00 2001 From: Caleb Woodbine Date: Wed, 22 Apr 2020 12:08:00 +1200 Subject: [PATCH 4/4] Add check for error in listing ServiceAccounts --- test/e2e/auth/service_accounts.go | 1 + 1 file changed, 1 insertion(+) diff --git a/test/e2e/auth/service_accounts.go b/test/e2e/auth/service_accounts.go index 3add729b83e..53f175d5139 100644 --- a/test/e2e/auth/service_accounts.go +++ b/test/e2e/auth/service_accounts.go @@ -678,6 +678,7 @@ var _ = SIGDescribe("ServiceAccounts", func() { ginkgo.By("finding ServiceAccount in list of all ServiceAccounts (by LabelSelector)") serviceAccountList, err := f.ClientSet.CoreV1().ServiceAccounts("").List(context.TODO(), metav1.ListOptions{LabelSelector: testServiceAccountStaticLabelsFlat}) + framework.ExpectNoError(err, "failed to list ServiceAccounts by LabelSelector") foundServiceAccount := false for _, serviceAccountItem := range serviceAccountList.Items { if serviceAccountItem.ObjectMeta.Name == testServiceAccountName && serviceAccountItem.ObjectMeta.Namespace == testNamespaceName && *serviceAccountItem.AutomountServiceAccountToken == boolFalse {