fix(webhook): Release annotation on bounded ResourcePoolClaim (#1965)

Signed-off-by: Omar Ferro <omar.ferroomar@gmail.com>
This commit is contained in:
Omar Ferro
2026-06-12 14:55:22 +02:00
committed by GitHub
parent f5d2d7d67b
commit f84f9d6c28
3 changed files with 136 additions and 3 deletions
+2 -2
View File
@@ -27,9 +27,9 @@ make test
## E2E Test
**New changes always require dedcated E2E tests. E2E help us to ensure the quality of the code and it's functionality.**
**New changes always require dedicated E2E tests. E2E help us to ensure the quality of the code and it's functionality.**
For E2E test we use the [ginkgo](https://github.com/onsi/ginkgo) framework. Ou can see all the test under [e2e](./e2e/).
For E2E test we use the [ginkgo](https://github.com/onsi/ginkgo) framework. You can see all the test under [e2e](./e2e/).
With the following command a new KinD cluster is created with the Kubernetes version `v1.20.7` (This can be done with any available Kubernetes version). A docker image is created and pushed and loaded into the KinD cluster. Then the E2E tests are executed against the KinD cluster.
+133
View File
@@ -621,6 +621,139 @@ var _ = Describe("ResourcePoolClaim Tests", Ordered, Label("resourcepool", "clai
})
})
It("Admission (Mutation) - Release Bound Claim", Label("skip-on-openshift"), func() {
pool := &capsulev1beta2.ResourcePool{
ObjectMeta: metav1.ObjectMeta{
Name: "test-release-bound-claim",
Labels: map[string]string{
"e2e-resourcepoolclaims": "test",
},
},
Spec: capsulev1beta2.ResourcePoolSpec{
Config: capsulev1beta2.ResourcePoolSpecConfiguration{
DeleteBoundResources: ptr.To(false),
},
Selectors: []selectors.NamespaceSelector{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"e2e.capsule.dev/test-suite": "release-bound-claim",
},
},
},
},
Quota: corev1.ResourceQuotaSpec{
Hard: corev1.ResourceList{
corev1.ResourceLimitsCPU: resource.MustParse("2"),
corev1.ResourceLimitsMemory: resource.MustParse("2Gi"),
corev1.ResourceRequestsCPU: resource.MustParse("2"),
corev1.ResourceRequestsMemory: resource.MustParse("2Gi"),
},
},
},
}
claim := &capsulev1beta2.ResourcePoolClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "release-bound-claim",
Namespace: "ns-release-bound-claim",
},
Spec: capsulev1beta2.ResourcePoolClaimSpec{
Pool: pool.GetName(),
ResourceClaims: corev1.ResourceList{
corev1.ResourceLimitsCPU: resource.MustParse("1"),
corev1.ResourceLimitsMemory: resource.MustParse("1Gi"),
corev1.ResourceRequestsCPU: resource.MustParse("1"),
corev1.ResourceRequestsMemory: resource.MustParse("1Gi"),
},
},
}
By("Create the ResourcePool and namespace", func() {
EventuallyCreation(func() error {
pool.ResourceVersion = ""
return k8sClient.Create(context.TODO(), pool)
}).Should(Succeed(), "Failed to create %s", pool)
ns := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: claim.Namespace,
Labels: map[string]string{
"e2e-resourcepoolclaims": "test",
"e2e.capsule.dev/test-suite": "release-bound-claim",
},
},
}
EventuallyCreation(func() error {
ns.ResourceVersion = ""
return k8sClient.Create(context.TODO(), ns)
}).Should(Succeed(), "Failed to create %s", ns)
})
By("Bind the claim to the pool", func() {
EventuallyCreation(func() error {
claim.ResourceVersion = ""
return k8sClient.Create(context.TODO(), claim)
}).Should(Succeed(), "Failed to create %s", claim)
isSuccessfullyBoundAndUnsedToPool(pool, claim)
})
By("Release the bound claim with the release annotation", func() {
Eventually(func() error {
stat := &capsulev1beta2.ResourcePoolClaim{}
if err := k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, stat); err != nil {
return err
}
if stat.Annotations == nil {
stat.Annotations = map[string]string{}
}
stat.Annotations[meta.ReleaseAnnotation] = meta.ReleaseAnnotationTrigger
return k8sClient.Update(context.TODO(), stat)
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
})
By("Verify the claim is disassociated and the release annotation was consumed", func() {
Eventually(func(g Gomega) {
stat := &capsulev1beta2.ResourcePoolClaim{}
g.Expect(k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, stat)).To(Succeed())
bound := stat.Status.Conditions.GetConditionByType(meta.BoundCondition)
g.Expect(bound).ToNot(BeNil(), "Bound condition should not be nil")
g.Expect(bound.Status).To(Equal(metav1.ConditionFalse), "Bound condition status should be False")
g.Expect(stat.Annotations).NotTo(HaveKey(meta.ReleaseAnnotation))
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
})
By("Allow updating the released claim resources while the pool still exists", func() {
Eventually(func() error {
stat := &capsulev1beta2.ResourcePoolClaim{}
if err := k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, stat); err != nil {
return err
}
stat.Spec.ResourceClaims = corev1.ResourceList{
corev1.ResourceLimitsCPU: resource.MustParse("2"),
corev1.ResourceLimitsMemory: resource.MustParse("2Gi"),
corev1.ResourceRequestsCPU: resource.MustParse("2"),
corev1.ResourceRequestsMemory: resource.MustParse("2Gi"),
}
return k8sClient.Update(context.TODO(), stat)
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
})
})
It("Admission (Mutation) - Auto Pool Assign", Label("skip-on-openshift"), func() {
pool1 := &capsulev1beta2.ResourcePool{
ObjectMeta: metav1.ObjectMeta{
@@ -104,7 +104,7 @@ func (h *claimMutationHandler) handleReleaseAnnotation(
return
}
if !claim.IsBoundInResourcePool() {
if claim.IsBoundInResourcePool() {
return
}