@@ -2,15 +2,12 @@ package e2e
2
2
3
3
import (
4
4
"fmt"
5
- "regexp"
6
5
"strings"
7
6
"testing"
8
7
"time"
9
8
10
9
"github.com/coreos/go-semver/semver"
11
- "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
12
10
"github.com/stretchr/testify/require"
13
- appsv1 "k8s.io/api/apps/v1"
14
11
authorizationv1 "k8s.io/api/authorization/v1"
15
12
corev1 "k8s.io/api/core/v1"
16
13
rbacv1 "k8s.io/api/rbac/v1"
@@ -21,7 +18,8 @@ import (
21
18
"k8s.io/apimachinery/pkg/util/wait"
22
19
"k8s.io/client-go/informers"
23
20
"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"
25
23
26
24
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1"
27
25
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
@@ -30,59 +28,6 @@ import (
30
28
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
31
29
)
32
30
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
-
86
31
func checkOperatorGroupAnnotations (obj metav1.Object , op * v1.OperatorGroup , checkTargetNamespaces bool , targetNamespaces string ) error {
87
32
if checkTargetNamespaces {
88
33
if annotation , ok := obj .GetAnnotations ()[v1 .OperatorGroupTargetsAnnotationKey ]; ! ok || annotation != targetNamespaces {
@@ -221,7 +166,7 @@ func TestOperatorGroup(t *testing.T) {
221
166
ServiceAccountName : serviceAccountName ,
222
167
Rules : []rbacv1.PolicyRule {
223
168
{
224
- Verbs : []string {rbac .VerbAll },
169
+ Verbs : []string {rbacv1 .VerbAll },
225
170
APIGroups : []string {mainCRD .Spec .Group },
226
171
Resources : []string {mainCRDPlural },
227
172
},
@@ -447,14 +392,130 @@ func TestOperatorGroup(t *testing.T) {
447
392
require .NoError (t , err )
448
393
}
449
394
395
+ func createProjectAdmin (t * testing.T , c operatorclient.ClientInterface , namespace string ) (string , cleanupFunc ) {
396
+ sa , err := c .CreateServiceAccount (& corev1.ServiceAccount {
397
+ ObjectMeta : metav1.ObjectMeta {
398
+ Namespace : namespace ,
399
+ Name : genName ("padmin-" ),
400
+ },
401
+ })
402
+ require .NoError (t , err )
403
+
404
+ rb , err := c .CreateRoleBinding (& rbacv1.RoleBinding {
405
+ ObjectMeta : metav1.ObjectMeta {
406
+ Name : genName ("padmin-" ),
407
+ Namespace : namespace ,
408
+ },
409
+ Subjects : []rbacv1.Subject {
410
+ {
411
+ Kind : "ServiceAccount" ,
412
+ Name : sa .GetName (),
413
+ Namespace : sa .GetNamespace (),
414
+ },
415
+ },
416
+ RoleRef : rbacv1.RoleRef {
417
+ APIGroup : "rbac.authorization.k8s.io" ,
418
+ Kind : "ClusterRole" ,
419
+ Name : "admin" ,
420
+ },
421
+ })
422
+ require .NoError (t , err )
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 () {
425
+ _ = c .DeleteServiceAccount (sa .GetNamespace (), sa .GetName (), metav1 .NewDeleteOptions (0 ))
426
+ _ = c .DeleteRoleBinding (rb .GetNamespace (), rb .GetName (), metav1 .NewDeleteOptions (0 ))
427
+ }
428
+ }
429
+
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
+
450
511
func TestOperatorGroupInstallModeSupport (t * testing.T ) {
451
512
// Generate namespaceA
452
513
// Generate namespaceB
453
514
// Create operatorGroupA in namespaceA that selects namespaceA
454
515
// Generate csvA with an unfulfilled required CRD and no supported InstallModes in namespaceA
455
516
// Ensure csvA transitions to Failed with reason "UnsupportedOperatorGroup"
456
517
// Update csvA to have OwnNamespace supported=true
457
- // Ensure csvA transitions to Pending
518
+ // Ensure csvA transitions to Succeeded
458
519
// Update operatorGroupA's target namespaces to select namespaceB
459
520
// Ensure csvA transitions to Failed with reason "UnsupportedOperatorGroup"
460
521
// Update csvA to have SingleNamespace supported=true
@@ -555,8 +616,13 @@ func TestOperatorGroupInstallModeSupport(t *testing.T) {
555
616
_ , err = crc .OperatorsV1alpha1 ().ClusterServiceVersions (nsA ).Update (csvA )
556
617
require .NoError (t , err )
557
618
558
- // Ensure csvA transitions to Pending
559
- csvA , err = fetchCSV (t , crc , csvA .GetName (), nsA , csvPendingChecker )
619
+ // Create crd so csv succeeds
620
+ cleanupCRD , err := createCRD (c , crd )
621
+ require .NoError (t , err )
622
+ defer cleanupCRD ()
623
+
624
+ // Ensure csvA transitions to Succeeded
625
+ csvA , err = fetchCSV (t , crc , csvA .GetName (), nsA , csvSucceededChecker )
560
626
require .NoError (t , err )
561
627
562
628
// Update operatorGroupA's target namespaces to select namespaceB
@@ -592,8 +658,8 @@ func TestOperatorGroupInstallModeSupport(t *testing.T) {
592
658
_ , err = crc .OperatorsV1alpha1 ().ClusterServiceVersions (nsA ).Update (csvA )
593
659
require .NoError (t , err )
594
660
595
- // Ensure csvA transitions to Pending
596
- 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 )
597
663
require .NoError (t , err )
598
664
599
665
// Update operatorGroupA's target namespaces to select namespaceA and namespaceB
@@ -629,8 +695,8 @@ func TestOperatorGroupInstallModeSupport(t *testing.T) {
629
695
_ , err = crc .OperatorsV1alpha1 ().ClusterServiceVersions (nsA ).Update (csvA )
630
696
require .NoError (t , err )
631
697
632
- // Ensure csvA transitions to Pending
633
- 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 )
634
700
require .NoError (t , err )
635
701
636
702
// Update operatorGroupA's target namespaces to select all namespaces
@@ -667,7 +733,7 @@ func TestOperatorGroupInstallModeSupport(t *testing.T) {
667
733
require .NoError (t , err )
668
734
669
735
// Ensure csvA transitions to Pending
670
- csvA , err = fetchCSV (t , crc , csvA .GetName (), nsA , csvPendingChecker )
736
+ csvA , err = fetchCSV (t , crc , csvA .GetName (), nsA , csvSucceededChecker )
671
737
require .NoError (t , err )
672
738
}
673
739
@@ -689,6 +755,7 @@ func TestOperatorGroupIntersection(t *testing.T) {
689
755
// Ensure csvD in namespaceD is still successful
690
756
// Generate csvA in namespaceA that owns crdA
691
757
// Wait for csvA to be successful
758
+ // Ensure clusterroles created and aggregated for accessing provided APIs
692
759
// Wait for operatorGroupA to have providedAPI annotation with crdA's Kind.version.group in its providedAPIs annotation
693
760
// Wait for csvA to have a CSV with copied status in namespace C
694
761
// Generate operatorGroupB in namespaceB that selects namespace C
@@ -851,6 +918,34 @@ func TestOperatorGroupIntersection(t *testing.T) {
851
918
_ , err = awaitCSV (t , crc , nsA , csvA .GetName (), csvSucceededChecker )
852
919
require .NoError (t , err )
853
920
921
+ // Ensure clusterroles created and aggregated for access provided APIs
922
+ padmin , cleanupPadmin := createProjectAdmin (t , c , nsA )
923
+ defer cleanupPadmin ()
924
+
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
+ },
936
+ },
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
946
+ })
947
+ require .NoError (t , err )
948
+
854
949
// Await annotation on groupA
855
950
q = func () (metav1.ObjectMeta , error ) {
856
951
g , err := crc .OperatorsV1 ().OperatorGroups (nsA ).Get (groupA .GetName (), metav1.GetOptions {})
@@ -1175,7 +1270,7 @@ func TestCSVCopyWatchingAllNamespaces(t *testing.T) {
1175
1270
ServiceAccountName : serviceAccountName ,
1176
1271
Rules : []rbacv1.PolicyRule {
1177
1272
{
1178
- Verbs : []string {rbac .VerbAll },
1273
+ Verbs : []string {rbacv1 .VerbAll },
1179
1274
APIGroups : []string {mainCRD .Spec .Group },
1180
1275
Resources : []string {mainCRDPlural },
1181
1276
},
0 commit comments