Skip to content

Commit 9585806

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 9585806

File tree

9 files changed

+1979
-295
lines changed

9 files changed

+1979
-295
lines changed
+210
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
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+
if depSpec.Spec.Template.Spec.ServiceAccountName == "" {
61+
depSpec.Spec.Template.Spec.ServiceAccountName = "default"
62+
}
63+
64+
// Hardcode the deployment with RevisionHistoryLimit=1 to maintain parity with OLMv0 behaviour.
65+
// See https://github.com/operator-framework/operator-lifecycle-manager/blob/dfd0b2bea85038d3c0d65348bc812d297f16b8d2/pkg/controller/install/deployment.go#L177-L180
66+
depSpec.Spec.RevisionHistoryLimit = ptr.To(int32(1))
67+
68+
objs = append(objs,
69+
GenerateDeploymentResource(
70+
depSpec.Name,
71+
opts.InstallNamespace,
72+
WithDeploymentSpec(depSpec.Spec),
73+
WithLabels(depSpec.Label),
74+
),
75+
)
76+
}
77+
return objs, nil
78+
}
79+
80+
func BundleCSVPermissionsGenerator(rv1 *RegistryV1, opts Options) ([]client.Object, error) {
81+
if rv1 == nil {
82+
return nil, fmt.Errorf("bundle cannot be nil")
83+
}
84+
85+
// If we're in AllNamespaces mode permissions will be treated as clusterPermissions
86+
if len(opts.TargetNamespaces) == 1 && opts.TargetNamespaces[0] == "" {
87+
return nil, nil
88+
}
89+
90+
permissions := rv1.CSV.Spec.InstallStrategy.StrategySpec.Permissions
91+
92+
objs := make([]client.Object, 0, 2*len(opts.TargetNamespaces)*len(permissions))
93+
for _, ns := range opts.TargetNamespaces {
94+
for _, permission := range permissions {
95+
saName := saNameOrDefault(permission.ServiceAccountName)
96+
name, err := opts.UniqueNameGenerator(fmt.Sprintf("%s-%s", rv1.CSV.Name, saName), permission)
97+
if err != nil {
98+
return nil, err
99+
}
100+
101+
objs = append(objs,
102+
GenerateRoleResource(name, ns, WithRules(permission.Rules...)),
103+
GenerateRoleBindingResource(
104+
name,
105+
ns,
106+
WithSubjects(rbacv1.Subject{Kind: "ServiceAccount", Namespace: opts.InstallNamespace, Name: saName}),
107+
WithRoleRef(rbacv1.RoleRef{APIGroup: rbacv1.GroupName, Kind: "Role", Name: name}),
108+
),
109+
)
110+
}
111+
}
112+
return objs, nil
113+
}
114+
115+
func BundleCSVClusterPermissionsGenerator(rv1 *RegistryV1, opts Options) ([]client.Object, error) {
116+
if rv1 == nil {
117+
return nil, fmt.Errorf("bundle cannot be nil")
118+
}
119+
clusterPermissions := rv1.CSV.Spec.InstallStrategy.StrategySpec.ClusterPermissions
120+
121+
// If we're in AllNamespaces mode, promote the permissions to clusterPermissions
122+
if len(opts.TargetNamespaces) == 1 && opts.TargetNamespaces[0] == "" {
123+
for _, p := range rv1.CSV.Spec.InstallStrategy.StrategySpec.Permissions {
124+
p.Rules = append(p.Rules, rbacv1.PolicyRule{
125+
Verbs: []string{"get", "list", "watch"},
126+
APIGroups: []string{corev1.GroupName},
127+
Resources: []string{"namespaces"},
128+
})
129+
clusterPermissions = append(clusterPermissions, p)
130+
}
131+
}
132+
133+
objs := make([]client.Object, 0, 2*len(clusterPermissions))
134+
for _, permission := range clusterPermissions {
135+
saName := saNameOrDefault(permission.ServiceAccountName)
136+
name, err := opts.UniqueNameGenerator(fmt.Sprintf("%s-%s", rv1.CSV.Name, saName), permission)
137+
if err != nil {
138+
return nil, err
139+
}
140+
objs = append(objs,
141+
GenerateClusterRoleResource(name, WithRules(permission.Rules...)),
142+
GenerateClusterRoleBindingResource(
143+
name,
144+
WithSubjects(rbacv1.Subject{Kind: "ServiceAccount", Namespace: opts.InstallNamespace, Name: saName}),
145+
WithRoleRef(rbacv1.RoleRef{APIGroup: rbacv1.GroupName, Kind: "ClusterRole", Name: name}),
146+
),
147+
)
148+
}
149+
return objs, nil
150+
}
151+
152+
func BundleCSVServiceAccountGenerator(rv1 *RegistryV1, opts Options) ([]client.Object, error) {
153+
if rv1 == nil {
154+
return nil, fmt.Errorf("bundle cannot be nil")
155+
}
156+
allPermissions := append(
157+
rv1.CSV.Spec.InstallStrategy.StrategySpec.Permissions,
158+
rv1.CSV.Spec.InstallStrategy.StrategySpec.ClusterPermissions...,
159+
)
160+
161+
serviceAccountNames := sets.Set[string]{}
162+
for _, permission := range allPermissions {
163+
serviceAccountNames.Insert(saNameOrDefault(permission.ServiceAccountName))
164+
}
165+
166+
objs := make([]client.Object, 0, len(serviceAccountNames))
167+
for _, serviceAccountName := range serviceAccountNames.UnsortedList() {
168+
// no need to generate the default service account
169+
if serviceAccountName != "default" {
170+
objs = append(objs, GenerateServiceAccountResource(serviceAccountName, opts.InstallNamespace))
171+
}
172+
}
173+
return objs, nil
174+
}
175+
176+
func BundleCRDGenerator(rv1 *RegistryV1, _ Options) ([]client.Object, error) {
177+
if rv1 == nil {
178+
return nil, fmt.Errorf("bundle cannot be nil")
179+
}
180+
objs := make([]client.Object, 0, len(rv1.CRDs))
181+
for _, crd := range rv1.CRDs {
182+
objs = append(objs, crd.DeepCopy())
183+
}
184+
return objs, nil
185+
}
186+
187+
func BundleAdditionalResourcesGenerator(rv1 *RegistryV1, opts Options) ([]client.Object, error) {
188+
if rv1 == nil {
189+
return nil, fmt.Errorf("bundle cannot be nil")
190+
}
191+
objs := make([]client.Object, 0, len(rv1.Others))
192+
for _, res := range rv1.Others {
193+
supported, namespaced := registrybundle.IsSupported(res.GetKind())
194+
if !supported {
195+
return nil, fmt.Errorf("bundle contains unsupported resource: Name: %v, Kind: %v", res.GetName(), res.GetKind())
196+
}
197+
198+
obj := res.DeepCopy()
199+
if namespaced {
200+
obj.SetNamespace(opts.InstallNamespace)
201+
}
202+
203+
objs = append(objs, obj)
204+
}
205+
return objs, nil
206+
}
207+
208+
func saNameOrDefault(saName string) string {
209+
return cmp.Or(saName, "default")
210+
}

0 commit comments

Comments
 (0)