feat: diverse performance improvements (#1861)

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
This commit is contained in:
Oliver Bähler
2026-02-03 22:05:00 +01:00
committed by GitHub
parent 43c23cb4c8
commit 0abc77b56a
146 changed files with 5620 additions and 1760 deletions

View File

@@ -77,6 +77,7 @@ var _ = Describe("creating a Namespace for a Tenant with additional metadata", L
for k, v := range tnt.Spec.NamespaceOptions.AdditionalMetadata.Labels {
Expect(ns.Labels).To(HaveKeyWithValue(k, v))
}
return
})
By("checking additional annotations", func() {

View File

@@ -0,0 +1,126 @@
// Copyright 2020-2023 Project Capsule Authors.
// SPDX-License-Identifier: Apache-2.0
package e2e
import (
"context"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
"github.com/projectcapsule/capsule/pkg/api"
)
var _ = Describe("creating a Namespace for a Tenant with required metadata", Label("namespace", "metadata", "me"), func() {
tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-metadata-required",
},
Spec: capsulev1beta2.TenantSpec{
Owners: api.OwnerListSpec{
{
CoreOwnerSpec: api.CoreOwnerSpec{
UserSpec: api.UserSpec{
Name: "gatsby",
Kind: "User",
},
},
},
},
NamespaceOptions: &capsulev1beta2.NamespaceOptions{
RequiredMetadata: &capsulev1beta2.RequiredMetadata{
Labels: map[string]string{
"environment": "^(prod|test|dev)$",
},
Annotations: map[string]string{
"example.corp/cost-center": "^INV-[0-9]{4}$",
},
},
},
},
}
JustBeforeEach(func() {
EventuallyCreation(func() error {
return k8sClient.Create(context.TODO(), tnt)
}).Should(Succeed())
})
JustAfterEach(func() {
Expect(k8sClient.Delete(context.TODO(), tnt)).Should(Succeed())
})
It("should contain required Namespace metadata", func() {
By("creating without required label", func() {
ns := NewNamespace("")
NamespaceCreation(ns, tnt.Spec.Owners[0].UserSpec, defaultTimeoutInterval).ShouldNot(Succeed())
TenantNamespaceList(tnt, defaultTimeoutInterval).ShouldNot(ContainElement(ns.GetName()))
})
By("creating with required label, without annotation", func() {
ns := NewNamespace("", map[string]string{
"environment": "prod",
})
ns.SetAnnotations(map[string]string{})
NamespaceCreation(ns, tnt.Spec.Owners[0].UserSpec, defaultTimeoutInterval).ShouldNot(Succeed())
TenantNamespaceList(tnt, defaultTimeoutInterval).ShouldNot(ContainElement(ns.GetName()))
})
By("creating with required label and annotation", func() {
ns := NewNamespace("", map[string]string{
"environment": "prod",
})
ns.SetAnnotations(map[string]string{
"example.corp/cost-center": "INV-1234",
})
NamespaceCreation(ns, tnt.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
TenantNamespaceList(tnt, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: ns.GetName()}, ns)).Should(Succeed())
ns.SetLabels(map[string]string{
"environment": "UAT",
})
ns.SetAnnotations(map[string]string{
"example.corp/cost-center": "INV-1",
})
c := impersonationClient(tnt.Spec.Owners[0].UserSpec.Name, withDefaultGroups(nil))
err := c.Update(context.TODO(), ns)
Expect(err).ShouldNot(Succeed(), "expected failure")
})
By("creating with required label (wrong value) and annotation", func() {
ns := NewNamespace("", map[string]string{
"environment": "UAT",
})
ns.SetAnnotations(map[string]string{
"example.corp/cost-center": "INV-1234",
})
NamespaceCreation(ns, tnt.Spec.Owners[0].UserSpec, defaultTimeoutInterval).ShouldNot(Succeed())
TenantNamespaceList(tnt, defaultTimeoutInterval).ShouldNot(ContainElement(ns.GetName()))
})
By("creating with required label and annotation (wrong value)", func() {
ns := NewNamespace("", map[string]string{
"environment": "prod",
})
ns.SetAnnotations(map[string]string{
"example.corp/cost-center": "INV-1",
})
NamespaceCreation(ns, tnt.Spec.Owners[0].UserSpec, defaultTimeoutInterval).ShouldNot(Succeed())
TenantNamespaceList(tnt, defaultTimeoutInterval).ShouldNot(ContainElement(ns.GetName()))
})
})
})

View File

