containerized-data-importer/tests/rbac_test.go
Edu Gómez Escandell 0e750262a3
Enable autoformatting linters (#3179)
* Enable gofmt linter

From the docs:

> Gofmt checks whether code was gofmt-ed. By default this tool runs with
> -s option to check for code simplification.

https://golangci-lint.run/usage/linters/#gofmt

Signed-off-by: Edu Gómez Escandell <egomez@redhat.com>

* Run gomft on the project

Ran this command after adding the gofmt linter:

	golangci-lint run ./... --fix

Signed-off-by: Edu Gómez Escandell <egomez@redhat.com>

* Enable whitespace linter

From the docs:
> Whitespace is a linter that checks for unnecessary newlines at the
> start and end of functions, if, for, etc.

https://golangci-lint.run/usage/linters/#whitespace

Signed-off-by: Edu Gómez Escandell <egomez@redhat.com>

* Run whitespace on the project

Ran this command after adding the whitespace linter:

	golangci-lint run ./... --fix

Signed-off-by: Edu Gómez Escandell <egomez@redhat.com>

* Enable GCI linter

Per the docs:

> Gci controls Go package import order and makes it always deterministic.

https://golangci-lint.run/usage/linters/#gci

NOTE: I noticed that many files separate their imports in a particular
way, so I set the linter to enforce this standard.

Signed-off-by: Edu Gómez Escandell <egomez@redhat.com>

* Run GCI on the project

Ran this command after adding the GCI linter:

	golangci-lint run ./... --fix

Signed-off-by: Edu Gómez Escandell <egomez@redhat.com>

---------

Signed-off-by: Edu Gómez Escandell <egomez@redhat.com>
2024-04-24 13:52:22 +02:00

303 lines
9.3 KiB
Go

package tests
import (
"context"
"time"
. "github.com/onsi/ginkgo/v2"
. "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"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client"
cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
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", Serial, func() {
var createServiceAccount = func(client kubernetes.Interface, namespace, name string) {
sa := &corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
}
_, err := client.CoreV1().ServiceAccounts(namespace).Create(context.TODO(), sa, metav1.CreateOptions{})
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(context.TODO(), rb, metav1.CreateOptions{})
Expect(err).ToNot(HaveOccurred())
}
f := framework.NewFramework("aggregated-role-tests")
DescribeTable("admin/edit datavolume permission checks", func(user string) {
var cdiClient *cdiClientset.Clientset
var crClient client.Client
var err error
createServiceAccount(f.K8sClient, f.Namespace.Name, user)
createRoleBinding(f.K8sClient, user, f.Namespace.Name, user)
Eventually(func() error {
cdiClient, err = f.GetCdiClientForServiceAccount(f.Namespace.Name, user)
return err
}, 60*time.Second, 2*time.Second).ShouldNot(HaveOccurred())
rc, err := f.GetRESTConfigForServiceAccount(f.Namespace.Name, user)
Expect(err).ToNot(HaveOccurred())
crClient, err = client.New(rc, client.Options{Scheme: scheme.Scheme})
Expect(err).ToNot(HaveOccurred())
dv := utils.NewDataVolumeWithHTTPImport("test-"+user, "1Gi", "http://nonexistant.url")
dv, err = cdiClient.CdiV1beta1().DataVolumes(f.Namespace.Name).Create(context.TODO(), dv, metav1.CreateOptions{})
Expect(err).ToNot(HaveOccurred())
dvl, err := cdiClient.CdiV1beta1().DataVolumes(f.Namespace.Name).List(context.TODO(), metav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(dvl.Items).To(HaveLen(1))
dv, err = cdiClient.CdiV1beta1().DataVolumes(f.Namespace.Name).Get(context.TODO(), dv.Name, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
err = cdiClient.CdiV1beta1().DataVolumes(f.Namespace.Name).Delete(context.TODO(), dv.Name, metav1.DeleteOptions{})
Expect(err).ToNot(HaveOccurred())
dvl, err = cdiClient.CdiV1beta1().DataVolumes(f.Namespace.Name).List(context.TODO(), metav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(dvl.Items).To(BeEmpty())
dv = utils.NewDataVolumeForUpload("upload-test-"+user, "1Gi")
dv, err = cdiClient.CdiV1beta1().DataVolumes(f.Namespace.Name).Create(context.TODO(), dv, metav1.CreateOptions{})
Expect(err).ToNot(HaveOccurred())
var pvc *corev1.PersistentVolumeClaim
Eventually(func() error {
pvc, err = f.K8sClient.CoreV1().PersistentVolumeClaims(f.Namespace.Name).Get(context.TODO(), 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(cdiClient, pvc)
Expect(err).ToNot(HaveOccurred())
Expect(token).ToNot(BeEmpty())
cl, err := cdiClient.CdiV1beta1().CDIConfigs().List(context.TODO(), metav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(cl.Items).To(HaveLen(1))
_, err = cdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), cl.Items[0].Name, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
err = utils.UpdateCDIConfig(crClient, func(config *cdiv1.CDIConfigSpec) {
config.ScratchSpaceStorageClass = &[]string{"foobar"}[0]
})
Expect(err).To(HaveOccurred())
profiles, err := cdiClient.CdiV1beta1().StorageProfiles().List(context.TODO(), metav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(profiles.Items).ToNot(BeEmpty())
profileName := profiles.Items[0].Name
storageProfile, err := cdiClient.CdiV1beta1().StorageProfiles().Get(context.TODO(), profileName, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
spec := &storageProfile.Spec
cs := cdiv1.CloneStrategyCsiClone
spec.CloneStrategy = &cs
err = utils.UpdateStorageProfile(crClient, profileName, *spec)
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 cdiClient cdiClientset.Interface
var crClient client.Client
var err error
createServiceAccount(f.K8sClient, f.Namespace.Name, user)
createRoleBinding(f.K8sClient, user, f.Namespace.Name, user)
Eventually(func() error {
cdiClient, err = f.GetCdiClientForServiceAccount(f.Namespace.Name, user)
return err
}, 60*time.Second, 2*time.Second).ShouldNot(HaveOccurred())
rc, err := f.GetRESTConfigForServiceAccount(f.Namespace.Name, user)
Expect(err).ToNot(HaveOccurred())
crClient, err = client.New(rc, client.Options{Scheme: scheme.Scheme})
Expect(err).ToNot(HaveOccurred())
dv := utils.NewDataVolumeWithHTTPImport("test-"+user, "1Gi", "http://nonexistant.url")
_, err = cdiClient.CdiV1beta1().DataVolumes(f.Namespace.Name).Create(context.TODO(), dv, metav1.CreateOptions{})
Expect(err).To(HaveOccurred())
dvl, err := cdiClient.CdiV1beta1().DataVolumes(f.Namespace.Name).List(context.TODO(), metav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(dvl.Items).To(BeEmpty())
_, err = cdiClient.CdiV1beta1().DataVolumes(f.Namespace.Name).Get(context.TODO(), "test-"+user, metav1.GetOptions{})
Expect(err).To(HaveOccurred())
Expect(k8serrors.IsNotFound(err)).To(BeTrue())
cl, err := cdiClient.CdiV1beta1().CDIConfigs().List(context.TODO(), metav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(cl.Items).To(HaveLen(1))
_, err = cdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), cl.Items[0].Name, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
err = utils.UpdateCDIConfig(crClient, func(config *cdiv1.CDIConfigSpec) {
config.ScratchSpaceStorageClass = &[]string{"foobar"}[0]
})
Expect(err).To(HaveOccurred())
profiles, err := cdiClient.CdiV1beta1().StorageProfiles().List(context.TODO(), metav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(profiles.Items).ToNot(BeEmpty())
profileName := profiles.Items[0].Name
storageProfile, err := cdiClient.CdiV1beta1().StorageProfiles().Get(context.TODO(), profileName, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
spec := &storageProfile.Spec
cs := cdiv1.CloneStrategyCsiClone
spec.CloneStrategy = &cs
err = utils.UpdateStorageProfile(crClient, profileName, *spec)
Expect(err).To(HaveOccurred())
})
})
var _ = Describe("Aggregated role definition tests", Serial, func() {
var adminRules = []rbacv1.PolicyRule{
{
APIGroups: []string{
"cdi.kubevirt.io",
},
Resources: []string{
"datavolumes",
"dataimportcrons",
"datasources",
"volumeimportsources",
"volumeuploadsources",
"volumeclonesources",
},
Verbs: []string{
"*",
},
},
{
APIGroups: []string{
"cdi.kubevirt.io",
},
Resources: []string{
"datavolumes/source",
},
Verbs: []string{
"create",
},
},
{
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{
"cdiconfigs",
"dataimportcrons",
"datasources",
"datavolumes",
"objecttransfers",
"storageprofiles",
"volumeimportsources",
"volumeuploadsources",
"volumeclonesources",
},
Verbs: []string{
"get",
"list",
"watch",
},
},
{
APIGroups: []string{
"cdi.kubevirt.io",
},
Resources: []string{
"datavolumes/source",
},
Verbs: []string{
"create",
},
},
}
f := framework.NewFramework("aggregated-role-definition-tests")
DescribeTable("check all expected rules exist", func(role string, rules []rbacv1.PolicyRule) {
clusterRole, err := f.K8sClient.RbacV1().ClusterRoles().Get(context.TODO(), role, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(clusterRole.Rules).To(ContainElements(rules))
},
Entry("[test_id:3945]for admin", "admin", adminRules),
Entry("[test_id:3946]for edit", "edit", editRules),
Entry("[test_id:3947]for view", "view", viewRules),
)
})