@@ -7,37 +7,25 @@ import (
7
7
"fmt"
8
8
"io/fs"
9
9
"path/filepath"
10
- "strings"
11
10
12
11
"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"
16
12
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
17
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
18
13
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
19
14
"k8s.io/apimachinery/pkg/runtime"
20
15
"k8s.io/apimachinery/pkg/util/sets"
21
16
"k8s.io/cli-runtime/pkg/resource"
22
- "k8s.io/utils/ptr"
23
17
"sigs.k8s.io/controller-runtime/pkg/client"
24
18
"sigs.k8s.io/yaml"
25
19
26
20
"github.com/operator-framework/api/pkg/operators/v1alpha1"
27
21
"github.com/operator-framework/operator-registry/alpha/property"
28
- registrybundle "github.com/operator-framework/operator-registry/pkg/lib/bundle"
29
22
30
23
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"
32
27
)
33
28
34
- type RegistryV1 struct {
35
- PackageName string
36
- CSV v1alpha1.ClusterServiceVersion
37
- CRDs []apiextensionsv1.CustomResourceDefinition
38
- Others []unstructured.Unstructured
39
- }
40
-
41
29
type Plain struct {
42
30
Objects []client.Object
43
31
}
@@ -70,16 +58,16 @@ func RegistryV1ToHelmChart(rv1 fs.FS, installNamespace string, watchNamespace st
70
58
return chrt , nil
71
59
}
72
60
73
- // ParseFS converts the rv1 filesystem into a RegistryV1.
61
+ // ParseFS converts the rv1 filesystem into a render. RegistryV1.
74
62
// ParseFS expects the filesystem to conform to the registry+v1 format:
75
63
// metadata/annotations.yaml
76
64
// manifests/
77
65
// - csv.yaml
78
66
// - ...
79
67
//
80
68
// 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 {}
83
71
annotationsFileData , err := fs .ReadFile (rv1 , filepath .Join ("metadata" , "annotations.yaml" ))
84
72
if err != nil {
85
73
return reg , err
@@ -224,22 +212,23 @@ func validateTargetNamespaces(supportedInstallModes sets.Set[string], installNam
224
212
return fmt .Errorf ("supported install modes %v do not support target namespaces %v" , sets.List [string ](supportedInstallModes ), targetNamespaces )
225
213
}
226
214
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
+ },
232
225
}
233
226
234
227
type Converter struct {
235
- BundleValidator BundleValidator
228
+ render. BundleRenderer
236
229
}
237
230
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 ) {
243
232
if installNamespace == "" {
244
233
installNamespace = rv1 .CSV .Annotations ["operatorframework.io/suggested-namespace" ]
245
234
}
@@ -272,246 +261,9 @@ func (c Converter) Convert(rv1 RegistryV1, installNamespace string, targetNamesp
272
261
return nil , fmt .Errorf ("webhookDefinitions are not supported" )
273
262
}
274
263
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 )
416
265
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
516
267
}
268
+ return & Plain {Objects : objs }, nil
517
269
}
0 commit comments