containerized-data-importer/tests/rbac_test.go
Bartosz Rybacki ab48911b9b
WaitForFirstConsumer handling for DataVolumes (#1242)
* Set the WaitForFirstConsumer phase on DataVolume when storage uses the WaitForFirstConsumer binding mode and is not bound yet.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Skip PVC if not bound in import|clone|upload controllers.

This is done so the VM pod(not the cdi pod) will be the first consumer, and the PVC can be scheduled on the same location as the pod.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

fixup! Skip PVC if not bound in import|clone|upload controllers.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Update importer tests to force bind the PCV by scheduling a pod for pvc, when storage class is wffc.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Update datavolume tests to force bind the PCV by scheduling a pod for pvc, when storage class is wffc.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Update upload controller and upload tests to correctly handle force binding the PCV by scheduling a pod for pvc, when storage class is wffc.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Update clone tests to force bind the PCV by scheduling a pod for pvc when the storage class is wffc.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Update cloner multi-node tests to force bind the PCV by scheduling a pod for pvc when storage class is wffc.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Correct after automerge

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Improve/simplify tests

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Fix error in import test.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Update transport_test,operator_test.go

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Update rbac_test.go and leaderelection_test.go

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Improve Datavolume and PVC Checks for WFFC.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Handle wffc only if feature gate is open - import-controller

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* TEST for Handle wffc only if feature gate is open - import-controller - TEST

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Handle wffc only if feature gate is open - upload-controller with test

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* rename and simplify checks

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* cleanup after rebase

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* update tests after rebase

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* update tests after rebase

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* more cleanups

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Document new WFFC behavior

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Document new HonorWaitForFirstConsumer option

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* update docs according to comments

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* extract common function, cleanup - code review fixes

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* add comment for another pr - 1210, so it can have easier merge/rebase

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* typo

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Simplify getStoragebindingMode - code review comments

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Add FeatureGates interface - code review fix

Additionally pass the features gates instead of the particular feature gate value,
and let shouldReconcilePVC decide what to do with the feature gate. That way shouldReconcilePVC
contains all the logic, and the caller does not need to do additional calls to provide parameters.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Update matcher

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>
2020-07-22 16:23:44 +02:00

280 lines
7.4 KiB
Go

package tests
import (
"reflect"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
cdiClientset "kubevirt.io/containerized-data-importer/pkg/client/clientset/versioned"
"kubevirt.io/containerized-data-importer/tests/framework"
"kubevirt.io/containerized-data-importer/tests/utils"
)
var _ = Describe("Aggregated role in-action tests", func() {
var createServiceAccount = func(client kubernetes.Interface, namespace, name string) {
sa := &corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
}
_, err := client.CoreV1().ServiceAccounts(namespace).Create(sa)
Expect(err).ToNot(HaveOccurred())
}
var createRoleBinding = func(client kubernetes.Interface, clusterRoleName, namespace, serviceAccount string) {
rb := &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: serviceAccount,
},
RoleRef: rbacv1.RoleRef{
Kind: "ClusterRole",
Name: clusterRoleName,
APIGroup: "rbac.authorization.k8s.io",
},
Subjects: []rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: serviceAccount,
Namespace: namespace,
},
},
}
_, err := client.RbacV1().RoleBindings(namespace).Create(rb)
Expect(err).ToNot(HaveOccurred())
}
f := framework.NewFrameworkOrDie("aggregated-role-tests")
DescribeTable("admin/edit datavolume permission checks", func(user string) {
var client *cdiClientset.Clientset
var err error
createServiceAccount(f.K8sClient, f.Namespace.Name, user)
createRoleBinding(f.K8sClient, user, f.Namespace.Name, user)
Eventually(func() error {
client, err = f.GetCdiClientForServiceAccount(f.Namespace.Name, user)
return err
}, 60*time.Second, 2*time.Second).ShouldNot(HaveOccurred())
dv := utils.NewDataVolumeWithHTTPImport("test-"+user, "1Gi", "http://nonexistant.url")
dv, err = client.CdiV1beta1().DataVolumes(f.Namespace.Name).Create(dv)
Expect(err).ToNot(HaveOccurred())
dvl, err := client.CdiV1beta1().DataVolumes(f.Namespace.Name).List(metav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(dvl.Items).To(HaveLen(1))
dv, err = client.CdiV1beta1().DataVolumes(f.Namespace.Name).Get(dv.Name, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
err = client.CdiV1beta1().DataVolumes(f.Namespace.Name).Delete(dv.Name, &metav1.DeleteOptions{})
Expect(err).ToNot(HaveOccurred())
dvl, err = client.CdiV1beta1().DataVolumes(f.Namespace.Name).List(metav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(dvl.Items).To(HaveLen(0))
dv = utils.NewDataVolumeForUpload("upload-test-"+user, "1Gi")
dv, err = client.CdiV1beta1().DataVolumes(f.Namespace.Name).Create(dv)
Expect(err).ToNot(HaveOccurred())
var pvc *corev1.PersistentVolumeClaim
Eventually(func() error {
pvc, err = f.K8sClient.CoreV1().PersistentVolumeClaims(f.Namespace.Name).Get(dv.Name, metav1.GetOptions{})
if err != nil {
return err
}
return nil
}, 90*time.Second, 2*time.Second).ShouldNot(HaveOccurred())
f.ForceBindPvcIfDvIsWaitForFirstConsumer(dv)
found, err := utils.WaitPVCPodStatusRunning(f.K8sClient, pvc)
Expect(err).ToNot(HaveOccurred())
Expect(found).Should(BeTrue())
token, err := utils.RequestUploadToken(client, pvc)
Expect(err).ToNot(HaveOccurred())
Expect(token).ToNot(BeEmpty())
cl, err := client.CdiV1beta1().CDIConfigs().List(metav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(cl.Items).To(HaveLen(1))
cfg, err := client.CdiV1beta1().CDIConfigs().Get(cl.Items[0].Name, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
cfg.Spec.ScratchSpaceStorageClass = &[]string{"foobar"}[0]
cfg, err = client.CdiV1beta1().CDIConfigs().Update(cfg)
Expect(err).To(HaveOccurred())
},
Entry("[test_id:3948]can do everything with admin", "admin"),
Entry("[test_id:3949]can do everything with edit", "edit"),
)
It("[test_id:3950]view datavolume permission checks", func() {
const user = "view"
var client cdiClientset.Interface
var err error
createServiceAccount(f.K8sClient, f.Namespace.Name, user)
createRoleBinding(f.K8sClient, user, f.Namespace.Name, user)
Eventually(func() error {
client, err = f.GetCdiClientForServiceAccount(f.Namespace.Name, user)
return err
}, 60*time.Second, 2*time.Second).ShouldNot(HaveOccurred())
dv := utils.NewDataVolumeWithHTTPImport("test-"+user, "1Gi", "http://nonexistant.url")
dv, err = client.CdiV1beta1().DataVolumes(f.Namespace.Name).Create(dv)
Expect(err).To(HaveOccurred())
dvl, err := client.CdiV1beta1().DataVolumes(f.Namespace.Name).List(metav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(dvl.Items).To(HaveLen(0))
_, err = client.CdiV1beta1().DataVolumes(f.Namespace.Name).Get("test-"+user, metav1.GetOptions{})
Expect(err).To(HaveOccurred())
Expect(k8serrors.IsNotFound(err)).To(BeTrue())
cl, err := client.CdiV1beta1().CDIConfigs().List(metav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(cl.Items).To(HaveLen(1))
cfg, err := client.CdiV1beta1().CDIConfigs().Get(cl.Items[0].Name, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
cfg.Spec.ScratchSpaceStorageClass = &[]string{"foobar"}[0]
cfg, err = client.CdiV1beta1().CDIConfigs().Update(cfg)
Expect(err).To(HaveOccurred())
})
})
var _ = Describe("Aggregated role definition tests", func() {
var adminRules = []rbacv1.PolicyRule{
{
APIGroups: []string{
"cdi.kubevirt.io",
},
Resources: []string{
"datavolumes",
},
Verbs: []string{
"*",
},
},
{
APIGroups: []string{
"cdi.kubevirt.io",
},
Resources: []string{
"datavolumes/source",
},
Verbs: []string{
"create",
},
},
{
APIGroups: []string{
"cdi.kubevirt.io",
},
Resources: []string{
"cdiconfigs",
},
Verbs: []string{
"get",
"list",
"watch",
"patch",
"update",
},
},
{
APIGroups: []string{
"upload.cdi.kubevirt.io",
},
Resources: []string{
"uploadtokenrequests",
},
Verbs: []string{
"*",
},
},
}
var editRules = adminRules
var viewRules = []rbacv1.PolicyRule{
{
APIGroups: []string{
"cdi.kubevirt.io",
},
Resources: []string{
"datavolumes",
},
Verbs: []string{
"get",
"list",
"watch",
},
},
{
APIGroups: []string{
"cdi.kubevirt.io",
},
Resources: []string{
"datavolumes/source",
},
Verbs: []string{
"create",
},
},
{
APIGroups: []string{
"cdi.kubevirt.io",
},
Resources: []string{
"cdiconfigs",
},
Verbs: []string{
"get",
"list",
"watch",
},
},
}
f := framework.NewFrameworkOrDie("aggregated-role-definition-tests")
DescribeTable("check all expected rules exist", func(role string, rules []rbacv1.PolicyRule) {
clusterRole, err := f.K8sClient.RbacV1().ClusterRoles().Get(role, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
found := false
for _, expectedRule := range rules {
for _, r := range clusterRole.Rules {
if reflect.DeepEqual(expectedRule, r) {
found = true
break
}
}
}
Expect(found).To(BeTrue())
},
Entry("[test_id:3945]for admin", "admin", adminRules),
Entry("[test_id:3946]for edit", "edit", editRules),
Entry("[test_id:3947]for view", "view", viewRules),
)
})