|
1 | 1 | package webhooks |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "errors" |
4 | 5 | "fmt" |
| 6 | + "reflect" |
| 7 | + "time" |
5 | 8 |
|
6 | 9 | . "github.com/onsi/ginkgo" |
7 | 10 | . "github.com/onsi/gomega" |
@@ -164,24 +167,78 @@ func podMutationWebhookCleanup() { |
164 | 167 | var _ = Describe("pod mutation webhook", func() { |
165 | 168 |
|
166 | 169 | It("should backfill role binding subjects when annotated pods already exist in the cluster", func() { |
167 | | - pod1 := getPod(existingPod1Name) |
168 | | - pod2 := getPod(existingPod2Name) |
169 | | - // Pod 1 and 2 must not have been mutated by the webhook (we want the rolebinding to be updated via BackfillPermissions) |
170 | | - Expect(len(pod1.Spec.Containers)).To(Equal(1)) |
171 | | - Expect(len(pod2.Spec.Containers)).To(Equal(1)) |
172 | | - rb := getRoleBinding(clusterRoleBindingName) |
173 | | - Expect(rb.Subjects).To(ContainElement(v1.Subject{ |
174 | | - Kind: "ServiceAccount", |
175 | | - APIGroup: "", |
176 | | - Name: existingPod1ServiceAccountName, |
177 | | - Namespace: mutatePodNamespace, |
178 | | - })) |
179 | | - Expect(rb.Subjects).To(ContainElement(v1.Subject{ |
| 170 | + // this integration test confirms the proper execution of the podMutator.BackfillPermissions method |
| 171 | + // this method is responsible for backfilling the subjects of the open-feature-operator-flagd-kubernetes-sync |
| 172 | + // cluster role binding, for previously existing pods on startup |
| 173 | + // a retry is required on this test as the backfilling occurs asynchronously |
| 174 | + var finalError error |
| 175 | + for i := 0; i < 3; i++ { |
| 176 | + pod1 := getPod(existingPod1Name) |
| 177 | + pod2 := getPod(existingPod2Name) |
| 178 | + // Pod 1 and 2 must not have been mutated by the webhook (we want the rolebinding to be updated via BackfillPermissions) |
| 179 | + |
| 180 | + if len(pod1.Spec.Containers) != 1 { |
| 181 | + finalError = errors.New("pod1 has had a container injected, it should not be mutated by the webhook") |
| 182 | + time.Sleep(1 * time.Second) |
| 183 | + continue |
| 184 | + } |
| 185 | + if len(pod2.Spec.Containers) != 1 { |
| 186 | + finalError = errors.New("pod2 has had a container injected, it should not be mutated by the webhook") |
| 187 | + time.Sleep(1 * time.Second) |
| 188 | + continue |
| 189 | + } |
| 190 | + |
| 191 | + rb := getRoleBinding(clusterRoleBindingName) |
| 192 | + |
| 193 | + unexpectedServiceAccount := "" |
| 194 | + for _, subject := range rb.Subjects { |
| 195 | + if !reflect.DeepEqual(subject, v1.Subject{ |
| 196 | + Kind: "ServiceAccount", |
| 197 | + APIGroup: "", |
| 198 | + Name: existingPod1ServiceAccountName, |
| 199 | + Namespace: mutatePodNamespace, |
| 200 | + }) && |
| 201 | + !reflect.DeepEqual(subject, v1.Subject{ |
| 202 | + Kind: "ServiceAccount", |
| 203 | + APIGroup: "", |
| 204 | + Name: existingPod2ServiceAccountName, |
| 205 | + Namespace: mutatePodNamespace, |
| 206 | + }) { |
| 207 | + unexpectedServiceAccount = subject.Name |
| 208 | + } |
| 209 | + } |
| 210 | + if unexpectedServiceAccount != "" { |
| 211 | + finalError = fmt.Errorf("unexpected subject found in role binding, name: %s", unexpectedServiceAccount) |
| 212 | + time.Sleep(1 * time.Second) |
| 213 | + continue |
| 214 | + } |
| 215 | + finalError = nil |
| 216 | + break |
| 217 | + } |
| 218 | + Expect(finalError).ShouldNot(HaveOccurred()) |
| 219 | + }) |
| 220 | + |
| 221 | + It("should update cluster role binding's subjects", func() { |
| 222 | + pod := testPod(defaultPodName, defaultPodServiceAccountName, map[string]string{ |
| 223 | + "openfeature.dev": "enabled", |
| 224 | + "openfeature.dev/featureflagconfiguration": fmt.Sprintf("%s/%s", mutatePodNamespace, featureFlagConfigurationName), |
| 225 | + }) |
| 226 | + err := k8sClient.Create(testCtx, pod) |
| 227 | + Expect(err).ShouldNot(HaveOccurred()) |
| 228 | + |
| 229 | + crb := &v1.ClusterRoleBinding{} |
| 230 | + err = k8sClient.Get(testCtx, client.ObjectKey{Name: clusterRoleBindingName}, crb) |
| 231 | + Expect(err).ShouldNot(HaveOccurred()) |
| 232 | + |
| 233 | + Expect(len(crb.Subjects)).Should(Equal(3)) |
| 234 | + Expect(crb.Subjects).To(ContainElement(v1.Subject{ |
180 | 235 | Kind: "ServiceAccount", |
181 | 236 | APIGroup: "", |
182 | | - Name: existingPod2ServiceAccountName, |
| 237 | + Name: defaultPodServiceAccountName, |
183 | 238 | Namespace: mutatePodNamespace, |
184 | 239 | })) |
| 240 | + |
| 241 | + podMutationWebhookCleanup() |
185 | 242 | }) |
186 | 243 |
|
187 | 244 | It("should create flagd sidecar", func() { |
@@ -264,29 +321,6 @@ var _ = Describe("pod mutation webhook", func() { |
264 | 321 | Expect(err).Should(HaveOccurred()) |
265 | 322 | }) |
266 | 323 |
|
267 | | - It("should update cluster role binding's subjects", func() { |
268 | | - pod := testPod(defaultPodName, defaultPodServiceAccountName, map[string]string{ |
269 | | - "openfeature.dev": "enabled", |
270 | | - "openfeature.dev/featureflagconfiguration": fmt.Sprintf("%s/%s", mutatePodNamespace, featureFlagConfigurationName), |
271 | | - }) |
272 | | - err := k8sClient.Create(testCtx, pod) |
273 | | - Expect(err).ShouldNot(HaveOccurred()) |
274 | | - |
275 | | - crb := &v1.ClusterRoleBinding{} |
276 | | - err = k8sClient.Get(testCtx, client.ObjectKey{Name: clusterRoleBindingName}, crb) |
277 | | - Expect(err).ShouldNot(HaveOccurred()) |
278 | | - |
279 | | - Expect(len(crb.Subjects)).Should(Equal(3)) |
280 | | - Expect(crb.Subjects).To(ContainElement(v1.Subject{ |
281 | | - Kind: "ServiceAccount", |
282 | | - APIGroup: "", |
283 | | - Name: defaultPodServiceAccountName, |
284 | | - Namespace: mutatePodNamespace, |
285 | | - })) |
286 | | - |
287 | | - podMutationWebhookCleanup() |
288 | | - }) |
289 | | - |
290 | 324 | It("should create config map if sync provider isn't kubernetes", func() { |
291 | 325 | ffConfig := &corev1alpha1.FeatureFlagConfiguration{} |
292 | 326 | err := k8sClient.Get( |
|
0 commit comments