@@ -30,16 +30,17 @@ import (
30
30
corev1 "k8s.io/api/core/v1"
31
31
rbacv1 "k8s.io/api/rbac/v1"
32
32
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
33
+ "sigs.k8s.io/controller-runtime/pkg/client"
33
34
34
35
"github.com/operator-framework/operator-sdk/internal/generate/collector"
35
36
"github.com/operator-framework/operator-sdk/internal/util/k8sutil"
36
37
)
37
38
38
39
// ApplyTo applies relevant manifests in c to csv, sorts the applied updates,
39
40
// and validates the result.
40
- func ApplyTo (c * collector.Manifests , csv * operatorsv1alpha1.ClusterServiceVersion ) error {
41
+ func ApplyTo (c * collector.Manifests , csv * operatorsv1alpha1.ClusterServiceVersion , extraSAs [] string ) error {
41
42
// Apply manifests to the CSV object.
42
- if err := apply (c , csv ); err != nil {
43
+ if err := apply (c , csv , extraSAs ); err != nil {
43
44
return err
44
45
}
45
46
@@ -50,12 +51,13 @@ func ApplyTo(c *collector.Manifests, csv *operatorsv1alpha1.ClusterServiceVersio
50
51
}
51
52
52
53
// apply applies relevant manifests in c to csv.
53
- func apply (c * collector.Manifests , csv * operatorsv1alpha1.ClusterServiceVersion ) error {
54
+ func apply (c * collector.Manifests , csv * operatorsv1alpha1.ClusterServiceVersion , extraSAs [] string ) error {
54
55
strategy := getCSVInstallStrategy (csv )
55
56
switch strategy .StrategyName {
56
57
case operatorsv1alpha1 .InstallStrategyNameDeployment :
57
- applyRoles (c , & strategy .StrategySpec )
58
- applyClusterRoles (c , & strategy .StrategySpec )
58
+ inPerms , inCPerms , _ := c .SplitCSVPermissionsObjects (extraSAs )
59
+ applyRoles (c , inPerms , & strategy .StrategySpec , extraSAs )
60
+ applyClusterRoles (c , inCPerms , & strategy .StrategySpec , extraSAs )
59
61
applyDeployments (c , & strategy .StrategySpec )
60
62
}
61
63
csv .Spec .InstallStrategy = strategy
@@ -82,34 +84,46 @@ const defaultServiceAccountName = "default"
82
84
83
85
// applyRoles applies Roles to strategy's permissions field by combining Roles bound to ServiceAccounts
84
86
// into one set of permissions.
85
- func applyRoles (c * collector.Manifests , strategy * operatorsv1alpha1.StrategyDetailsDeployment ) { //nolint:dupl
86
- objs , _ := c . SplitCSVPermissionsObjects ( )
87
- roleSet := make (map [string ]* rbacv1.Role )
87
+ func applyRoles (c * collector.Manifests , objs []client. Object , strategy * operatorsv1alpha1.StrategyDetailsDeployment , extraSAs [] string ) { //nolint:dupl
88
+ roleSet := make ( map [ string ]rbacv1. Role )
89
+ cRoleSet := make (map [string ]rbacv1.ClusterRole )
88
90
for i := range objs {
89
91
switch t := objs [i ].(type ) {
90
92
case * rbacv1.Role :
91
- roleSet [t .GetName ()] = t
92
- }
93
- }
94
-
95
- saToPermissions := make (map [string ]operatorsv1alpha1.StrategyDeploymentPermissions )
96
- for _ , dep := range c .Deployments {
97
- saName := dep .Spec .Template .Spec .ServiceAccountName
98
- if saName == "" {
99
- saName = defaultServiceAccountName
93
+ roleSet [t .GetName ()] = * t
94
+ case * rbacv1.ClusterRole :
95
+ cRoleSet [t .GetName ()] = * t
100
96
}
101
- saToPermissions [saName ] = operatorsv1alpha1.StrategyDeploymentPermissions {ServiceAccountName : saName }
102
97
}
103
98
104
- // Collect all role names by their corresponding service accounts via bindings. This lets us
99
+ // Collect all role and cluster role names by their corresponding service accounts via bindings. This lets us
105
100
// look up all service accounts a role is bound to and create one set of permissions per service account.
101
+ saToPermissions := initPermissionSet (c .Deployments , extraSAs )
106
102
for _ , binding := range c .RoleBindings {
107
- if role , hasRole := roleSet [binding .RoleRef .Name ]; hasRole {
108
- for _ , subject := range binding .Subjects {
109
- if perm , hasSA := saToPermissions [subject .Name ]; hasSA && subject .Kind == "ServiceAccount" {
110
- perm .Rules = append (perm .Rules , role .Rules ... )
111
- saToPermissions [subject .Name ] = perm
112
- }
103
+ for _ , subject := range binding .Subjects {
104
+ perm , hasSA := saToPermissions [subject .Name ]
105
+ if subject .Kind != "ServiceAccount" || ! hasSA {
106
+ continue
107
+ }
108
+ var (
109
+ rules []rbacv1.PolicyRule
110
+ hasRole bool
111
+ )
112
+ switch binding .RoleRef .Kind {
113
+ case "Role" :
114
+ role , has := roleSet [binding .RoleRef .Name ]
115
+ rules = role .Rules
116
+ hasRole = has
117
+ case "ClusterRole" :
118
+ role , has := cRoleSet [binding .RoleRef .Name ]
119
+ rules = role .Rules
120
+ hasRole = has
121
+ default :
122
+ continue
123
+ }
124
+ if hasRole {
125
+ perm .Rules = append (perm .Rules , rules ... )
126
+ saToPermissions [subject .Name ] = perm
113
127
}
114
128
}
115
129
}
@@ -121,39 +135,35 @@ func applyRoles(c *collector.Manifests, strategy *operatorsv1alpha1.StrategyDeta
121
135
perms = append (perms , perm )
122
136
}
123
137
}
138
+ sort .Slice (perms , func (i , j int ) bool {
139
+ return perms [i ].ServiceAccountName < perms [j ].ServiceAccountName
140
+ })
124
141
strategy .Permissions = perms
125
142
}
126
143
127
144
// applyClusterRoles applies ClusterRoles to strategy's clusterPermissions field by combining ClusterRoles
128
145
// bound to ServiceAccounts into one set of clusterPermissions.
129
- func applyClusterRoles (c * collector.Manifests , strategy * operatorsv1alpha1.StrategyDetailsDeployment ) { //nolint:dupl
130
- objs , _ := c .SplitCSVClusterPermissionsObjects ()
131
- roleSet := make (map [string ]* rbacv1.ClusterRole )
146
+ func applyClusterRoles (c * collector.Manifests , objs []client.Object , strategy * operatorsv1alpha1.StrategyDetailsDeployment , extraSAs []string ) { //nolint:dupl
147
+ roleSet := make (map [string ]rbacv1.ClusterRole )
132
148
for i := range objs {
133
149
switch t := objs [i ].(type ) {
134
150
case * rbacv1.ClusterRole :
135
- roleSet [t .GetName ()] = t
151
+ roleSet [t .GetName ()] = * t
136
152
}
137
153
}
138
154
139
- saToPermissions := make (map [string ]operatorsv1alpha1.StrategyDeploymentPermissions )
140
- for _ , dep := range c .Deployments {
141
- saName := dep .Spec .Template .Spec .ServiceAccountName
142
- if saName == "" {
143
- saName = defaultServiceAccountName
144
- }
145
- saToPermissions [saName ] = operatorsv1alpha1.StrategyDeploymentPermissions {ServiceAccountName : saName }
146
- }
147
-
148
155
// Collect all role names by their corresponding service accounts via bindings. This lets us
149
156
// look up all service accounts a role is bound to and create one set of permissions per service account.
157
+ saToPermissions := initPermissionSet (c .Deployments , extraSAs )
150
158
for _ , binding := range c .ClusterRoleBindings {
151
- if role , hasRole := roleSet [binding .RoleRef .Name ]; hasRole {
152
- for _ , subject := range binding .Subjects {
153
- if perm , hasSA := saToPermissions [subject .Name ]; hasSA && subject .Kind == "ServiceAccount" {
154
- perm .Rules = append (perm .Rules , role .Rules ... )
155
- saToPermissions [subject .Name ] = perm
156
- }
159
+ for _ , subject := range binding .Subjects {
160
+ perm , hasSA := saToPermissions [subject .Name ]
161
+ if ! hasSA || subject .Kind != "ServiceAccount" {
162
+ continue
163
+ }
164
+ if role , hasRole := roleSet [binding .RoleRef .Name ]; hasRole {
165
+ perm .Rules = append (perm .Rules , role .Rules ... )
166
+ saToPermissions [subject .Name ] = perm
157
167
}
158
168
}
159
169
}
@@ -165,9 +175,28 @@ func applyClusterRoles(c *collector.Manifests, strategy *operatorsv1alpha1.Strat
165
175
perms = append (perms , perm )
166
176
}
167
177
}
178
+ sort .Slice (perms , func (i , j int ) bool {
179
+ return perms [i ].ServiceAccountName < perms [j ].ServiceAccountName
180
+ })
168
181
strategy .ClusterPermissions = perms
169
182
}
170
183
184
+ // initPermissionSet initializes a map of ServiceAccount name to permissions, which are empty.
185
+ func initPermissionSet (deps []appsv1.Deployment , extraSAs []string ) map [string ]operatorsv1alpha1.StrategyDeploymentPermissions {
186
+ saToPermissions := make (map [string ]operatorsv1alpha1.StrategyDeploymentPermissions )
187
+ for _ , dep := range deps {
188
+ saName := dep .Spec .Template .Spec .ServiceAccountName
189
+ if saName == "" {
190
+ saName = defaultServiceAccountName
191
+ }
192
+ saToPermissions [saName ] = operatorsv1alpha1.StrategyDeploymentPermissions {ServiceAccountName : saName }
193
+ }
194
+ for _ , extraSA := range extraSAs {
195
+ saToPermissions [extraSA ] = operatorsv1alpha1.StrategyDeploymentPermissions {ServiceAccountName : extraSA }
196
+ }
197
+ return saToPermissions
198
+ }
199
+
171
200
// applyDeployments updates strategy's deployments with the Deployments
172
201
// in the collector.
173
202
func applyDeployments (c * collector.Manifests , strategy * operatorsv1alpha1.StrategyDetailsDeployment ) {
0 commit comments