Skip to content

Commit c4fbb00

Browse files
committed
OCPBUGS-32262: couldn't find unpack step
1 parent 97c411b commit c4fbb00

File tree

3 files changed

+159
-0
lines changed

3 files changed

+159
-0
lines changed

pkg/controller/registry/resolver/rbac.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ import (
44
"crypto/sha256"
55
"encoding/json"
66
"fmt"
7+
"hash/fnv"
78
"math/big"
89

10+
utilrand "k8s.io/apimachinery/pkg/util/rand"
11+
912
"github.com/operator-framework/api/pkg/operators/v1alpha1"
1013
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
1114
hashutil "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/hash"
@@ -29,6 +32,16 @@ func generateName(base string, o interface{}) (string, error) {
2932
return fmt.Sprintf("%s-%s", base, hash), nil
3033
}
3134

35+
func legacyGenerateName(base string, o interface{}) string {
36+
hasher := fnv.New32a()
37+
hashutil.LegacyDeepHashObject(hasher, o)
38+
hash := utilrand.SafeEncodeString(fmt.Sprint(hasher.Sum32()))
39+
if len(base)+len(hash) > maxNameLength {
40+
base = base[:maxNameLength-len(hash)-1]
41+
}
42+
return fmt.Sprintf("%s-%s", base, hash)
43+
}
44+
3245
type OperatorPermissions struct {
3346
ServiceAccount *corev1.ServiceAccount
3447
Roles []*rbacv1.Role
@@ -233,3 +246,128 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri
233246
}
234247
return permissions, nil
235248
}
249+
250+
func LegacyRBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[string]*OperatorPermissions, error) {
251+
permissions := map[string]*OperatorPermissions{}
252+
253+
// Use a StrategyResolver to get the strategy details
254+
strategyResolver := install.StrategyResolver{}
255+
strategy, err := strategyResolver.UnmarshalStrategy(csv.Spec.InstallStrategy)
256+
if err != nil {
257+
return nil, err
258+
}
259+
260+
// Assume the strategy is for a deployment
261+
strategyDetailsDeployment, ok := strategy.(*v1alpha1.StrategyDetailsDeployment)
262+
if !ok {
263+
return nil, fmt.Errorf("could not assert strategy implementation as deployment for CSV %s", csv.GetName())
264+
}
265+
266+
// Resolve Permissions
267+
for _, permission := range strategyDetailsDeployment.Permissions {
268+
// Create ServiceAccount if necessary
269+
if _, ok := permissions[permission.ServiceAccountName]; !ok {
270+
serviceAccount := &corev1.ServiceAccount{}
271+
serviceAccount.SetNamespace(csv.GetNamespace())
272+
serviceAccount.SetName(permission.ServiceAccountName)
273+
ownerutil.AddNonBlockingOwner(serviceAccount, csv)
274+
275+
permissions[permission.ServiceAccountName] = NewOperatorPermissions(serviceAccount)
276+
}
277+
278+
// Create Role
279+
role := &rbacv1.Role{
280+
ObjectMeta: metav1.ObjectMeta{
281+
Name: legacyGenerateName(fmt.Sprintf("%s-%s", csv.GetName(), permission.ServiceAccountName), []interface{}{csv.GetName(), permission}),
282+
Namespace: csv.GetNamespace(),
283+
OwnerReferences: []metav1.OwnerReference{ownerutil.NonBlockingOwner(csv)},
284+
Labels: ownerutil.OwnerLabel(csv, v1alpha1.ClusterServiceVersionKind),
285+
},
286+
Rules: permission.Rules,
287+
}
288+
hash, err := PolicyRuleHashLabelValue(permission.Rules)
289+
if err != nil {
290+
return nil, fmt.Errorf("failed to hash permission rules: %w", err)
291+
}
292+
role.Labels[ContentHashLabelKey] = hash
293+
permissions[permission.ServiceAccountName].AddRole(role)
294+
295+
// Create RoleBinding
296+
roleBinding := &rbacv1.RoleBinding{
297+
ObjectMeta: metav1.ObjectMeta{
298+
Name: role.GetName(),
299+
Namespace: csv.GetNamespace(),
300+
OwnerReferences: []metav1.OwnerReference{ownerutil.NonBlockingOwner(csv)},
301+
Labels: ownerutil.OwnerLabel(csv, v1alpha1.ClusterServiceVersionKind),
302+
},
303+
RoleRef: rbacv1.RoleRef{
304+
Kind: "Role",
305+
Name: role.GetName(),
306+
APIGroup: rbacv1.GroupName},
307+
Subjects: []rbacv1.Subject{{
308+
Kind: "ServiceAccount",
309+
Name: permission.ServiceAccountName,
310+
Namespace: csv.GetNamespace(),
311+
}},
312+
}
313+
hash, err = RoleReferenceAndSubjectHashLabelValue(roleBinding.RoleRef, roleBinding.Subjects)
314+
if err != nil {
315+
return nil, fmt.Errorf("failed to hash binding content: %w", err)
316+
}
317+
roleBinding.Labels[ContentHashLabelKey] = hash
318+
permissions[permission.ServiceAccountName].AddRoleBinding(roleBinding)
319+
}
320+
321+
// Resolve ClusterPermissions as StepResources
322+
for _, permission := range strategyDetailsDeployment.ClusterPermissions {
323+
// Create ServiceAccount if necessary
324+
if _, ok := permissions[permission.ServiceAccountName]; !ok {
325+
serviceAccount := &corev1.ServiceAccount{}
326+
ownerutil.AddOwner(serviceAccount, csv, false, false)
327+
serviceAccount.SetName(permission.ServiceAccountName)
328+
329+
permissions[permission.ServiceAccountName] = NewOperatorPermissions(serviceAccount)
330+
}
331+
332+
// Create ClusterRole
333+
role := &rbacv1.ClusterRole{
334+
ObjectMeta: metav1.ObjectMeta{
335+
Name: legacyGenerateName(csv.GetName(), []interface{}{csv.GetName(), csv.GetNamespace(), permission}),
336+
Labels: ownerutil.OwnerLabel(csv, v1alpha1.ClusterServiceVersionKind),
337+
},
338+
Rules: permission.Rules,
339+
}
340+
hash, err := PolicyRuleHashLabelValue(permission.Rules)
341+
if err != nil {
342+
return nil, fmt.Errorf("failed to hash permission rules: %w", err)
343+
}
344+
role.Labels[ContentHashLabelKey] = hash
345+
permissions[permission.ServiceAccountName].AddClusterRole(role)
346+
347+
// Create ClusterRoleBinding
348+
roleBinding := &rbacv1.ClusterRoleBinding{
349+
ObjectMeta: metav1.ObjectMeta{
350+
Name: role.GetName(),
351+
Namespace: csv.GetNamespace(),
352+
Labels: ownerutil.OwnerLabel(csv, v1alpha1.ClusterServiceVersionKind),
353+
},
354+
RoleRef: rbacv1.RoleRef{
355+
Kind: "ClusterRole",
356+
Name: role.GetName(),
357+
APIGroup: rbacv1.GroupName,
358+
},
359+
Subjects: []rbacv1.Subject{{
360+
Kind: "ServiceAccount",
361+
Name: permission.ServiceAccountName,
362+
Namespace: csv.GetNamespace(),
363+
}},
364+
}
365+
hash, err = RoleReferenceAndSubjectHashLabelValue(roleBinding.RoleRef, roleBinding.Subjects)
366+
if err != nil {
367+
return nil, fmt.Errorf("failed to hash binding content: %w", err)
368+
}
369+
roleBinding.Labels[ContentHashLabelKey] = hash
370+
permissions[permission.ServiceAccountName].AddClusterRoleBinding(roleBinding)
371+
}
372+
return permissions, nil
373+
}