@@ -23,7 +23,7 @@ import (
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
)
var _ = Describe("enforcing a Runtime Class", Label("pod", "classes", "current"), func() {
var _ = Describe("enforcing a Runtime Class", Label("pod", "classes"), func() {
tntWithDefault := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "e2e-runtime-selection",

View File

@@ -20,7 +20,7 @@ import (
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
"github.com/projectcapsule/capsule/pkg/api/meta"
"github.com/projectcapsule/capsule/pkg/api/misc"
"github.com/projectcapsule/capsule/pkg/runtime/selectors"
"github.com/projectcapsule/capsule/pkg/utils"
)
@@ -85,7 +85,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
},
},
Spec: capsulev1beta2.ResourcePoolSpec{
Selectors: []misc.NamespaceSelector{
Selectors: []selectors.NamespaceSelector{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
@@ -243,7 +243,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err := k8sClient.Create(context.TODO(), claim1)
Expect(err).Should(Succeed(), "Failed to create Claim %s", claim1)
isSuccessfullyBoundToPool(pool, claim1)
isSuccessfullyBoundAndUnsedToPool(pool, claim1)
claim2 := &capsulev1beta2.ResourcePoolClaim{
ObjectMeta: metav1.ObjectMeta{
@@ -260,7 +260,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err = k8sClient.Create(context.TODO(), claim2)
Expect(err).Should(Succeed(), "Failed to create Claim %s", claim2)
isSuccessfullyBoundToPool(pool, claim2)
isSuccessfullyBoundAndUnsedToPool(pool, claim2)
claim3 := &capsulev1beta2.ResourcePoolClaim{
ObjectMeta: metav1.ObjectMeta{
@@ -524,7 +524,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
},
},
Spec: capsulev1beta2.ResourcePoolSpec{
Selectors: []misc.NamespaceSelector{
Selectors: []selectors.NamespaceSelector{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
@@ -696,7 +696,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
},
},
Spec: capsulev1beta2.ResourcePoolSpec{
Selectors: []misc.NamespaceSelector{
Selectors: []selectors.NamespaceSelector{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
@@ -769,7 +769,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err := k8sClient.Create(context.TODO(), claim)
Expect(err).Should(Succeed(), "Failed to create Claim %s", claim)
isSuccessfullyBoundToPool(pool, claim)
isSuccessfullyBoundAndUnsedToPool(pool, claim)
})
By("Verify Status was correctly initialized", func() {
@@ -834,16 +834,16 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err = k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
conditions := extractResourcePoolMessage(claim.Status.Condition.Message)
expected := []string{
"requested.requests.cpu=4",
"available.requests.cpu=2",
}
Expect(containsAll(conditions, expected)).To(BeTrue(), "Actual message"+claim.Status.Condition.Message)
Expect(claim.Status.Condition.Reason).To(Equal(meta.PoolExhaustedReason))
Expect(claim.Status.Condition.Status).To(Equal(metav1.ConditionFalse))
Expect(claim.Status.Condition.Type).To(Equal(meta.BoundCondition))
exhausted := claim.Status.Conditions.GetConditionByType(meta.ExhaustedCondition)
Expect(containsAll(extractResourcePoolMessage(exhausted.Message), expected)).To(BeTrue(), "Actual message"+exhausted.Message)
Expect(exhausted.Reason).To(Equal(meta.PoolExhaustedReason))
Expect(exhausted.Status).To(Equal(metav1.ConditionTrue))
Expect(exhausted.Type).To(Equal(meta.ExhaustedCondition))
})
By("Create claim for request.memory", func() {
@@ -862,7 +862,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err := k8sClient.Create(context.TODO(), claim)
Expect(err).Should(Succeed(), "Failed to create Claim %s", claim)
isSuccessfullyBoundToPool(pool, claim)
isSuccessfullyBoundAndUnsedToPool(pool, claim)
})
By("Verify Status was correctly initialized", func() {
@@ -905,7 +905,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err := k8sClient.Create(context.TODO(), claim)
Expect(err).Should(Succeed(), "Failed to create Claim %s", claim)
isSuccessfullyBoundToPool(pool, claim)
isSuccessfullyBoundAndUnsedToPool(pool, claim)
})
By("Verify Status was correctly initialized", func() {
@@ -942,16 +942,15 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err = k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
conditions := extractResourcePoolMessage(claim.Status.Condition.Message)
exhausted := claim.Status.Conditions.GetConditionByType(meta.ExhaustedCondition)
expected := []string{
"requested.requests.cpu=4",
"available.requests.cpu=0",
}
Expect(containsAll(conditions, expected)).To(BeTrue(), "Actual message"+claim.Status.Condition.Message)
Expect(claim.Status.Condition.Reason).To(Equal(meta.PoolExhaustedReason))
Expect(claim.Status.Condition.Status).To(Equal(metav1.ConditionFalse))
Expect(claim.Status.Condition.Type).To(Equal(meta.BoundCondition))
Expect(containsAll(extractResourcePoolMessage(exhausted.Message), expected)).To(BeTrue(), "Actual message"+claim.Status.Condition.Message)
Expect(exhausted.Reason).To(Equal(meta.PoolExhaustedReason))
Expect(exhausted.Status).To(Equal(metav1.ConditionTrue))
})
})
@@ -964,7 +963,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
},
},
Spec: capsulev1beta2.ResourcePoolSpec{
Selectors: []misc.NamespaceSelector{
Selectors: []selectors.NamespaceSelector{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
@@ -1037,7 +1036,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err := k8sClient.Create(context.TODO(), claim)
Expect(err).Should(Succeed(), "Failed to create Claim %s", claim)
isSuccessfullyBoundToPool(pool, claim)
isSuccessfullyBoundAndUnsedToPool(pool, claim)
})
By("Create claim for requests.requests", func() {
@@ -1056,7 +1055,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err := k8sClient.Create(context.TODO(), claim)
Expect(err).Should(Succeed(), "Failed to create Claim %s", claim)
isSuccessfullyBoundToPool(pool, claim)
isSuccessfullyBoundAndUnsedToPool(pool, claim)
})
By("Verify Status was correctly initialized", func() {
@@ -1104,16 +1103,15 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err = k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
conditions := extractResourcePoolMessage(claim.Status.Condition.Message)
exhausted := claim.Status.Conditions.GetConditionByType(meta.ExhaustedCondition)
expected := []string{
"requested.requests.cpu=4",
"available.requests.cpu=2",
}
Expect(containsAll(conditions, expected)).To(BeTrue(), "Actual message"+claim.Status.Condition.Message)
Expect(claim.Status.Condition.Reason).To(Equal(meta.PoolExhaustedReason))
Expect(claim.Status.Condition.Status).To(Equal(metav1.ConditionFalse))
Expect(claim.Status.Condition.Type).To(Equal(meta.BoundCondition))
Expect(containsAll(extractResourcePoolMessage(exhausted.Message), expected)).To(BeTrue(), "Actual message"+exhausted.Message)
Expect(exhausted.Reason).To(Equal(meta.PoolExhaustedReason))
Expect(exhausted.Status).To(Equal(metav1.ConditionTrue))
})
By("Create claim exhausting limits.cpu", func() {
@@ -1137,16 +1135,15 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err = k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
conditions := extractResourcePoolMessage(claim.Status.Condition.Message)
exhausted := claim.Status.Conditions.GetConditionByType(meta.ExhaustedCondition)
expected := []string{
"requested.limits.cpu=4",
"available.limits.cpu=2",
}
Expect(containsAll(conditions, expected)).To(BeTrue(), "Actual message"+claim.Status.Condition.Message)
Expect(claim.Status.Condition.Reason).To(Equal(meta.PoolExhaustedReason))
Expect(claim.Status.Condition.Status).To(Equal(metav1.ConditionFalse))
Expect(claim.Status.Condition.Type).To(Equal(meta.BoundCondition))
Expect(containsAll(extractResourcePoolMessage(exhausted.Message), expected)).To(BeTrue(), "Actual message"+exhausted.Message)
Expect(exhausted.Reason).To(Equal(meta.PoolExhaustedReason))
Expect(exhausted.Status).To(Equal(metav1.ConditionTrue))
})
By("Create claim for requests.cpu (attempt to skip exhausting one)", func() {
@@ -1171,7 +1168,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err = k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
conditions := extractResourcePoolMessage(claim.Status.Condition.Message)
exhausted := claim.Status.Conditions.GetConditionByType(meta.ExhaustedCondition)
expected := []string{
"requested.limits.cpu=2",
"queued.limits.cpu=4",
@@ -1179,10 +1176,9 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
"queued.requests.cpu=4",
}
Expect(containsAll(conditions, expected)).To(BeTrue(), "Actual message"+claim.Status.Condition.Message)
Expect(claim.Status.Condition.Reason).To(Equal(meta.QueueExhaustedReason))
Expect(claim.Status.Condition.Status).To(Equal(metav1.ConditionFalse))
Expect(claim.Status.Condition.Type).To(Equal(meta.BoundCondition))
Expect(containsAll(extractResourcePoolMessage(exhausted.Message), expected)).To(BeTrue(), "Actual message"+exhausted.Message)
Expect(exhausted.Reason).To(Equal(meta.QueueExhaustedReason))
Expect(exhausted.Status).To(Equal(metav1.ConditionTrue))
})
By("Verify ResourceQuotas for namespaces", func() {
@@ -1257,7 +1253,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "simple-2", Namespace: "ns-2-pool-ordered"}, claim)
Expect(err).Should(Succeed(), "Failed to create Claim %s", claim)
isSuccessfullyBoundToPool(pool, claim)
isSuccessfullyBoundAndUnsedToPool(pool, claim)
})
By("Verify queued claim can be allocated", func() {
@@ -1266,7 +1262,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "simple-3", Namespace: "ns-1-pool-ordered"}, claim)
Expect(err).Should(Succeed(), "Failed to create Claim %s", claim)
isSuccessfullyBoundToPool(pool, claim)
isSuccessfullyBoundAndUnsedToPool(pool, claim)
})
By("Verify ResourceQuotas for namespaces", func() {
@@ -1309,7 +1305,8 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err = k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
conditions := extractResourcePoolMessage(claim.Status.Condition.Message)
exhausted := claim.Status.Conditions.GetConditionByType(meta.ExhaustedCondition)
expected := []string{
"requested.limits.cpu=2",
"available.limits.cpu=0",
@@ -1317,10 +1314,9 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
"available.requests.cpu=0",
}
Expect(containsAll(conditions, expected)).To(BeTrue(), "Actual message"+claim.Status.Condition.Message)
Expect(claim.Status.Condition.Reason).To(Equal(meta.PoolExhaustedReason))
Expect(claim.Status.Condition.Status).To(Equal(metav1.ConditionFalse))
Expect(claim.Status.Condition.Type).To(Equal(meta.BoundCondition))
Expect(containsAll(extractResourcePoolMessage(exhausted.Message), expected)).To(BeTrue(), "Actual message"+exhausted.Message)
Expect(exhausted.Reason).To(Equal(meta.PoolExhaustedReason))
Expect(exhausted.Status).To(Equal(metav1.ConditionTrue))
})
})
@@ -1333,7 +1329,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
},
},
Spec: capsulev1beta2.ResourcePoolSpec{
Selectors: []misc.NamespaceSelector{
Selectors: []selectors.NamespaceSelector{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
@@ -1414,14 +1410,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err := k8sClient.Create(context.TODO(), claim)
Expect(err).Should(Succeed(), "Failed to create Claim %s", claim)
isSuccessfullyBoundToPool(pool, claim)
err = k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
Expect(claim.Status.Condition.Reason).To(Equal(meta.SucceededReason))
Expect(claim.Status.Condition.Status).To(Equal(metav1.ConditionTrue))
Expect(claim.Status.Condition.Type).To(Equal(meta.BoundCondition))
isSuccessfullyBoundAndUnsedToPool(pool, claim)
})
By("Create claim non matching namespace", func() {
@@ -1446,9 +1435,11 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err = k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
Expect(claim.Status.Condition.Reason).To(Equal(meta.FailedReason))
Expect(claim.Status.Condition.Status).To(Equal(metav1.ConditionFalse))
Expect(claim.Status.Condition.Type).To(Equal(meta.AssignedCondition))
assigned := claim.Status.Conditions.GetConditionByType(meta.ReadyCondition)
Expect(assigned.Reason).To(Equal(meta.FailedReason))
Expect(assigned.Status).To(Equal(metav1.ConditionFalse))
Expect(assigned.Type).To(Equal(meta.ReadyCondition))
})
By("Update Namespace Labels to become matching", func() {
@@ -1477,7 +1468,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err := k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
isSuccessfullyBoundToPool(pool, claim)
isSuccessfullyBoundAndUnsedToPool(pool, claim)
})
})
@@ -1491,7 +1482,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
},
},
Spec: capsulev1beta2.ResourcePoolSpec{
Selectors: []misc.NamespaceSelector{
Selectors: []selectors.NamespaceSelector{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
@@ -1599,7 +1590,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
},
},
Spec: capsulev1beta2.ResourcePoolSpec{
Selectors: []misc.NamespaceSelector{
Selectors: []selectors.NamespaceSelector{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
@@ -1707,7 +1698,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
},
},
Spec: capsulev1beta2.ResourcePoolSpec{
Selectors: []misc.NamespaceSelector{
Selectors: []selectors.NamespaceSelector{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
@@ -1779,14 +1770,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err := k8sClient.Create(context.TODO(), claim)
Expect(err).Should(Succeed(), "Failed to create Claim %s", claim)
isSuccessfullyBoundToPool(pool, claim)
err = k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
Expect(claim.Status.Condition.Reason).To(Equal(meta.SucceededReason))
Expect(claim.Status.Condition.Status).To(Equal(metav1.ConditionTrue))
Expect(claim.Status.Condition.Type).To(Equal(meta.BoundCondition))
isSuccessfullyBoundAndUnsedToPool(pool, claim)
})
By("Create claims", func() {
@@ -1805,14 +1789,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
err := k8sClient.Create(context.TODO(), claim)
Expect(err).Should(Succeed(), "Failed to create Claim %s", claim)
isSuccessfullyBoundToPool(pool, claim)
err = k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
Expect(claim.Status.Condition.Reason).To(Equal(meta.SucceededReason))
Expect(claim.Status.Condition.Status).To(Equal(metav1.ConditionTrue))
Expect(claim.Status.Condition.Type).To(Equal(meta.BoundCondition))
isSuccessfullyBoundAndUnsedToPool(pool, claim)
})
By("Verify ResourcePool Status Allocation", func() {
@@ -2026,7 +2003,7 @@ var _ = Describe("ResourcePool Tests", Label("resourcepool"), func() {
})
})
func isSuccessfullyBoundToPool(pool *capsulev1beta2.ResourcePool, claim *capsulev1beta2.ResourcePoolClaim) {
func isSuccessfullyBoundAndUnsedToPool(pool *capsulev1beta2.ResourcePool, claim *capsulev1beta2.ResourcePoolClaim) {
fetchedPool := &capsulev1beta2.ResourcePool{}
err := k8sClient.Get(context.TODO(), client.ObjectKey{Name: pool.Name}, fetchedPool)
Expect(err).Should(Succeed())
@@ -2040,9 +2017,32 @@ func isSuccessfullyBoundToPool(pool *capsulev1beta2.ResourcePool, claim *capsule
Expect(fetchedClaim.Status.Pool.Name.String()).To(Equal(fetchedPool.Name))
Expect(fetchedClaim.Status.Pool.UID).To(Equal(fetchedPool.GetUID()))
Expect(fetchedClaim.Status.Condition.Type).To(Equal(meta.BoundCondition))
Expect(fetchedClaim.Status.Condition.Status).To(Equal(metav1.ConditionTrue))
Expect(fetchedClaim.Status.Condition.Reason).To(Equal(meta.SucceededReason))
bound := fetchedClaim.Status.Conditions.GetConditionByType(meta.BoundCondition)
Expect(bound.Type).To(Equal(meta.BoundCondition))
Expect(bound.Status).To(Equal(metav1.ConditionFalse))
Expect(bound.Reason).To(Equal(meta.UnusedReason))
}
func isSuccessfullyBoundAndUsedToPool(pool *capsulev1beta2.ResourcePool, claim *capsulev1beta2.ResourcePoolClaim) {
fetchedPool := &capsulev1beta2.ResourcePool{}
err := k8sClient.Get(context.TODO(), client.ObjectKey{Name: pool.Name}, fetchedPool)
Expect(err).Should(Succeed())
fetchedClaim := &capsulev1beta2.ResourcePoolClaim{}
err = k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, fetchedClaim)
Expect(err).Should(Succeed())
isBoundToPool(fetchedPool, fetchedClaim)
Expect(fetchedClaim.Status.Pool.Name.String()).To(Equal(fetchedPool.Name))
Expect(fetchedClaim.Status.Pool.UID).To(Equal(fetchedPool.GetUID()))
bound := fetchedClaim.Status.Conditions.GetConditionByType(meta.BoundCondition)
Expect(bound.Type).To(Equal(meta.BoundCondition))
Expect(bound.Status).To(Equal(metav1.ConditionTrue))
Expect(bound.Reason).To(Equal(meta.InUseReason))
}
func isBoundToPool(pool *capsulev1beta2.ResourcePool, claim *capsulev1beta2.ResourcePoolClaim) bool {

View File

@@ -5,10 +5,12 @@ package e2e
import (
"context"
"time"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
@@ -17,7 +19,7 @@ import (
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
"github.com/projectcapsule/capsule/pkg/api"
"github.com/projectcapsule/capsule/pkg/api/meta"
"github.com/projectcapsule/capsule/pkg/api/misc"
"github.com/projectcapsule/capsule/pkg/runtime/selectors"
)
var _ = Describe("ResourcePoolClaim Tests", Label("resourcepool"), func() {
@@ -102,7 +104,7 @@ var _ = Describe("ResourcePoolClaim Tests", Label("resourcepool"), func() {
},
},
Spec: capsulev1beta2.ResourcePoolSpec{
Selectors: []misc.NamespaceSelector{
Selectors: []selectors.NamespaceSelector{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
@@ -230,16 +232,7 @@ var _ = Describe("ResourcePoolClaim Tests", Label("resourcepool"), func() {
err = k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim1.Name, Namespace: claim1.Namespace}, claim1)
Expect(err).Should(Succeed())
isSuccessfullyBoundToPool(pool1, claim1)
expectedPool := api.StatusNameUID{
Name: api.Name(pool1.Name),
UID: pool1.GetUID(),
}
Expect(claim1.Status.Pool).To(Equal(expectedPool), "expected pool name to match")
Expect(claim1.Status.Condition.Status).To(Equal(metav1.ConditionTrue), "failed to verify condition status")
Expect(claim1.Status.Condition.Type).To(Equal(meta.BoundCondition), "failed to verify condition type")
Expect(claim1.Status.Condition.Reason).To(Equal(meta.SucceededReason), "failed to verify condition reason")
isSuccessfullyBoundAndUnsedToPool(pool1, claim1)
})
By("Create a second claim and verify binding", func() {
@@ -249,16 +242,7 @@ var _ = Describe("ResourcePoolClaim Tests", Label("resourcepool"), func() {
err = k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim2.Name, Namespace: claim2.Namespace}, claim2)
Expect(err).Should(Succeed())
isSuccessfullyBoundToPool(pool1, claim2)
expectedPool := api.StatusNameUID{
Name: api.Name(pool1.Name),
UID: pool1.GetUID(),
}
Expect(claim2.Status.Pool).To(Equal(expectedPool), "expected pool name to match")
Expect(claim2.Status.Condition.Status).To(Equal(metav1.ConditionTrue), "failed to verify condition status")
Expect(claim2.Status.Condition.Type).To(Equal(meta.BoundCondition), "failed to verify condition type")
Expect(claim2.Status.Condition.Reason).To(Equal(meta.SucceededReason), "failed to verify condition reason")
isSuccessfullyBoundAndUnsedToPool(pool1, claim2)
})
By("Create a third claim and verify error", func() {
@@ -284,12 +268,15 @@ var _ = Describe("ResourcePoolClaim Tests", Label("resourcepool"), func() {
err = k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
expectedPool := api.StatusNameUID{}
expectedPool := meta.LocalRFC1123ObjectReferenceWithUID{}
Expect(claim.Status.Pool).To(Equal(expectedPool), "expected pool name to be empty")
Expect(claim.Status.Condition.Status).To(Equal(metav1.ConditionFalse), "failed to verify condition status")
Expect(claim.Status.Condition.Type).To(Equal(meta.AssignedCondition), "failed to verify condition type")
Expect(claim.Status.Condition.Reason).To(Equal(meta.FailedReason), "failed to verify condition reason")
Expect(len(claim.Status.Conditions)).To(Equal(1), "expected single condition")
Expect(len(claim.OwnerReferences)).To(Equal(0), "expected no ownerreferences")
assigned := claim.Status.Conditions.GetConditionByType(meta.ReadyCondition)
Expect(assigned.Status).To(Equal(metav1.ConditionFalse), "failed to verify condition status")
Expect(assigned.Type).To(Equal(meta.ReadyCondition), "failed to verify condition type")
Expect(assigned.Reason).To(Equal(meta.FailedReason), "failed to verify condition reason")
})
})
@@ -305,7 +292,7 @@ var _ = Describe("ResourcePoolClaim Tests", Label("resourcepool"), func() {
Config: capsulev1beta2.ResourcePoolSpecConfiguration{
DeleteBoundResources: ptr.To(false),
},
Selectors: []misc.NamespaceSelector{
Selectors: []selectors.NamespaceSelector{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
@@ -373,20 +360,56 @@ var _ = Describe("ResourcePoolClaim Tests", Label("resourcepool"), func() {
err := k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
expectedPool := api.StatusNameUID{
Name: api.Name(pool.Name),
expectedPool := meta.LocalRFC1123ObjectReferenceWithUID{
Name: meta.RFC1123Name(pool.Name),
UID: pool.GetUID(),
}
isBoundCondition(claim)
isBoundAndUnusedCondition(claim)
Expect(claim.Status.Pool).To(Equal(expectedPool), "expected pool name to match")
})
By("Error on deleting bound claim", func() {
By("Create a pod with resource requests/limits", func() {
pod := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "claim-pod",
Namespace: claim.Namespace,
Labels: map[string]string{
"e2e": "claim-pod",
},
},
Spec: corev1.PodSpec{
// optional: helps schedule quickly, avoid restarts
RestartPolicy: corev1.RestartPolicyNever,
Containers: []corev1.Container{
{
Name: "pause",
Image: "registry.k8s.io/pause:3.9",
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("10m"),
corev1.ResourceMemory: resource.MustParse("16Mi"),
},
Limits: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("20m"),
corev1.ResourceMemory: resource.MustParse("32Mi"),
},
},
},
},
},
}
Expect(k8sClient.Create(context.TODO(), pod)).To(Succeed())
})
By("Verify the claim is used", func() {
time.Sleep(250 * time.Millisecond)
err := k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
isBoundCondition(claim)
isBoundAndUsedCondition(claim)
err = k8sClient.Delete(context.TODO(), claim)
Expect(err).ShouldNot(Succeed())
@@ -432,6 +455,82 @@ var _ = Describe("ResourcePoolClaim Tests", Label("resourcepool"), func() {
Expect(err).ShouldNot(Succeed(), "Expected error when updating resources in bound state %s", claim)
})
By("Make the claim unused", func() {
key := client.ObjectKey{Name: "claim-pod", Namespace: claim.Namespace}
pod := &corev1.Pod{}
err := k8sClient.Get(context.TODO(), key, pod)
Expect(err).To(Succeed(), "pod must exist before deleting")
Expect(k8sClient.Delete(context.TODO(), pod, &client.DeleteOptions{
GracePeriodSeconds: ptr.To(int64(0)),
})).To(Succeed())
Eventually(func() bool {
p := &corev1.Pod{}
err := k8sClient.Get(
context.TODO(),
key,
p,
)
return apierrors.IsNotFound(err)
}, defaultTimeoutInterval, defaultPollInterval).Should(BeTrue())
})
By("Bind a claim", func() {
err := k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
expectedPool := meta.LocalRFC1123ObjectReferenceWithUID{
Name: meta.RFC1123Name(pool.Name),
UID: pool.GetUID(),
}
isBoundAndUnusedCondition(claim)
Expect(claim.Status.Pool).To(Equal(expectedPool), "expected pool name to match")
})
By("Allow on patching resources for claim (Increase)", func() {
err := k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
claim.Spec.ResourceClaims = corev1.ResourceList{
corev1.ResourceLimitsCPU: resource.MustParse("2"),
corev1.ResourceLimitsMemory: resource.MustParse("2Gi"),
corev1.ResourceRequestsCPU: resource.MustParse("2"),
corev1.ResourceRequestsMemory: resource.MustParse("2Gi"),
}
err = k8sClient.Update(context.TODO(), claim)
Expect(err).Should(Succeed(), "Expected error when updating resources in bound state %s", claim)
})
By("Allow on patching resources for claim (Decrease)", func() {
err := k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
claim.Spec.ResourceClaims = corev1.ResourceList{
corev1.ResourceLimitsCPU: resource.MustParse("0"),
corev1.ResourceLimitsMemory: resource.MustParse("0Gi"),
corev1.ResourceRequestsCPU: resource.MustParse("0"),
corev1.ResourceRequestsMemory: resource.MustParse("0Gi"),
}
err = k8sClient.Update(context.TODO(), claim)
Expect(err).Should(Succeed(), "Expected error when updating resources in bound state %s", claim)
})
By("Allow on patching pool name", func() {
err := k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, claim)
Expect(err).Should(Succeed())
claim.Spec.Pool = "some-random-pool"
err = k8sClient.Update(context.TODO(), claim)
Expect(err).Should(Succeed(), "Expected error when updating resources in bound state %s", claim)
})
By("Delete Pool", func() {
err := k8sClient.Delete(context.TODO(), pool)
Expect(err).Should(Succeed())
@@ -495,7 +594,7 @@ var _ = Describe("ResourcePoolClaim Tests", Label("resourcepool"), func() {
Config: capsulev1beta2.ResourcePoolSpecConfiguration{
DeleteBoundResources: ptr.To(false),
},
Selectors: []misc.NamespaceSelector{
Selectors: []selectors.NamespaceSelector{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
@@ -524,7 +623,7 @@ var _ = Describe("ResourcePoolClaim Tests", Label("resourcepool"), func() {
Config: capsulev1beta2.ResourcePoolSpecConfiguration{
DeleteBoundResources: ptr.To(false),
},
Selectors: []misc.NamespaceSelector{
Selectors: []selectors.NamespaceSelector{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
@@ -666,17 +765,33 @@ func isUnassignedCondition(claim *capsulev1beta2.ResourcePoolClaim) {
err := k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, cl)
Expect(err).Should(Succeed())
Expect(cl.Status.Condition.Status).To(Equal(metav1.ConditionFalse), "failed to verify condition status")
Expect(cl.Status.Condition.Type).To(Equal(meta.AssignedCondition), "failed to verify condition type")
Expect(cl.Status.Condition.Reason).To(Equal(meta.FailedReason), "failed to verify condition reason")
assigned := cl.Status.Conditions.GetConditionByType(meta.ReadyCondition)
Expect(assigned.Status).To(Equal(metav1.ConditionFalse), "failed to verify condition status")
Expect(assigned.Type).To(Equal(meta.ReadyCondition), "failed to verify condition type")
Expect(assigned.Reason).To(Equal(meta.FailedReason), "failed to verify condition reason")
}
func isBoundCondition(claim *capsulev1beta2.ResourcePoolClaim) {
func isBoundAndUnusedCondition(claim *capsulev1beta2.ResourcePoolClaim) {
cl := &capsulev1beta2.ResourcePoolClaim{}
err := k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, cl)
Expect(err).Should(Succeed())
Expect(cl.Status.Condition.Status).To(Equal(metav1.ConditionTrue), "failed to verify condition status")
Expect(cl.Status.Condition.Type).To(Equal(meta.BoundCondition), "failed to verify condition type")
Expect(cl.Status.Condition.Reason).To(Equal(meta.SucceededReason), "failed to verify condition reason")
bound := cl.Status.Conditions.GetConditionByType(meta.BoundCondition)
Expect(bound.Type).To(Equal(meta.BoundCondition), "failed to verify condition type")
Expect(bound.Reason).To(Equal(meta.UnusedReason), "failed to verify condition reason")
Expect(bound.Status).To(Equal(metav1.ConditionFalse), "failed to verify condition status")
}
func isBoundAndUsedCondition(claim *capsulev1beta2.ResourcePoolClaim) {
cl := &capsulev1beta2.ResourcePoolClaim{}
err := k8sClient.Get(context.TODO(), client.ObjectKey{Name: claim.Name, Namespace: claim.Namespace}, cl)
Expect(err).Should(Succeed())
bound := cl.Status.Conditions.GetConditionByType(meta.BoundCondition)
Expect(bound.Status).To(Equal(metav1.ConditionTrue), "failed to verify condition status")
Expect(bound.Type).To(Equal(meta.BoundCondition), "failed to verify condition type")
Expect(bound.Reason).To(Equal(meta.InUseReason), "failed to verify condition reason")
}

View File

@@ -119,7 +119,7 @@ var _ = Describe("Promoting ServiceAccounts to Owners", Label("config"), Label("
if saCopy.Labels == nil {
saCopy.Labels = map[string]string{}
}
saCopy.Labels[meta.OwnerPromotionLabel] = meta.OwnerPromotionLabelTrigger
saCopy.Labels[meta.OwnerPromotionLabel] = meta.ValueTrue
return tc.client.Update(context.TODO(), saCopy)
}, defaultTimeoutInterval, defaultPollInterval).Should(tc.matcher, "persona=%s", name)
@@ -212,7 +212,7 @@ var _ = Describe("Promoting ServiceAccounts to Owners", Label("config"), Label("
if saCopy.Labels == nil {
saCopy.Labels = map[string]string{}
}
saCopy.Labels[meta.OwnerPromotionLabel] = meta.OwnerPromotionLabelTrigger
saCopy.Labels[meta.OwnerPromotionLabel] = meta.ValueTrue
return tc.client.Update(context.TODO(), saCopy)
}, defaultTimeoutInterval, defaultPollInterval).Should(tc.matcher, "persona=%s", name)
@@ -271,7 +271,7 @@ var _ = Describe("Promoting ServiceAccounts to Owners", Label("config"), Label("
if saCopy.Labels == nil {
saCopy.Labels = map[string]string{}
}
saCopy.Labels[meta.OwnerPromotionLabel] = meta.OwnerPromotionLabelTrigger
saCopy.Labels[meta.OwnerPromotionLabel] = meta.ValueTrue
return tc.client.Update(context.TODO(), saCopy)
}, defaultTimeoutInterval, defaultPollInterval).Should(tc.matcher, "persona=%s", name)

View File

@@ -9,6 +9,7 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
@@ -49,6 +50,7 @@ var _ = Describe("verify scalability", Label("scalability"), func() {
It("verify lifecycle (scalability)", func() {
const amount = 50
const podsPerNamespace int32 = 1
getTenant := func() *capsulev1beta2.Tenant {
t := &capsulev1beta2.Tenant{}
@@ -123,6 +125,15 @@ var _ = Describe("verify scalability", Label("scalability"), func() {
waitSize(uint(i + 1))
waitInstancePresent(ns)
// --- NEW: create low-impact traffic pods in the namespace ---
dep := newTrafficDeployment(ns.GetName(), podsPerNamespace)
EventuallyCreation(func() error {
return k8sClient.Create(context.TODO(), dep)
}).Should(Succeed())
// Wait until pods are actually scheduled & ready
waitDeploymentReady(context.TODO(), ns.GetName(), dep.Name, podsPerNamespace)
namespaces = append(namespaces, ns)
}
@@ -139,3 +150,56 @@ var _ = Describe("verify scalability", Label("scalability"), func() {
})
})
func newTrafficDeployment(ns string, replicas int32) *appsv1.Deployment {
labels := map[string]string{"app": "traffic-pause"}
return &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "traffic-pause",
Namespace: ns,
},
Spec: appsv1.DeploymentSpec{
Replicas: &replicas,
Selector: &metav1.LabelSelector{MatchLabels: labels},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{Labels: labels},
Spec: corev1.PodSpec{
// pause container keeps footprint tiny
Containers: []corev1.Container{
{
Name: "pause",
Image: "registry.k8s.io/pause:3.9",
// No resources specified => requests/limits default to zero.
// Resources: corev1.ResourceRequirements{},
},
},
},
},
},
}
}
func scaleDeployment(ctx context.Context, ns, name string, replicas int32) {
Eventually(func() error {
d := &appsv1.Deployment{}
if err := k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: name}, d); err != nil {
return err
}
*d.Spec.Replicas = replicas
return k8sClient.Update(ctx, d)
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
waitDeploymentReady(ctx, ns, name, replicas)
}
func waitDeploymentReady(ctx context.Context, ns, name string, replicas int32) {
Eventually(func() (int32, error) {
d := &appsv1.Deployment{}
err := k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: name}, d)
if err != nil {
return 0, err
}
return d.Status.ReadyReplicas, nil
}, defaultTimeoutInterval, defaultPollInterval).Should(Equal(replicas))
}

View File

@@ -21,7 +21,7 @@ import (
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
)
var _ = Describe("changing Tenant managed Kubernetes resources", Label("tenant"), func() {
var _ = Describe("changing Tenant managed Kubernetes resources", Label("tenant", "managed", "current"), func() {
tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-resources-changes",
@@ -184,6 +184,10 @@ var _ = Describe("changing Tenant managed Kubernetes resources", Label("tenant")
return k8sClient.Get(context.TODO(), types.NamespacedName{Name: n, Namespace: ns}, lr)
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
cs := ownerClient(tnt.Spec.Owners[0].UserSpec)
err := cs.CoreV1().LimitRanges(ns).Delete(context.TODO(), n, metav1.DeleteOptions{})
Expect(err).To(HaveOccurred())
c := lr.DeepCopy()
c.Spec.Limits = []corev1.LimitRangeItem{}
Expect(k8sClient.Update(context.TODO(), c, &client.UpdateOptions{})).Should(Succeed())
@@ -203,6 +207,10 @@ var _ = Describe("changing Tenant managed Kubernetes resources", Label("tenant")
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
Expect(np.Spec).Should(Equal(s))
cs := ownerClient(tnt.Spec.Owners[0].UserSpec)
err := cs.NetworkingV1().NetworkPolicies(ns).Delete(context.TODO(), n, metav1.DeleteOptions{})
Expect(err).To(HaveOccurred())
c := np.DeepCopy()
c.Spec.Egress = []networkingv1.NetworkPolicyEgressRule{}
c.Spec.Ingress = []networkingv1.NetworkPolicyIngressRule{}
@@ -222,6 +230,10 @@ var _ = Describe("changing Tenant managed Kubernetes resources", Label("tenant")
return k8sClient.Get(context.TODO(), types.NamespacedName{Name: n, Namespace: ns}, rq)
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
cs := ownerClient(tnt.Spec.Owners[0].UserSpec)
err := cs.CoreV1().ResourceQuotas(ns).Delete(context.TODO(), n, metav1.DeleteOptions{})
Expect(err).To(HaveOccurred())
c := rq.DeepCopy()
c.Spec.Hard = map[corev1.ResourceName]resource.Quantity{}
Expect(k8sClient.Update(context.TODO(), c, &client.UpdateOptions{})).Should(Succeed())