Skip to content

Commit ab19c3a

Browse files
Merge pull request #568 from jpeeler/add-operator-group-2
Operator group follow ups
2 parents 14aff97 + f233a1a commit ab19c3a

File tree

5 files changed

+117
-53
lines changed

5 files changed

+117
-53
lines changed

deploy/chart/templates/0000_30_14-operatorgroup.crd.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,36 @@ spec:
2525
properties:
2626
selector:
2727
type: object
28+
description: Label selector to find resources associated with or managed by the operator
29+
properties:
30+
matchLabels:
31+
type: object
32+
description: Label key:value pairs to match directly
33+
matchExpressions:
34+
type: array
35+
description: A set of expressions to match against the resource.
36+
items:
37+
allOf:
38+
- type: object
39+
required:
40+
- key
41+
- operator
42+
- values
43+
properties:
44+
key:
45+
type: string
46+
description: the key to match
47+
operator:
48+
type: string
49+
description: the operator for the expression
50+
enum:
51+
- In
52+
- NotIn
53+
- Exists
54+
- DoesNotExist
55+
values:
56+
type: array
57+
description: set of values for the expression
2858
serviceAccountName:
2959
type: string
3060
required:

pkg/controller/operators/olm/operator_test.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,10 @@ func NewFakeOperator(clientObjs []runtime.Object, k8sObjs []runtime.Object, extO
134134
// Create the new operator
135135
queueOperator, err := queueinformer.NewOperatorFromClient(opClientFake)
136136
op := &Operator{
137-
Operator: queueOperator,
138-
client: clientFake,
139-
lister: operatorlister.NewLister(),
140-
resolver: resolver,
137+
Operator: queueOperator,
138+
client: clientFake,
139+
lister: operatorlister.NewLister(),
140+
resolver: resolver,
141141
csvQueues: make(map[string]workqueue.RateLimitingInterface),
142142
recorder: eventRecorder,
143143
}
@@ -2183,13 +2183,12 @@ func TestSyncOperatorGroups(t *testing.T) {
21832183
},
21842184
},
21852185
},
2186-
21872186
clientObjs: []runtime.Object{
21882187
csv("csv1",
21892188
testNS,
21902189
"",
21912190
installStrategy("csv1-dep1", nil, nil),
2192-
[]*v1beta1.CustomResourceDefinition{crd("c1", "v1")},
2191+
[]*v1beta1.CustomResourceDefinition{crd("c1.fake.api.group", "v1")},
21932192
[]*v1beta1.CustomResourceDefinition{},
21942193
v1alpha1.CSVPhaseSucceeded,
21952194
),
@@ -2240,7 +2239,7 @@ func TestSyncOperatorGroups(t *testing.T) {
22402239
testNS,
22412240
"",
22422241
installStrategy("csv1-dep1", nil, nil),
2243-
[]*v1beta1.CustomResourceDefinition{crd("c1", "v1")},
2242+
[]*v1beta1.CustomResourceDefinition{crd("c1.fake.api.group", "v1")},
22442243
[]*v1beta1.CustomResourceDefinition{},
22452244
v1alpha1.CSVPhaseSucceeded,
22462245
),

pkg/controller/operators/olm/operatorgroup.go

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -180,22 +180,18 @@ func (a *Operator) ensureClusterRoles(op *v1alpha2.OperatorGroup) error {
180180
apiEditPolicyRules := []rbacv1.PolicyRule{}
181181
apiViewPolicyRules := []rbacv1.PolicyRule{}
182182
for _, owned := range csv.Spec.CustomResourceDefinitions.Owned {
183-
resourceNames := []string{}
184-
for _, resource := range owned.Resources {
185-
resourceNames = append(resourceNames, resource.Name)
183+
nameGroupPair := strings.SplitN(owned.Name, ".", 2) // -> etcdclusters etcd.database.coreos.com
184+
if len(nameGroupPair) != 2 {
185+
return fmt.Errorf("Invalid parsing of name '%v', got %v", owned.Name, nameGroupPair)
186186
}
187-
managerPolicyRules = append(managerPolicyRules, rbacv1.PolicyRule{Verbs: []string{"*"}, APIGroups: []string{owned.Name}, Resources: resourceNames})
188-
apiEditPolicyRules = append(apiEditPolicyRules, rbacv1.PolicyRule{Verbs: []string{"create", "update", "patch", "delete"}, APIGroups: []string{owned.Name}, Resources: []string{owned.Kind}})
189-
apiViewPolicyRules = append(apiViewPolicyRules, rbacv1.PolicyRule{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{owned.Name}, Resources: []string{owned.Kind}})
187+
managerPolicyRules = append(managerPolicyRules, rbacv1.PolicyRule{Verbs: []string{"*"}, APIGroups: []string{nameGroupPair[1]}, Resources: []string{nameGroupPair[0]}})
188+
apiEditPolicyRules = append(apiEditPolicyRules, rbacv1.PolicyRule{Verbs: []string{"create", "update", "patch", "delete"}, APIGroups: []string{nameGroupPair[1]}, Resources: []string{nameGroupPair[0]}})
189+
apiViewPolicyRules = append(apiViewPolicyRules, rbacv1.PolicyRule{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{nameGroupPair[1]}, Resources: []string{nameGroupPair[0]}})
190190
}
191191
for _, owned := range csv.Spec.APIServiceDefinitions.Owned {
192-
resourceNames := []string{}
193-
for _, resource := range owned.Resources {
194-
resourceNames = append(resourceNames, resource.Name)
195-
}
196-
managerPolicyRules = append(managerPolicyRules, rbacv1.PolicyRule{Verbs: []string{"*"}, APIGroups: []string{owned.Group}, Resources: resourceNames})
197-
apiEditPolicyRules = append(apiEditPolicyRules, rbacv1.PolicyRule{Verbs: []string{"create", "update", "patch", "delete"}, APIGroups: []string{owned.Group}, Resources: []string{owned.Kind}})
198-
apiViewPolicyRules = append(apiViewPolicyRules, rbacv1.PolicyRule{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{owned.Group}, Resources: []string{owned.Kind}})
192+
managerPolicyRules = append(managerPolicyRules, rbacv1.PolicyRule{Verbs: []string{"*"}, APIGroups: []string{owned.Group}, Resources: []string{owned.Name}})
193+
apiEditPolicyRules = append(apiEditPolicyRules, rbacv1.PolicyRule{Verbs: []string{"create", "update", "patch", "delete"}, APIGroups: []string{owned.Group}, Resources: []string{owned.Name}})
194+
apiViewPolicyRules = append(apiViewPolicyRules, rbacv1.PolicyRule{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{owned.Group}, Resources: []string{owned.Name}})
199195
}
200196

201197
clusterRole := &rbacv1.ClusterRole{

pkg/controller/operators/olm/requirements.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func (a *Operator) requirementStatus(strategyDetailsDeployment *install.Strategy
2828
// check if CRD exists - this verifies group, version, and kind, so no need for GVK check via discovery
2929
crd, err := a.lister.APIExtensionsV1beta1().CustomResourceDefinitionLister().Get(r.Name)
3030
if err != nil {
31+
log.Debugf("Setting 'met' to false, %v with err: %v", r.Name, err)
3132
status.Status = v1alpha1.RequirementStatusReasonNotPresent
3233
met = false
3334
statuses = append(statuses, status)
@@ -277,6 +278,9 @@ func (a *Operator) requirementAndPermissionStatus(csv *v1alpha1.ClusterServiceVe
277278
// Aggregate requirement and permissions statuses
278279
statuses := append(reqStatuses, permStatuses...)
279280
met := reqMet && permMet
281+
if !met {
282+
log.Debugf("reqMet=%#v permMet=%v\n", reqMet, permMet)
283+
}
280284

281285
return met, statuses, nil
282286
}

test/e2e/operator_groups_e2e_test.go

Lines changed: 68 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ import (
66
"strings"
77
"testing"
88

9-
appsv1 "k8s.io/api/apps/v1"
10-
"k8s.io/apimachinery/pkg/api/errors"
11-
"k8s.io/apimachinery/pkg/util/wait"
129
"github.com/coreos/go-semver/semver"
1310
"github.com/stretchr/testify/require"
11+
appsv1 "k8s.io/api/apps/v1"
1412
corev1 "k8s.io/api/core/v1"
13+
rbacv1 "k8s.io/api/rbac/v1"
14+
extv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
15+
"k8s.io/apimachinery/pkg/api/errors"
1516
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
17+
"k8s.io/apimachinery/pkg/util/wait"
1618

1719
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
1820
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha2"
@@ -27,39 +29,49 @@ func DeploymentComplete(deployment *appsv1.Deployment, newStatus *appsv1.Deploym
2729
}
2830

2931
// Currently this function only modifies the watchedNamespace in the container command
30-
func patchOlmDeployment(t *testing.T, c operatorclient.ClientInterface, newNamespace string) []string {
32+
func patchOlmDeployment(t *testing.T, c operatorclient.ClientInterface, newNamespace string) (cleanupFunc func() error) {
3133
runningDeploy, err := c.GetDeployment(testNamespace, "olm-operator")
3234
require.NoError(t, err)
3335

34-
command := runningDeploy.Spec.Template.Spec.Containers[0].Command
36+
oldCommand := runningDeploy.Spec.Template.Spec.Containers[0].Command
3537
re, err := regexp.Compile(`-watchedNamespaces\W(\S+)`)
3638
require.NoError(t, err)
37-
newCommand := re.ReplaceAllString(strings.Join(command, " "), "$0"+","+newNamespace)
38-
t.Logf("original=%#v newCommand=%#v", command, newCommand)
39+
newCommand := re.ReplaceAllString(strings.Join(oldCommand, " "), "$0"+","+newNamespace)
40+
t.Logf("original=%#v newCommand=%#v", oldCommand, newCommand)
3941
finalNewCommand := strings.Split(newCommand, " ")
4042
runningDeploy.Spec.Template.Spec.Containers[0].Command = make([]string, len(finalNewCommand))
4143
copy(runningDeploy.Spec.Template.Spec.Containers[0].Command, finalNewCommand)
4244

43-
newDeployment, updated, err := c.UpdateDeployment(runningDeploy)
45+
olmDeployment, updated, err := c.UpdateDeployment(runningDeploy)
4446
if err != nil || updated == false {
4547
t.Fatalf("Deployment update failed: (updated %v) %v\n", updated, err)
4648
}
4749
require.NoError(t, err)
4850

4951
err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
5052
t.Log("Polling for OLM deployment update...")
51-
fetchedDeployment, err := c.GetDeployment(newDeployment.Namespace, newDeployment.Name)
53+
fetchedDeployment, err := c.GetDeployment(olmDeployment.Namespace, olmDeployment.Name)
5254
if err != nil {
5355
return false, err
5456
}
55-
if DeploymentComplete(newDeployment, &fetchedDeployment.Status) {
57+
if DeploymentComplete(olmDeployment, &fetchedDeployment.Status) {
5658
return true, nil
5759
}
5860
return false, nil
5961
})
60-
6162
require.NoError(t, err)
62-
return command
63+
64+
return func() error {
65+
olmDeployment.Spec.Template.Spec.Containers[0].Command = oldCommand
66+
_, updated, err := c.UpdateDeployment(olmDeployment)
67+
if err != nil || updated == false {
68+
t.Fatalf("Deployment update failed: (updated %v) %v\n", updated, err)
69+
}
70+
if err != nil {
71+
return err
72+
}
73+
return nil
74+
}
6375
}
6476

6577
func checkOperatorGroupAnnotations(obj metav1.Object, op *v1alpha2.OperatorGroup, targetNamespaces string) error {
@@ -78,6 +90,7 @@ func checkOperatorGroupAnnotations(obj metav1.Object, op *v1alpha2.OperatorGroup
7890

7991
func TestOperatorGroup(t *testing.T) {
8092
// Create namespace with specific label
93+
// Create CRD
8194
// Create CSV in operator namespace
8295
// Create operator group that watches namespace and uses specific label
8396
// Verify operator group status contains correct status
@@ -101,10 +114,18 @@ func TestOperatorGroup(t *testing.T) {
101114
createdOtherNamespace, err := c.KubernetesInterface().CoreV1().Namespaces().Create(&otherNamespace)
102115
require.NoError(t, err)
103116

104-
oldCommand := patchOlmDeployment(t, c, otherNamespaceName)
117+
cleanupOlmDeployment := patchOlmDeployment(t, c, otherNamespaceName)
118+
119+
t.Log("Creating CRD")
120+
mainCRDPlural := genName("ins")
121+
apiGroup := "cluster.com"
122+
mainCRDName := mainCRDPlural + "." + apiGroup
123+
mainCRD := newCRD(mainCRDName, testNamespace, mainCRDPlural)
124+
cleanupCRD, err := createCRD(c, mainCRD)
125+
require.NoError(t, err)
105126

106127
t.Log("Creating CSV")
107-
aCSV := newCSV(csvName, testNamespace, "", *semver.New("0.0.0"), nil, nil, newNginxInstallStrategy("operator-deployment", nil, nil))
128+
aCSV := newCSV(csvName, testNamespace, "", *semver.New("0.0.0"), []extv1beta1.CustomResourceDefinition{mainCRD}, nil, newNginxInstallStrategy("operator-deployment", nil, nil))
108129
createdCSV, err := crc.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Create(&aCSV)
109130
require.NoError(t, err)
110131

@@ -119,6 +140,7 @@ func TestOperatorGroup(t *testing.T) {
119140
MatchLabels: matchingLabel,
120141
},
121142
},
143+
//ServiceAccountName: "default-sa",
122144
}
123145
_, err = crc.OperatorsV1alpha2().OperatorGroups(testNamespace).Create(&operatorGroup)
124146
require.NoError(t, err)
@@ -133,12 +155,36 @@ func TestOperatorGroup(t *testing.T) {
133155
return false, fetchErr
134156
}
135157
if len(fetched.Status.Namespaces) > 0 {
136-
require.Equal(t, expectedOperatorGroupStatus.Namespaces[0].Name, fetched.Status.Namespaces[0].Name)
158+
require.EqualValues(t, expectedOperatorGroupStatus.Namespaces[0].Name, fetched.Status.Namespaces[0].Name)
137159
return true, nil
138160
}
139161
return false, nil
140162
})
141163

164+
t.Log("Checking for proper RBAC permissions in target namespace")
165+
roleList, err := c.KubernetesInterface().RbacV1().ClusterRoles().List(metav1.ListOptions{})
166+
for _, item := range roleList.Items {
167+
role, err := c.GetClusterRole(item.GetName())
168+
require.NoError(t, err)
169+
switch roleName := item.GetName(); roleName {
170+
case "owned-crd-manager-another-csv":
171+
managerPolicyRules := []rbacv1.PolicyRule{
172+
rbacv1.PolicyRule{Verbs: []string{"*"}, APIGroups: []string{apiGroup}, Resources: []string{mainCRDPlural}},
173+
}
174+
require.Equal(t, managerPolicyRules, role.Rules)
175+
case "e2e-operator-group-edit":
176+
editPolicyRules := []rbacv1.PolicyRule{
177+
rbacv1.PolicyRule{Verbs: []string{"create", "update", "patch", "delete"}, APIGroups: []string{apiGroup}, Resources: []string{mainCRDPlural}},
178+
}
179+
require.Equal(t, editPolicyRules, role.Rules)
180+
case "e2e-operator-group-view":
181+
viewPolicyRules := []rbacv1.PolicyRule{
182+
rbacv1.PolicyRule{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{apiGroup}, Resources: []string{mainCRDPlural}},
183+
}
184+
require.Equal(t, viewPolicyRules, role.Rules)
185+
}
186+
}
187+
142188
t.Log("Waiting for operator namespace csv to have annotations")
143189
err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
144190
fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Get(csvName, metav1.GetOptions{})
@@ -171,8 +217,8 @@ func TestOperatorGroup(t *testing.T) {
171217
require.NoError(t, err)
172218
require.EqualValues(t, v1alpha1.CSVReasonCopied, fetchedCSV.Status.Reason)
173219
// also check name and spec
174-
require.Equal(t, createdCSV.Name, fetchedCSV.Name)
175-
require.Equal(t, createdCSV.Spec, fetchedCSV.Spec)
220+
require.EqualValues(t, createdCSV.Name, fetchedCSV.Name)
221+
require.EqualValues(t, createdCSV.Spec, fetchedCSV.Spec)
176222

177223
t.Log("Waiting on deployment to have correct annotations")
178224
err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
@@ -195,29 +241,18 @@ func TestOperatorGroup(t *testing.T) {
195241
require.NoError(t, err)
196242

197243
t.Log("Waiting for orphaned CSV to be deleted")
198-
err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
244+
err = waitForDelete(func() error {
199245
_, err = crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Get(csvName, metav1.GetOptions{})
200-
if err != nil {
201-
if errors.IsNotFound(err) {
202-
return true, nil
203-
}
204-
return false, err
205-
}
206-
return false, nil
246+
return err
207247
})
208248
require.NoError(t, err)
209249

210250
// clean up
211-
// TODO: unpatch function
212-
runningDeploy, err := c.GetDeployment(testNamespace, "olm-operator")
213-
require.NoError(t, err)
214-
runningDeploy.Spec.Template.Spec.Containers[0].Command = oldCommand
215-
_, updated, err := c.UpdateDeployment(runningDeploy)
216-
if err != nil || updated == false {
217-
t.Fatalf("Deployment update failed: (updated %v) %v\n", updated, err)
218-
}
251+
err = cleanupOlmDeployment()
219252
require.NoError(t, err)
220253

254+
cleanupCRD()
255+
221256
err = c.KubernetesInterface().CoreV1().Namespaces().Delete(otherNamespaceName, &metav1.DeleteOptions{})
222257
require.NoError(t, err)
223258
err = crc.OperatorsV1alpha2().OperatorGroups(testNamespace).Delete(operatorGroup.Name, &metav1.DeleteOptions{})

0 commit comments

Comments
 (0)