Skip to content

Commit 744a674

Browse files
Per Goncalves da Silvaperdasilva
Per Goncalves da Silva
authored andcommitted
Replace rukpak Convert() with BundleRenderer
Signed-off-by: Per Goncalves da Silva <[email protected]>
1 parent 0bcdd61 commit 744a674

File tree

14 files changed

+2344
-389
lines changed

14 files changed

+2344
-389
lines changed

Diff for: internal/operator-controller/rukpak/convert/registryv1.go

+21-269
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,25 @@ import (
77
"fmt"
88
"io/fs"
99
"path/filepath"
10-
"strings"
1110

1211
"helm.sh/helm/v3/pkg/chart"
13-
appsv1 "k8s.io/api/apps/v1"
14-
corev1 "k8s.io/api/core/v1"
15-
rbacv1 "k8s.io/api/rbac/v1"
1612
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
17-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1813
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1914
"k8s.io/apimachinery/pkg/runtime"
2015
"k8s.io/apimachinery/pkg/util/sets"
2116
"k8s.io/cli-runtime/pkg/resource"
22-
"k8s.io/utils/ptr"
2317
"sigs.k8s.io/controller-runtime/pkg/client"
2418
"sigs.k8s.io/yaml"
2519

2620
"github.com/operator-framework/api/pkg/operators/v1alpha1"
2721
"github.com/operator-framework/operator-registry/alpha/property"
28-
registrybundle "github.com/operator-framework/operator-registry/pkg/lib/bundle"
2922

3023
registry "github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/operator-registry"
31-
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/util"
24+
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/render"
25+
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/render/generators"
26+
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/render/validators"
3227
)
3328

34-
type RegistryV1 struct {
35-
PackageName string
36-
CSV v1alpha1.ClusterServiceVersion
37-
CRDs []apiextensionsv1.CustomResourceDefinition
38-
Others []unstructured.Unstructured
39-
}
40-
4129
type Plain struct {
4230
Objects []client.Object
4331
}
@@ -70,16 +58,16 @@ func RegistryV1ToHelmChart(rv1 fs.FS, installNamespace string, watchNamespace st
7058
return chrt, nil
7159
}
7260

