mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-02-14 09:59:57 +00:00
* feat: functional appsets * feat(api): add resourcepools api Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: fix gomod Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: correct webhooks Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: fix harpoon image Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: improve e2e Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: add labels to e2e test Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: fix status handling Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: fix racing conditions Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: make values compatible Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: fix custom resources test Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: correct metrics Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> --------- Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
198 lines
5.2 KiB
Go
198 lines
5.2 KiB
Go
// 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"
|
|
corev1 "k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/api/resource"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/types"
|
|
"k8s.io/utils/ptr"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
|
|
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
|
|
)
|
|
|
|
var _ = Describe("preventing PersistentVolume cross-tenant mount", Label("tenant", "storage"), func() {
|
|
tnt1 := &capsulev1beta2.Tenant{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "pv-one",
|
|
},
|
|
Spec: capsulev1beta2.TenantSpec{
|
|
Owners: capsulev1beta2.OwnerListSpec{
|
|
{
|
|
Name: "jessica",
|
|
Kind: "User",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
tnt2 := &capsulev1beta2.Tenant{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "pv-two",
|
|
},
|
|
Spec: capsulev1beta2.TenantSpec{
|
|
Owners: capsulev1beta2.OwnerListSpec{
|
|
{
|
|
Name: "leto",
|
|
Kind: "User",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
JustBeforeEach(func() {
|
|
for _, tnt := range []*capsulev1beta2.Tenant{tnt1, tnt2} {
|
|
EventuallyCreation(func() error {
|
|
tnt.ResourceVersion = ""
|
|
|
|
return k8sClient.Create(context.TODO(), tnt)
|
|
}).Should(Succeed())
|
|
}
|
|
})
|
|
|
|
JustAfterEach(func() {
|
|
for _, tnt := range []*capsulev1beta2.Tenant{tnt1, tnt2} {
|
|
Expect(k8sClient.Delete(context.TODO(), tnt)).Should(Succeed())
|
|
}
|
|
})
|
|
|
|
It("should add labels to PersistentVolume and prevent cross-Tenant mount", func() {
|
|
ns := NewNamespace("")
|
|
NamespaceCreation(ns, tnt1.Spec.Owners[0], defaultTimeoutInterval).Should(Succeed())
|
|
TenantNamespaceList(tnt1, defaultTimeoutInterval).Should(ContainElement(ns.Name))
|
|
|
|
pvc := corev1.PersistentVolumeClaim{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "arrakis",
|
|
Namespace: ns.Name,
|
|
},
|
|
Spec: corev1.PersistentVolumeClaimSpec{
|
|
AccessModes: []corev1.PersistentVolumeAccessMode{
|
|
corev1.ReadWriteOnce,
|
|
},
|
|
Resources: corev1.VolumeResourceRequirements{
|
|
Requests: corev1.ResourceList{
|
|
corev1.ResourceStorage: resource.MustParse("1Gi"),
|
|
},
|
|
},
|
|
StorageClassName: ptr.To("standard"),
|
|
},
|
|
}
|
|
|
|
EventuallyCreation(func() error {
|
|
return k8sClient.Create(context.Background(), &pvc)
|
|
}).Should(Succeed())
|
|
|
|
pod := corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "arrakis-pod",
|
|
Namespace: ns.Name,
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: "container",
|
|
Image: "gcr.io/google_containers/pause-amd64:3.0",
|
|
ImagePullPolicy: corev1.PullAlways,
|
|
VolumeMounts: []corev1.VolumeMount{
|
|
{
|
|
Name: "data",
|
|
MountPath: "/tmp",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Volumes: []corev1.Volume{
|
|
{
|
|
Name: "data",
|
|
VolumeSource: corev1.VolumeSource{
|
|
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
|
|
ClaimName: pvc.Name,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
EventuallyCreation(func() error {
|
|
return k8sClient.Create(context.Background(), &pod)
|
|
}).Should(Succeed())
|
|
|
|
Eventually(func() int {
|
|
nsName := types.NamespacedName{Name: pvc.Name, Namespace: pvc.Namespace}
|
|
|
|
if err := k8sClient.Get(context.Background(), nsName, &pvc); err != nil {
|
|
return 0
|
|
}
|
|
|
|
return len(pvc.Spec.VolumeName)
|
|
}, defaultTimeoutInterval, defaultPollInterval).Should(BeNumerically(">", 0))
|
|
|
|
pv := corev1.PersistentVolume{}
|
|
defer func() {
|
|
_ = k8sClient.Delete(context.Background(), &pv)
|
|
}()
|
|
|
|
Eventually(func() string {
|
|
if err := k8sClient.Get(context.Background(), types.NamespacedName{Name: pvc.Spec.VolumeName}, &pv); err != nil {
|
|
return "not-found"
|
|
}
|
|
|
|
if pv.GetLabels() == nil {
|
|
return "no-labels"
|
|
}
|
|
|
|
return pv.GetLabels()["capsule.clastix.io/tenant"]
|
|
}, defaultTimeoutInterval, defaultPollInterval).Should(Equal(tnt1.Name))
|
|
|
|
Eventually(func() error {
|
|
nsName := types.NamespacedName{Name: pv.Name}
|
|
|
|
if err := k8sClient.Get(context.Background(), nsName, &pv); err != nil {
|
|
return err
|
|
}
|
|
|
|
pv.Spec.PersistentVolumeReclaimPolicy = corev1.PersistentVolumeReclaimRecycle
|
|
|
|
return k8sClient.Update(context.Background(), &pv)
|
|
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
|
|
|
|
Expect(k8sClient.Delete(context.Background(), &pod, &client.DeleteOptions{GracePeriodSeconds: ptr.To(int64(0))})).ToNot(HaveOccurred())
|
|
|
|
ns2 := NewNamespace("")
|
|
NamespaceCreation(ns2, tnt2.Spec.Owners[0], defaultTimeoutInterval).Should(Succeed())
|
|
TenantNamespaceList(tnt2, defaultTimeoutInterval).Should(ContainElement(ns2.Name))
|
|
|
|
Consistently(func() error {
|
|
pvc := corev1.PersistentVolumeClaim{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "caladan",
|
|
Namespace: ns2.Name,
|
|
},
|
|
Spec: corev1.PersistentVolumeClaimSpec{
|
|
AccessModes: []corev1.PersistentVolumeAccessMode{
|
|
corev1.ReadWriteOnce,
|
|
},
|
|
Resources: corev1.VolumeResourceRequirements{
|
|
Requests: corev1.ResourceList{
|
|
corev1.ResourceStorage: resource.MustParse("1Gi"),
|
|
},
|
|
},
|
|
StorageClassName: ptr.To("standard"),
|
|
VolumeName: pv.Name,
|
|
},
|
|
}
|
|
|
|
return k8sClient.Create(context.Background(), &pvc)
|
|
}, defaultTimeoutInterval, defaultPollInterval).Should(HaveOccurred())
|
|
})
|
|
})
|