Skip to content

Commit eea8fba

Browse files
author
Per Goncalves da Silva
committed
Replace rukpak Convert() with BundleRenderer
Signed-off-by: Per Goncalves da Silva <[email protected]>
1 parent 50c04df commit eea8fba

File tree

9 files changed

+1966
-295
lines changed

9 files changed

+1966
-295
lines changed
+206
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
package convert
2+
3+
import (
4+
"cmp"
5+
"fmt"
6+
"strings"
7+
8+
corev1 "k8s.io/api/core/v1"
9+
rbacv1 "k8s.io/api/rbac/v1"
10+
"k8s.io/apimachinery/pkg/util/sets"
11+
"k8s.io/utils/ptr"
12+
"sigs.k8s.io/controller-runtime/pkg/client"
13+
14+
registrybundle "github.com/operator-framework/operator-registry/pkg/lib/bundle"
15+
16+
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/util"
17+
)
18+
19+
type ResourceGenerator func(rv1 *RegistryV1, opts Options) ([]client.Object, error)
20+
21+
func (g ResourceGenerator) GenerateResources(rv1 *RegistryV1, opts Options) ([]client.Object, error) {
22+
return g(rv1, opts)
23+
}
24+
25+
type ResourceGenerators []ResourceGenerator
26+
27+
func (r ResourceGenerators) GenerateResources(rv1 *RegistryV1, opts Options) ([]client.Object, error) {
28+
//nolint:prealloc
29+
var renderedObjects []client.Object
30+
for _, generator := range r {
31+
objs, err := generator.GenerateResources(rv1, opts)
32+
if err != nil {
33+
return nil, err
34+
}
35+
renderedObjects = append(renderedObjects, objs...)
36+
}
37+
return renderedObjects, nil
38+
}
39+
40+
func (r ResourceGenerators) ResourceGenerator() ResourceGenerator {
41+
return r.GenerateResources
42+
}
43+
44+
var BundleCSVRBACResourceGenerator = ResourceGenerators{
45+
BundleCSVServiceAccountGenerator,
46+
BundleCSVPermissionsGenerator,
47+
BundleCSVClusterPermissionsGenerator,
48+
}
49+
50+
func BundleCSVDeploymentGenerator(rv1 *RegistryV1, opts Options) ([]client.Object, error) {
51+
if rv1 == nil {
52+
return nil, fmt.Errorf("bundle cannot be nil")
53+
}
54+
objs := make([]client.Object, 0, len(rv1.CSV.Spec.InstallStrategy.StrategySpec.DeploymentSpecs))
55+
for _, depSpec := range rv1.CSV.Spec.InstallStrategy.StrategySpec.DeploymentSpecs {
56+
annotations := util.MergeMaps(rv1.CSV.Annotations, depSpec.Spec.Template.Annotations)
57+
annotations["olm.targetNamespaces"] = strings.Join(opts.TargetNamespaces, ",")
58+
depSpec.Spec.Template.Annotations = annotations
59+
60+
// Hardcode the deployment with RevisionHistoryLimit=1 to maintain parity with OLMv0 behaviour.
61+
// See https://github.com/operator-framework/operator-lifecycle-manager/blob/dfd0b2bea85038d3c0d65348bc812d297f16b8d2/pkg/controller/install/deployment.go#L177-L180
62+
depSpec.Spec.RevisionHistoryLimit = ptr.To(int32(1))
63+
64+
objs = append(objs,
65+
GenerateDeploymentResource(
66+
depSpec.Name,
67+
opts.InstallNamespace,
68+
WithDeploymentSpec(depSpec.Spec),
69+
WithLabels(depSpec.Label),
70+
),
71+
)
72+
}
73+
return objs, nil
74+
}
75+
76+
func BundleCSVPermissionsGenerator(rv1 *RegistryV1, opts Options) ([]client.Object, error) {
77+
if rv1 == nil {
78+
return nil, fmt.Errorf("bundle cannot be nil")
79+
}
80+
81+
// If we're in AllNamespaces mode permissions will be treated as clusterPermissions
82+
if len(opts.TargetNamespaces) == 1 && opts.TargetNamespaces[0] == "" {
83+
return nil, nil
84+
}
85+
86+
permissions := rv1.CSV.Spec.InstallStrategy.StrategySpec.Permissions
87+
88+
objs := make([]client.Object, 0, 2*len(opts.TargetNamespaces)*len(permissions))
89+
for _, ns := range opts.TargetNamespaces {
90+
for _, permission := range permissions {
91+
saName := saNameOrDefault(permission.ServiceAccountName)
92+
name, err := opts.UniqueNameGenerator(fmt.Sprintf("%s-%s", rv1.CSV.Name, saName), permission)
93+
if err != nil {
94+
return nil, err
95+
}
96+
97+
objs = append(objs,
98+
GenerateRoleResource(name, ns, WithRules(permission.Rules...)),
99+
GenerateRoleBindingResource(
100+
name,
101+
ns,
102+
WithSubjects(rbacv1.Subject{Kind: "ServiceAccount", Namespace: opts.InstallNamespace, Name: saName}),
103+
WithRoleRef(rbacv1.RoleRef{APIGroup: rbacv1.GroupName, Kind: "Role", Name: name}),
104+
),
105+
)
106+
}
107+
}
108+
return objs, nil
109+
}
110+
111+
func BundleCSVClusterPermissionsGenerator(rv1 *RegistryV1, opts Options) ([]client.Object, error) {
112+
if rv1 == nil {
113+
return nil, fmt.Errorf("bundle cannot be nil")
114+
}
115+
clusterPermissions := rv1.CSV.Spec.InstallStrategy.StrategySpec.ClusterPermissions
116+
117+
// If we're in AllNamespaces mode, promote the permissions to clusterPermissions
118+
if len(opts.TargetNamespaces) == 1 && opts.TargetNamespaces[0] == "" {
119+
for _, p := range rv1.CSV.Spec.InstallStrategy.StrategySpec.Permissions {
120+
p.Rules = append(p.Rules, rbacv1.PolicyRule{
121+
Verbs: []string{"get", "list", "watch"},
122+
APIGroups: []string{corev1.GroupName},
123+
Resources: []string{"namespaces"},
124+
})
125+
clusterPermissions = append(clusterPermissions, p)
126+
}
127+
}
128+
129+
objs := make([]client.Object, 0, 2*len(clusterPermissions))
130+
for _, permission := range clusterPermissions {
131+
saName := saNameOrDefault(permission.ServiceAccountName)
132+
name, err := opts.UniqueNameGenerator(fmt.Sprintf("%s-%s", rv1.CSV.Name, saName), permission)
133+
if err != nil {
134+
return nil, err
135+
}
136+
objs = append(objs,
137+
GenerateClusterRoleResource(name, WithRules(permission.Rules...)),
138+
GenerateClusterRoleBindingResource(
139+
name,
140+
WithSubjects(rbacv1.Subject{Kind: "ServiceAccount", Namespace: opts.InstallNamespace, Name: saName}),
141+
WithRoleRef(rbacv1.RoleRef{APIGroup: rbacv1.GroupName, Kind: "ClusterRole", Name: name}),
142+
),
143+
)
144+
}
145+
return objs, nil
146+
}
147+
148+
func BundleCSVServiceAccountGenerator(rv1 *RegistryV1, opts Options) ([]client.Object, error) {
149+
if rv1 == nil {
150+
return nil, fmt.Errorf("bundle cannot be nil")
151+
}
152+
allPermissions := append(
153+
rv1.CSV.Spec.InstallStrategy.StrategySpec.Permissions,
154+
rv1.CSV.Spec.InstallStrategy.StrategySpec.ClusterPermissions...,
155+
)
156+
157+
serviceAccountNames := sets.Set[string]{}
158+
for _, permission := range allPermissions {
159+
serviceAccountNames.Insert(saNameOrDefault(permission.ServiceAccountName))
160+
}
161+
162+
objs := make([]client.Object, 0, len(serviceAccountNames))
163+
for _, serviceAccountName := range serviceAccountNames.UnsortedList() {
164+
// no need to generate the default service account
165+
if serviceAccountName != "default" {
166+
objs = append(objs, GenerateServiceAccountResource(serviceAccountName, opts.InstallNamespace))
167+
}
168+
}
169+
return objs, nil
170+
}
171+
172+
func BundleCRDGenerator(rv1 *RegistryV1, _ Options) ([]client.Object, error) {
173+
if rv1 == nil {
174+
return nil, fmt.Errorf("bundle cannot be nil")
175+
}
176+
objs := make([]client.Object, 0, len(rv1.CRDs))
177+
for _, crd := range rv1.CRDs {
178+
objs = append(objs, crd.DeepCopy())
179+
}
180+
return objs, nil
181+
}
182+
183+
func BundleAdditionalResourcesGenerator(rv1 *RegistryV1, opts Options) ([]client.Object, error) {
184+
if rv1 == nil {
185+
return nil, fmt.Errorf("bundle cannot be nil")
186+
}
187+
objs := make([]client.Object, 0, len(rv1.Others))
188+
for _, res := range rv1.Others {
189+
supported, namespaced := registrybundle.IsSupported(res.GetKind())
190+
if !supported {
191+
return nil, fmt.Errorf("bundle contains unsupported resource: Name: %v, Kind: %v", res.GetName(), res.GetKind())
192+
}
193+
194+
obj := res.DeepCopy()
195+
if namespaced {
196+
obj.SetNamespace(opts.InstallNamespace)
197+
}
198+
199+
objs = append(objs, obj)
200+
}
201+
return objs, nil
202+
}
203+
204+
func saNameOrDefault(saName string) string {
205+
return cmp.Or(saName, "default")
206+
}

0 commit comments

Comments
 (0)