1
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
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
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
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
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
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
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
106 err = f.ClientSet.CoreV1().PodTemplates(testNamespaceName).Delete(ctx, podTemplateName, metav1.DeleteOptions{})
107 framework.ExpectNoError(err, "failed to delete PodTemplate")
108
109
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
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
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
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
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
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 }
234
View as plain text