Skip to content

Commit 7aaadf9

Browse files
author
Per Goncalves da Silva
committed
add render package
Signed-off-by: Per Goncalves da Silva <[email protected]>
1 parent e49597a commit 7aaadf9

File tree

8 files changed

+2011
-1
lines changed

8 files changed

+2011
-1
lines changed

internal/operator-controller/rukpak/convert/registryv1.go

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

0 commit comments

Comments
 (0)