k8s.io/kubernetes@v1.29.3/test/e2e/common/node/podtemplates.go (about) 1 /* 2 Copyright 2020 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 node 18 19 import ( 20 "context" 21 "encoding/json" 22 23 "time" 24 25 v1 "k8s.io/api/core/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/types" 28 utilrand "k8s.io/apimachinery/pkg/util/rand" 29 "k8s.io/apimachinery/pkg/util/uuid" 30 "k8s.io/apimachinery/pkg/util/wait" 31 "k8s.io/client-go/util/retry" 32 "k8s.io/kubernetes/test/e2e/framework" 33 imageutils "k8s.io/kubernetes/test/utils/image" 34 admissionapi "k8s.io/pod-security-admission/api" 35 36 "github.com/onsi/ginkgo/v2" 37 "github.com/onsi/gomega" 38 ) 39 40 const ( 41 podTemplateRetryPeriod = 1 * time.Second 42 podTemplateRetryTimeout = 1 * time.Minute 43 ) 44 45 var _ = SIGDescribe("PodTemplates", func() { 46 f := framework.NewDefaultFramework("podtemplate") 47 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged 48 /* 49 Release: v1.19 50 Testname: PodTemplate lifecycle 51 Description: Attempt to create a PodTemplate. Patch the created PodTemplate. Fetching the PodTemplate MUST reflect changes. 52 By fetching all the PodTemplates via a Label selector it MUST find the PodTemplate by it's static label and updated value. The PodTemplate must be deleted. 53 */ 54 framework.ConformanceIt("should run the lifecycle of PodTemplates", func(ctx context.Context) { 55 testNamespaceName := f.Namespace.Name 56 podTemplateName := "nginx-pod-template-" + string(uuid.NewUUID()) 57 58 // get a list of PodTemplates (in all namespaces to hit endpoint) 59 podTemplateList, err := f.ClientSet.CoreV1().PodTemplates("").List(ctx, metav1.ListOptions{ 60 LabelSelector: "podtemplate-static=true", 61 }) 62 framework.ExpectNoError(err, "failed to list all PodTemplates") 63 gomega.Expect(podTemplateList.Items).To(gomega.BeEmpty(), "unable to find templates") 64 65 // create a PodTemplate 66 _, err = f.ClientSet.CoreV1().PodTemplates(testNamespaceName).Create(ctx, &v1.PodTemplate{ 67 ObjectMeta: metav1.ObjectMeta{ 68 Name: podTemplateName, 69 Labels: map[string]string{ 70 "podtemplate-static": "true", 71 }, 72 }, 73 Template: v1.PodTemplateSpec{ 74 Spec: v1.PodSpec{ 75 Containers: []v1.Container{ 76 {Name: "nginx", Image: imageutils.GetE2EImage(imageutils.Nginx)}, 77 }, 78 }, 79 }, 80 }, metav1.CreateOptions{}) 81 framework.ExpectNoError(err, "failed to create PodTemplate") 82 83 // get template 84 podTemplateRead, err := f.ClientSet.CoreV1().PodTemplates(testNamespaceName).Get(ctx, podTemplateName, metav1.GetOptions{}) 85 framework.ExpectNoError(err, "failed to get created PodTemplate") 86 gomega.Expect(podTemplateRead.ObjectMeta.Name).To(gomega.Equal(podTemplateName)) 87 88 // patch template 89 podTemplatePatch, err := json.Marshal(map[string]interface{}{ 90 "metadata": map[string]interface{}{ 91 "labels": map[string]string{ 92 "podtemplate": "patched", 93 }, 94 }, 95 }) 96 framework.ExpectNoError(err, "failed to marshal patch data") 97 _, err = f.ClientSet.CoreV1().PodTemplates(testNamespaceName).Patch(ctx, podTemplateName, types.StrategicMergePatchType, []byte(podTemplatePatch), metav1.PatchOptions{}) 98 framework.ExpectNoError(err, "failed to patch PodTemplate") 99 100 // get template (ensure label is there) 101 podTemplateRead, err = f.ClientSet.CoreV1().PodTemplates(testNamespaceName).Get(ctx, podTemplateName, metav1.GetOptions{}) 102 framework.ExpectNoError(err, "failed to get PodTemplate") 103 gomega.Expect(podTemplateRead.ObjectMeta.Labels).To(gomega.HaveKeyWithValue("podtemplate", "patched"), "failed to patch template, new label not found") 104 105 // delete the PodTemplate 106 err = f.ClientSet.CoreV1().PodTemplates(testNamespaceName).Delete(ctx, podTemplateName, metav1.DeleteOptions{}) 107 framework.ExpectNoError(err, "failed to delete PodTemplate") 108 109 // list the PodTemplates 110 podTemplateList, err = f.ClientSet.CoreV1().PodTemplates("").List(ctx, metav1.ListOptions{ 111 LabelSelector: "podtemplate-static=true", 112 }) 113 framework.ExpectNoError(err, "failed to list PodTemplate") 114 gomega.Expect(podTemplateList.Items).To(gomega.BeEmpty(), "PodTemplate list returned items, failed to delete PodTemplate") 115 }) 116 117 /* 118 Release: v1.19 119 Testname: PodTemplate, delete a collection 120 Description: A set of Pod Templates is created with a label selector which MUST be found when listed. 121 The set of Pod Templates is deleted and MUST NOT show up when listed by its label selector. 122 */ 123 framework.ConformanceIt("should delete a collection of pod templates", func(ctx context.Context) { 124 podTemplateNames := []string{"test-podtemplate-1", "test-podtemplate-2", "test-podtemplate-3"} 125 126 ginkgo.By("Create set of pod templates") 127 // create a set of pod templates in test namespace 128 for _, podTemplateName := range podTemplateNames { 129 _, err := f.ClientSet.CoreV1().PodTemplates(f.Namespace.Name).Create(ctx, &v1.PodTemplate{ 130 ObjectMeta: metav1.ObjectMeta{ 131 Name: podTemplateName, 132 Labels: map[string]string{"podtemplate-set": "true"}, 133 }, 134 Template: v1.PodTemplateSpec{ 135 Spec: v1.PodSpec{ 136 Containers: []v1.Container{ 137 {Name: "token-test", Image: imageutils.GetE2EImage(imageutils.Agnhost)}, 138 }, 139 }, 140 }, 141 }, metav1.CreateOptions{}) 142 framework.ExpectNoError(err, "failed to create pod template") 143 framework.Logf("created %v", podTemplateName) 144 } 145 146 ginkgo.By("get a list of pod templates with a label in the current namespace") 147 // get a list of pod templates 148 podTemplateList, err := f.ClientSet.CoreV1().PodTemplates(f.Namespace.Name).List(ctx, metav1.ListOptions{ 149 LabelSelector: "podtemplate-set=true", 150 }) 151 framework.ExpectNoError(err, "failed to get a list of pod templates") 152 153 gomega.Expect(podTemplateList.Items).To(gomega.HaveLen(len(podTemplateNames)), "looking for expected number of pod templates") 154 155 ginkgo.By("delete collection of pod templates") 156 // delete collection 157 158 framework.Logf("requesting DeleteCollection of pod templates") 159 err = f.ClientSet.CoreV1().PodTemplates(f.Namespace.Name).DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{ 160 LabelSelector: "podtemplate-set=true"}) 161 framework.ExpectNoError(err, "failed to delete all pod templates") 162 163 ginkgo.By("check that the list of pod templates matches the requested quantity") 164 165 err = wait.PollImmediate(podTemplateRetryPeriod, podTemplateRetryTimeout, checkPodTemplateListQuantity(ctx, f, "podtemplate-set=true", 0)) 166 framework.ExpectNoError(err, "failed to count required pod templates") 167 168 }) 169 170 /* 171 Release: v1.24 172 Testname: PodTemplate, replace 173 Description: Attempt to create a PodTemplate which MUST succeed. 174 Attempt to replace the PodTemplate to include a new annotation 175 which MUST succeed. The annotation MUST be found in the new PodTemplate. 176 */ 177 framework.ConformanceIt("should replace a pod template", func(ctx context.Context) { 178 ptClient := f.ClientSet.CoreV1().PodTemplates(f.Namespace.Name) 179 ptName := "podtemplate-" + utilrand.String(5) 180 181 ginkgo.By("Create a pod template") 182 ptResource, err := ptClient.Create(ctx, &v1.PodTemplate{ 183 ObjectMeta: metav1.ObjectMeta{ 184 Name: ptName, 185 }, 186 Template: v1.PodTemplateSpec{ 187 Spec: v1.PodSpec{ 188 Containers: []v1.Container{ 189 {Name: "e2e-test", Image: imageutils.GetE2EImage(imageutils.Agnhost)}, 190 }, 191 }, 192 }, 193 }, metav1.CreateOptions{}) 194 framework.ExpectNoError(err, "failed to create pod template") 195 196 ginkgo.By("Replace a pod template") 197 var updatedPT *v1.PodTemplate 198 199 err = retry.RetryOnConflict(retry.DefaultRetry, func() error { 200 ptResource, err = ptClient.Get(ctx, ptName, metav1.GetOptions{}) 201 framework.ExpectNoError(err, "Unable to get pod template %s", ptName) 202 ptResource.Annotations = map[string]string{ 203 "updated": "true", 204 } 205 updatedPT, err = ptClient.Update(ctx, ptResource, metav1.UpdateOptions{}) 206 return err 207 }) 208 framework.ExpectNoError(err) 209 gomega.Expect(updatedPT.Annotations).To(gomega.HaveKeyWithValue("updated", "true"), "updated object should have the applied annotation") 210 framework.Logf("Found updated podtemplate annotation: %#v\n", updatedPT.Annotations["updated"]) 211 }) 212 213 }) 214 215 func checkPodTemplateListQuantity(ctx context.Context, f *framework.Framework, label string, quantity int) func() (bool, error) { 216 return func() (bool, error) { 217 var err error 218 219 framework.Logf("requesting list of pod templates to confirm quantity") 220 221 list, err := f.ClientSet.CoreV1().PodTemplates(f.Namespace.Name).List(ctx, metav1.ListOptions{ 222 LabelSelector: label}) 223 224 if err != nil { 225 return false, err 226 } 227 228 if len(list.Items) != quantity { 229 return false, err 230 } 231 return true, nil 232 } 233 }