73-
// ParseFS converts the rv1 filesystem into a RegistryV1.
61+
// ParseFS converts the rv1 filesystem into a render.RegistryV1.
7462
// ParseFS expects the filesystem to conform to the registry+v1 format:
7563
// metadata/annotations.yaml
7664
// manifests/
7765
// - csv.yaml
7866
// - ...
7967
//
8068
// manifests directory does not contain subdirectories
81-
func ParseFS(rv1 fs.FS) (RegistryV1, error) {
82-
reg := RegistryV1{}
69+
func ParseFS(rv1 fs.FS) (render.RegistryV1, error) {
70+
reg := render.RegistryV1{}
8371
annotationsFileData, err := fs.ReadFile(rv1, filepath.Join("metadata", "annotations.yaml"))
8472
if err != nil {
8573
return reg, err
@@ -224,22 +212,23 @@ func validateTargetNamespaces(supportedInstallModes sets.Set[string], installNam
224212
return fmt.Errorf("supported install modes %v do not support target namespaces %v", sets.List[string](supportedInstallModes), targetNamespaces)
225213
}
226214

227-
func saNameOrDefault(saName string) string {
228-
if saName == "" {
229-
return "default"
230-
}
231-
return saName
215+
var PlainConverter = Converter{
216+
BundleRenderer: render.BundleRenderer{
217+
BundleValidator: validators.RegistryV1BundleValidator,
218+
ResourceGenerators: []render.ResourceGenerator{
219+
generators.BundleCSVRBACResourceGenerator.ResourceGenerator(),
220+
generators.BundleCRDGenerator,
221+
generators.BundleAdditionalResourcesGenerator,
222+
generators.BundleCSVDeploymentGenerator,
223+
},
224+
},
232225
}
233226

234227
type Converter struct {
235-
BundleValidator BundleValidator
228+
render.BundleRenderer
236229
}
237230

238-
func (c Converter) Convert(rv1 RegistryV1, installNamespace string, targetNamespaces []string) (*Plain, error) {
239-
if err := c.BundleValidator.Validate(&rv1); err != nil {
240-
return nil, err
241-
}
242-
231+
func (c Converter) Convert(rv1 render.RegistryV1, installNamespace string, targetNamespaces []string) (*Plain, error) {
243232
if installNamespace == "" {
244233
installNamespace = rv1.CSV.Annotations["operatorframework.io/suggested-namespace"]
245234
}
@@ -272,246 +261,9 @@ func (c Converter) Convert(rv1 RegistryV1, installNamespace string, targetNamesp
272261
return nil, fmt.Errorf("webhookDefinitions are not supported")
273262
}
274263

275-
deployments := []appsv1.Deployment{}
276-
serviceAccounts := map[string]corev1.ServiceAccount{}
277-
for _, depSpec := range rv1.CSV.Spec.InstallStrategy.StrategySpec.DeploymentSpecs {
278-
annotations := util.MergeMaps(rv1.CSV.Annotations, depSpec.Spec.Template.Annotations)
279-
annotations["olm.targetNamespaces"] = strings.Join(targetNamespaces, ",")
280-
depSpec.Spec.Template.Annotations = annotations
281-
282-
// Hardcode the deployment with RevisionHistoryLimit=1 to replicate OLMv0 behavior
283-
// https://github.com/operator-framework/operator-lifecycle-manager/blob/dfd0b2bea85038d3c0d65348bc812d297f16b8d2/pkg/controller/install/deployment.go#L181
284-
depSpec.Spec.RevisionHistoryLimit = ptr.To(int32(1))
285-
286-
deployments = append(deployments, appsv1.Deployment{
287-
TypeMeta: metav1.TypeMeta{
288-
Kind: "Deployment",
289-
APIVersion: appsv1.SchemeGroupVersion.String(),
290-
},
291-
292-
ObjectMeta: metav1.ObjectMeta{
293-
Namespace: installNamespace,
294-
Name: depSpec.Name,
295-
Labels: depSpec.Label,
296-
},
297-
Spec: depSpec.Spec,
298-
})
299-
saName := saNameOrDefault(depSpec.Spec.Template.Spec.ServiceAccountName)
300-
serviceAccounts[saName] = newServiceAccount(installNamespace, saName)
301-
}
302-
303-
// NOTES:
304-
// 1. There's an extra Role for OperatorConditions: get/update/patch; resourceName=csv.name
305-
// - This is managed by the OperatorConditions controller here: https://github.com/operator-framework/operator-lifecycle-manager/blob/9ced412f3e263b8827680dc0ad3477327cd9a508/pkg/controller/operators/operatorcondition_controller.go#L106-L109
306-
// 2. There's an extra RoleBinding for the above mentioned role.
307-
// - Every SA mentioned in the OperatorCondition.spec.serviceAccounts is a subject for this role binding: https://github.com/operator-framework/operator-lifecycle-manager/blob/9ced412f3e263b8827680dc0ad3477327cd9a508/pkg/controller/operators/operatorcondition_controller.go#L171-L177
308-
// 3. strategySpec.permissions are _also_ given a clusterrole/clusterrole binding.
309-
// - (for AllNamespaces mode only?)
310-
// - (where does the extra namespaces get/list/watch rule come from?)
311-
312-
roles := []rbacv1.Role{}
313-
roleBindings := []rbacv1.RoleBinding{}
314-
clusterRoles := []rbacv1.ClusterRole{}
315-
clusterRoleBindings := []rbacv1.ClusterRoleBinding{}
316-
317-
permissions := rv1.CSV.Spec.InstallStrategy.StrategySpec.Permissions
318-
clusterPermissions := rv1.CSV.Spec.InstallStrategy.StrategySpec.ClusterPermissions
319-
allPermissions := append(permissions, clusterPermissions...)
320-
321-
// Create all the service accounts
322-
for _, permission := range allPermissions {
323-
saName := saNameOrDefault(permission.ServiceAccountName)
324-
if _, ok := serviceAccounts[saName]; !ok {
325-
serviceAccounts[saName] = newServiceAccount(installNamespace, saName)
326-
}
327-
}
328-
329-
// If we're in AllNamespaces mode, promote the permissions to clusterPermissions
330-
if len(targetNamespaces) == 1 && targetNamespaces[0] == "" {
331-
for _, p := range permissions {
332-
p.Rules = append(p.Rules, rbacv1.PolicyRule{
333-
Verbs: []string{"get", "list", "watch"},
334-
APIGroups: []string{corev1.GroupName},
335-
Resources: []string{"namespaces"},
336-
})
337-
clusterPermissions = append(clusterPermissions, p)
338-
}
339-
permissions = nil
340-
}
341-
342-
for _, ns := range targetNamespaces {
343-
for _, permission := range permissions {
344-
saName := saNameOrDefault(permission.ServiceAccountName)
345-
name, err := generateName(fmt.Sprintf("%s-%s", rv1.CSV.Name, saName), permission)
346-
if err != nil {
347-
return nil, err
348-
}
349-
roles = append(roles, newRole(ns, name, permission.Rules))
350-
roleBindings = append(roleBindings, newRoleBinding(ns, name, name, installNamespace, saName))
351-
}
352-
}
353-
354-
for _, permission := range clusterPermissions {
355-
saName := saNameOrDefault(permission.ServiceAccountName)
356-
name, err := generateName(fmt.Sprintf("%s-%s", rv1.CSV.Name, saName), permission)
357-
if err != nil {
358-
return nil, err
359-
}
360-
clusterRoles = append(clusterRoles, newClusterRole(name, permission.Rules))
361-
clusterRoleBindings = append(clusterRoleBindings, newClusterRoleBinding(name, name, installNamespace, saName))
362-
}
363-
364-
objs := []client.Object{}
365-
for _, obj := range serviceAccounts {
366-
obj := obj
367-
if obj.GetName() != "default" {
368-
objs = append(objs, &obj)
369-
}
370-
}
371-
for _, obj := range roles {
372-
obj := obj
373-
objs = append(objs, &obj)
374-
}
375-
for _, obj := range roleBindings {
376-
obj := obj
377-
objs = append(objs, &obj)
378-
}
379-
for _, obj := range clusterRoles {
380-
obj := obj
381-
objs = append(objs, &obj)
382-
}
383-
for _, obj := range clusterRoleBindings {
384-
obj := obj
385-
objs = append(objs, &obj)
386-
}
387-
for _, obj := range rv1.CRDs {
388-
objs = append(objs, &obj)
389-
}
390-
for _, obj := range rv1.Others {
391-
obj := obj
392-
supported, namespaced := registrybundle.IsSupported(obj.GetKind())
393-
if !supported {
394-
return nil, fmt.Errorf("bundle contains unsupported resource: Name: %v, Kind: %v", obj.GetName(), obj.GetKind())
395-
}
396-
if namespaced {
397-
obj.SetNamespace(installNamespace)
398-
}
399-
objs = append(objs, &obj)
400-
}
401-
for _, obj := range deployments {
402-
obj := obj
403-
objs = append(objs, &obj)
404-
}
405-
return &Plain{Objects: objs}, nil
406-
}
407-
408-
var PlainConverter = Converter{
409-
BundleValidator: RegistryV1BundleValidator,
410-
}
411-
412-
const maxNameLength = 63
413-
414-
func generateName(base string, o interface{}) (string, error) {
415-
hashStr, err := util.DeepHashObject(o)
264+
objs, err := c.BundleRenderer.Render(rv1, installNamespace, targetNamespaces)
416265
if err != nil {
417-
return "", err
418-
}
419-
if len(base)+len(hashStr) > maxNameLength {
420-
base = base[:maxNameLength-len(hashStr)-1]
421-
}
422-
423-
return fmt.Sprintf("%s-%s", base, hashStr), nil
424-
}
425-
426-
func newServiceAccount(namespace, name string) corev1.ServiceAccount {
427-
return corev1.ServiceAccount{
428-
TypeMeta: metav1.TypeMeta{
429-
Kind: "ServiceAccount",
430-
APIVersion: corev1.SchemeGroupVersion.String(),
431-
},
432-
ObjectMeta: metav1.ObjectMeta{
433-
Namespace: namespace,
434-
Name: name,
435-
},
436-
}
437-
}
438-
439-
func newRole(namespace, name string, rules []rbacv1.PolicyRule) rbacv1.Role {
440-
return rbacv1.Role{
441-
TypeMeta: metav1.TypeMeta{
442-
Kind: "Role",
443-
APIVersion: rbacv1.SchemeGroupVersion.String(),
444-
},
445-
ObjectMeta: metav1.ObjectMeta{
446-
Namespace: namespace,
447-
Name: name,
448-
},
449-
Rules: rules,
450-
}
451-
}
452-
453-
func newClusterRole(name string, rules []rbacv1.PolicyRule) rbacv1.ClusterRole {
454-
return rbacv1.ClusterRole{
455-
TypeMeta: metav1.TypeMeta{
456-
Kind: "ClusterRole",
457-
APIVersion: rbacv1.SchemeGroupVersion.String(),
458-
},
459-
ObjectMeta: metav1.ObjectMeta{
460-
Name: name,
461-
},
462-
Rules: rules,
463-
}
464-
}
465-
466-
func newRoleBinding(namespace, name, roleName, saNamespace string, saNames ...string) rbacv1.RoleBinding {
467-
subjects := make([]rbacv1.Subject, 0, len(saNames))
468-
for _, saName := range saNames {
469-
subjects = append(subjects, rbacv1.Subject{
470-
Kind: "ServiceAccount",
471-
Namespace: saNamespace,
472-
Name: saName,
473-
})
474-
}
475-
return rbacv1.RoleBinding{
476-
TypeMeta: metav1.TypeMeta{
477-
Kind: "RoleBinding",
478-
APIVersion: rbacv1.SchemeGroupVersion.String(),
479-
},
480-
ObjectMeta: metav1.ObjectMeta{
481-
Namespace: namespace,
482-
Name: name,
483-
},
484-
Subjects: subjects,
485-
RoleRef: rbacv1.RoleRef{
486-
APIGroup: rbacv1.GroupName,
487-
Kind: "Role",
488-
Name: roleName,
489-
},
490-
}
491-
}
492-
493-
func newClusterRoleBinding(name, roleName, saNamespace string, saNames ...string) rbacv1.ClusterRoleBinding {
494-
subjects := make([]rbacv1.Subject, 0, len(saNames))
495-
for _, saName := range saNames {
496-
subjects = append(subjects, rbacv1.Subject{
497-
Kind: "ServiceAccount",
498-
Namespace: saNamespace,
499-
Name: saName,
500-
})
501-
}
502-
return rbacv1.ClusterRoleBinding{
503-
TypeMeta: metav1.TypeMeta{
504-
Kind: "ClusterRoleBinding",
505-
APIVersion: rbacv1.SchemeGroupVersion.String(),
506-
},
507-
ObjectMeta: metav1.ObjectMeta{
508-
Name: name,
509-
},
510-
Subjects: subjects,
511-
RoleRef: rbacv1.RoleRef{
512-
APIGroup: rbacv1.GroupName,
513-
Kind: "ClusterRole",
514-
Name: roleName,
515-
},
266+
return nil, err
516267
}
268+
return &Plain{Objects: objs}, nil
517269
}

0 commit comments

Comments
 (0)