Skip to content

Commit b86522d

Browse files
committed
test(aggregation): Add test for operatorgroup role aggregation
1 parent 7fb889e commit b86522d

File tree

2 files changed

+113
-77
lines changed

2 files changed

+113
-77
lines changed

scripts/build_local.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
set -e
77

88
if [ -z "$NO_MINIKUBE" ]; then
9-
ps x | grep -q [m]inikube || minikube start --kubernetes-version="v1.12.0" --extra-config=apiserver.v=4 || { echo 'Cannot start minikube.'; exit 1; }
9+
ps x | grep -q [m]inikube || minikube start --kubernetes-version="v1.13.0" --extra-config=apiserver.v=4 || { echo 'Cannot start minikube.'; exit 1; }
1010
eval $(minikube docker-env) || { echo 'Cannot switch to minikube docker'; exit 1; }
1111
kubectl config use-context minikube
1212
fi

test/e2e/operator_groups_e2e_test.go

Lines changed: 112 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,12 @@ package e2e
22

33
import (
44
"fmt"
5-
"regexp"
65
"strings"
76
"testing"
87
"time"
98

109
"github.com/coreos/go-semver/semver"
11-
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
1210
"github.com/stretchr/testify/require"
13-
appsv1 "k8s.io/api/apps/v1"
1411
authorizationv1 "k8s.io/api/authorization/v1"
1512
corev1 "k8s.io/api/core/v1"
1613
rbacv1 "k8s.io/api/rbac/v1"
@@ -21,7 +18,8 @@ import (
2118
"k8s.io/apimachinery/pkg/util/wait"
2219
"k8s.io/client-go/informers"
2320
"k8s.io/client-go/tools/cache"
24-
"k8s.io/kubernetes/pkg/apis/rbac"
21+
22+
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
2523

2624
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1"
2725
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
@@ -30,59 +28,6 @@ import (
3028
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
3129
)
3230

33-
func DeploymentComplete(deployment *appsv1.Deployment, newStatus *appsv1.DeploymentStatus) bool {
34-
return newStatus.UpdatedReplicas == *(deployment.Spec.Replicas) &&
35-
newStatus.Replicas == *(deployment.Spec.Replicas) &&
36-
newStatus.AvailableReplicas == *(deployment.Spec.Replicas) &&
37-
newStatus.ObservedGeneration >= deployment.Generation
38-
}
39-
40-
// Currently this function only modifies the watchedNamespace in the container command
41-
func patchOlmDeployment(t *testing.T, c operatorclient.ClientInterface, newNamespace string) (cleanupFunc func() error) {
42-
runningDeploy, err := c.GetDeployment(operatorNamespace, "olm-operator")
43-
require.NoError(t, err)
44-
45-
oldCommand := runningDeploy.Spec.Template.Spec.Containers[0].Command
46-
re, err := regexp.Compile(`-watchedNamespaces\W(\S+)`)
47-
require.NoError(t, err)
48-
newCommand := re.ReplaceAllString(strings.Join(oldCommand, " "), "$0"+","+newNamespace)
49-
t.Logf("original=%#v newCommand=%#v", oldCommand, newCommand)
50-
finalNewCommand := strings.Split(newCommand, " ")
51-
runningDeploy.Spec.Template.Spec.Containers[0].Command = make([]string, len(finalNewCommand))
52-
copy(runningDeploy.Spec.Template.Spec.Containers[0].Command, finalNewCommand)
53-
54-
olmDeployment, updated, err := c.UpdateDeployment(runningDeploy)
55-
if err != nil || updated == false {
56-
t.Fatalf("Deployment update failed: (updated %v) %v\n", updated, err)
57-
}
58-
require.NoError(t, err)
59-
60-
err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
61-
t.Log("Polling for OLM deployment update...")
62-
fetchedDeployment, err := c.GetDeployment(olmDeployment.Namespace, olmDeployment.Name)
63-
if err != nil {
64-
return false, err
65-
}
66-
if DeploymentComplete(olmDeployment, &fetchedDeployment.Status) {
67-
return true, nil
68-
}
69-
return false, nil
70-
})
71-
require.NoError(t, err)
72-
73-
return func() error {
74-
olmDeployment.Spec.Template.Spec.Containers[0].Command = oldCommand
75-
_, updated, err := c.UpdateDeployment(olmDeployment)
76-
if err != nil || updated == false {
77-
t.Fatalf("Deployment update failed: (updated %v) %v\n", updated, err)
78-
}
79-
if err != nil {
80-
return err
81-
}
82-
return nil
83-
}
84-
}
85-
8631
func checkOperatorGroupAnnotations(obj metav1.Object, op *v1.OperatorGroup, checkTargetNamespaces bool, targetNamespaces string) error {
8732
if checkTargetNamespaces {
8833
if annotation, ok := obj.GetAnnotations()[v1.OperatorGroupTargetsAnnotationKey]; !ok || annotation != targetNamespaces {
@@ -221,7 +166,7 @@ func TestOperatorGroup(t *testing.T) {
221166
ServiceAccountName: serviceAccountName,
222167
Rules: []rbacv1.PolicyRule{
223168
{
224-
Verbs: []string{rbac.VerbAll},
169+
Verbs: []string{rbacv1.VerbAll},
225170
APIGroups: []string{mainCRD.Spec.Group},
226171
Resources: []string{mainCRDPlural},
227172
},
@@ -475,12 +420,94 @@ func createProjectAdmin(t *testing.T, c operatorclient.ClientInterface, namespac
475420
},
476421
})
477422
require.NoError(t, err)
478-
return "system:serviceaccount:" + sa.GetNamespace() + ":" + sa.GetName(), func() {
423+
// kubectl -n a8v4sw auth can-i create alp999.cluster.com --as system:serviceaccount:a8v4sw:padmin-xqdfz
424+
return "system:serviceaccount:" + namespace + ":" + sa.GetName(), func() {
479425
_ = c.DeleteServiceAccount(sa.GetNamespace(), sa.GetName(), metav1.NewDeleteOptions(0))
480426
_ = c.DeleteRoleBinding(rb.GetNamespace(), rb.GetName(), metav1.NewDeleteOptions(0))
481427
}
482428
}
483429

430+
func TestOperatorGroupRoleAggregation(t *testing.T) {
431+
// Generate namespaceA
432+
// Generate operatorGroupA - OwnNamespace
433+
// Generate csvA in namespaceA with all installmodes supported
434+
// Create crd so csv succeeds
435+
// Ensure clusterroles created and aggregated for access provided APIs
436+
437+
defer cleaner.NotifyTestComplete(t, true)
438+
439+
// Generate namespaceA
440+
nsA := genName("a")
441+
c := newKubeClient(t)
442+
for _, ns := range []string{nsA} {
443+
namespace := &corev1.Namespace{
444+
ObjectMeta: metav1.ObjectMeta{
445+
Name: ns,
446+
},
447+
}
448+
_, err := c.KubernetesInterface().CoreV1().Namespaces().Create(namespace)
449+
require.NoError(t, err)
450+
defer func(name string) {
451+
require.NoError(t, c.KubernetesInterface().CoreV1().Namespaces().Delete(name, &metav1.DeleteOptions{}))
452+
}(ns)
453+
}
454+
455+
// Generate operatorGroupA - OwnNamespace
456+
crc := newCRClient(t)
457+
groupA := newOperatorGroup(nsA, genName("a"), nil, nil, []string{nsA}, false)
458+
_, err := crc.OperatorsV1().OperatorGroups(nsA).Create(groupA)
459+
require.NoError(t, err)
460+
defer func() {
461+
require.NoError(t, crc.OperatorsV1().OperatorGroups(nsA).Delete(groupA.GetName(), &metav1.DeleteOptions{}))
462+
}()
463+
464+
// Generate csvA in namespaceA with all installmodes supported
465+
crd := newCRD(genName("a"))
466+
namedStrategy := newNginxInstallStrategy(genName("dep-"), nil, nil)
467+
csvA := newCSV("nginx-a", nsA, "", *semver.New("0.1.0"), []apiextensions.CustomResourceDefinition{crd}, nil, namedStrategy)
468+
_, err = crc.OperatorsV1alpha1().ClusterServiceVersions(nsA).Create(&csvA)
469+
require.NoError(t, err)
470+
defer func() {
471+
require.NoError(t, crc.OperatorsV1alpha1().ClusterServiceVersions(nsA).Delete(csvA.GetName(), &metav1.DeleteOptions{}))
472+
}()
473+
474+
// Create crd so csv succeeds
475+
cleanupCRD, err := createCRD(c, crd)
476+
require.NoError(t, err)
477+
defer cleanupCRD()
478+
479+
_, err = fetchCSV(t, crc, csvA.GetName(), nsA, csvSucceededChecker)
480+
require.NoError(t, err)
481+
482+
// Ensure clusterroles created and aggregated for access provided APIs
483+
padmin, cleanupPadmin := createProjectAdmin(t, c, nsA)
484+
defer cleanupPadmin()
485+
486+
err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
487+
res, err := c.KubernetesInterface().AuthorizationV1().SubjectAccessReviews().Create(&authorizationv1.SubjectAccessReview{
488+
Spec: authorizationv1.SubjectAccessReviewSpec{
489+
User: padmin,
490+
ResourceAttributes: &authorizationv1.ResourceAttributes{
491+
Namespace: nsA,
492+
Group: crd.Spec.Group,
493+
Version: crd.Spec.Version,
494+
Resource: crd.Spec.Names.Plural,
495+
Verb: "create",
496+
},
497+
},
498+
})
499+
if err != nil {
500+
return false, err
501+
}
502+
if res == nil {
503+
return false, nil
504+
}
505+
t.Log("checking padmin for permission")
506+
return res.Status.Allowed, nil
507+
})
508+
require.NoError(t, err)
509+
}
510+
484511
func TestOperatorGroupInstallModeSupport(t *testing.T) {
485512
// Generate namespaceA
486513
// Generate namespaceB
@@ -631,8 +658,8 @@ func TestOperatorGroupInstallModeSupport(t *testing.T) {
631658
_, err = crc.OperatorsV1alpha1().ClusterServiceVersions(nsA).Update(csvA)
632659
require.NoError(t, err)
633660

634-
// Ensure csvA transitions to Pending
635-
csvA, err = fetchCSV(t, crc, csvA.GetName(), nsA, csvPendingChecker)
661+
// Ensure csvA transitions to Succeeded
662+
csvA, err = fetchCSV(t, crc, csvA.GetName(), nsA, csvSucceededChecker)
636663
require.NoError(t, err)
637664

638665
// Update operatorGroupA's target namespaces to select namespaceA and namespaceB
@@ -668,8 +695,8 @@ func TestOperatorGroupInstallModeSupport(t *testing.T) {
668695
_, err = crc.OperatorsV1alpha1().ClusterServiceVersions(nsA).Update(csvA)
669696
require.NoError(t, err)
670697

671-
// Ensure csvA transitions to Pending
672-
csvA, err = fetchCSV(t, crc, csvA.GetName(), nsA, csvPendingChecker)
698+
// Ensure csvA transitions to Succeeded
699+
csvA, err = fetchCSV(t, crc, csvA.GetName(), nsA, csvSucceededChecker)
673700
require.NoError(t, err)
674701

675702
// Update operatorGroupA's target namespaces to select all namespaces
@@ -706,7 +733,7 @@ func TestOperatorGroupInstallModeSupport(t *testing.T) {
706733
require.NoError(t, err)
707734

708735
// Ensure csvA transitions to Pending
709-
csvA, err = fetchCSV(t, crc, csvA.GetName(), nsA, csvPendingChecker)
736+
csvA, err = fetchCSV(t, crc, csvA.GetName(), nsA, csvSucceededChecker)
710737
require.NoError(t, err)
711738
}
712739

@@ -895,20 +922,29 @@ func TestOperatorGroupIntersection(t *testing.T) {
895922
padmin, cleanupPadmin := createProjectAdmin(t, c, nsA)
896923
defer cleanupPadmin()
897924

898-
res, err := c.KubernetesInterface().AuthorizationV1().SubjectAccessReviews().Create(&v1.SubjectAccessReview{
899-
Spec: v1.SubjectAccessReviewSpec{
900-
User: padmin,
901-
ResourceAttributes: &v1.ResourceAttributes{
902-
Namespace: nsA,
903-
Group: crdA.Spec.Group,
904-
Version: crdA.Spec.Version,
905-
Resource: crdA.Spec.Names.Plural,
906-
Verb: "create",
925+
err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
926+
res, err := c.KubernetesInterface().AuthorizationV1().SubjectAccessReviews().Create(&authorizationv1.SubjectAccessReview{
927+
Spec: authorizationv1.SubjectAccessReviewSpec{
928+
User: padmin,
929+
ResourceAttributes: &authorizationv1.ResourceAttributes{
930+
Namespace: nsA,
931+
Group: crdA.Spec.Group,
932+
Version: crdA.Spec.Version,
933+
Resource: crdA.Spec.Names.Plural,
934+
Verb: "create",
935+
},
907936
},
908-
},
937+
})
938+
if err != nil {
939+
return false, err
940+
}
941+
if res == nil {
942+
return false, nil
943+
}
944+
t.Log("checking padmin for permission")
945+
return res.Status.Allowed, nil
909946
})
910947
require.NoError(t, err)
911-
require.True(t, res.Status.Allowed, "got %#v", res.Status)
912948

913949
// Await annotation on groupA
914950
q = func() (metav1.ObjectMeta, error) {
@@ -1234,7 +1270,7 @@ func TestCSVCopyWatchingAllNamespaces(t *testing.T) {
12341270
ServiceAccountName: serviceAccountName,
12351271
Rules: []rbacv1.PolicyRule{
12361272
{
1237-
Verbs: []string{rbac.VerbAll},
1273+
Verbs: []string{rbacv1.VerbAll},
12381274
APIGroups: []string{mainCRD.Spec.Group},
12391275
Resources: []string{mainCRDPlural},
12401276
},

0 commit comments

Comments
 (0)