pkg/controller/registry/resolver/steps.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,13 @@ func NewServiceAccountStepResources(csv *v1alpha1.ClusterServiceVersion, catalog
200200
if err != nil {
201201
return nil, err
202202
}
203+
legacyPerms, err := LegacyRBACForClusterServiceVersion(csv)
204+
if err != nil {
205+
return nil, err
206+
}
207+
for k, v := range legacyPerms {
208+
operatorPermissions[k] = v
209+
}
203210

204211
for _, perms := range operatorPermissions {
205212
if perms.ServiceAccount.Name != "default" {

pkg/lib/kubernetes/pkg/util/hash/hash.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ import (
2020
"crypto/sha256"
2121
"encoding/json"
2222
"fmt"
23+
"hash"
2324
"math/big"
25+
26+
"github.com/davecgh/go-spew/spew"
2427
)
2528

2629
// DeepHashObject writes specified object to hash using the spew library
@@ -53,3 +56,14 @@ func DeepHashObject(obj interface{}) (string, error) {
5356
i.SetBytes(hash[:])
5457
return i.Text(62), nil
5558
}
59+
60+
func LegacyDeepHashObject(hasher hash.Hash, objectToWrite interface{}) {
61+
hasher.Reset()
62+
printer := spew.ConfigState{
63+
Indent: " ",
64+
SortKeys: true,
65+
DisableMethods: true,
66+
SpewKeys: true,
67+
}
68+
printer.Fprintf(hasher, "%#v", objectToWrite)
69+
}

0 commit comments

Comments
 (0)