in tooling/mcerepkg/internal/rukpak/convert/registryv1.go [188:342]
func Convert(in RegistryV1, installNamespace string, targetNamespaces []string) (*Plain, error) {
if installNamespace == "" {
installNamespace = in.CSV.Annotations["operatorframework.io/suggested-namespace"]
}
if installNamespace == "" {
installNamespace = fmt.Sprintf("%s-system", in.PackageName)
}
supportedInstallModes := sets.New[string]()
for _, im := range in.CSV.Spec.InstallModes {
if im.Supported {
supportedInstallModes.Insert(string(im.Type))
}
}
if len(targetNamespaces) == 0 {
if supportedInstallModes.Has(string(v1alpha1.InstallModeTypeAllNamespaces)) {
targetNamespaces = []string{""}
} else if supportedInstallModes.Has(string(v1alpha1.InstallModeTypeOwnNamespace)) {
targetNamespaces = []string{installNamespace}
}
}
if err := validateTargetNamespaces(supportedInstallModes, installNamespace, targetNamespaces); err != nil {
return nil, err
}
if len(in.CSV.Spec.APIServiceDefinitions.Owned) > 0 {
return nil, fmt.Errorf("apiServiceDefintions are not supported")
}
if len(in.CSV.Spec.WebhookDefinitions) > 0 {
return nil, fmt.Errorf("webhookDefinitions are not supported")
}
deployments := []appsv1.Deployment{}
serviceAccounts := map[string]corev1.ServiceAccount{}
for _, depSpec := range in.CSV.Spec.InstallStrategy.StrategySpec.DeploymentSpecs {
annotations := util.MergeMaps(in.CSV.Annotations, depSpec.Spec.Template.Annotations)
annotations["olm.targetNamespaces"] = strings.Join(targetNamespaces, ",")
deployments = append(deployments, appsv1.Deployment{
TypeMeta: metav1.TypeMeta{
Kind: "Deployment",
APIVersion: appsv1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Namespace: installNamespace,
Name: depSpec.Name,
Labels: depSpec.Label,
Annotations: annotations,
},
Spec: depSpec.Spec,
})
saName := saNameOrDefault(depSpec.Spec.Template.Spec.ServiceAccountName)
serviceAccounts[saName] = newServiceAccount(installNamespace, saName)
}
// NOTES:
// 1. There's an extra Role for OperatorConditions: get/update/patch; resourceName=csv.name
// - 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
// 2. There's an extra RoleBinding for the above mentioned role.
// - 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
// 3. strategySpec.permissions are _also_ given a clusterrole/clusterrole binding.
// - (for AllNamespaces mode only?)
// - (where does the extra namespaces get/list/watch rule come from?)
roles := []rbacv1.Role{}
roleBindings := []rbacv1.RoleBinding{}
clusterRoles := []rbacv1.ClusterRole{}
clusterRoleBindings := []rbacv1.ClusterRoleBinding{}
permissions := in.CSV.Spec.InstallStrategy.StrategySpec.Permissions
clusterPermissions := in.CSV.Spec.InstallStrategy.StrategySpec.ClusterPermissions
allPermissions := append(permissions, clusterPermissions...)
// Create all the service accounts
for _, permission := range allPermissions {
saName := saNameOrDefault(permission.ServiceAccountName)
if _, ok := serviceAccounts[saName]; !ok {
serviceAccounts[saName] = newServiceAccount(installNamespace, saName)
}
}
// If we're in AllNamespaces mode, promote the permissions to clusterPermissions
if len(targetNamespaces) == 1 && targetNamespaces[0] == "" {
for _, p := range permissions {
p.Rules = append(p.Rules, rbacv1.PolicyRule{
Verbs: []string{"get", "list", "watch"},
APIGroups: []string{corev1.GroupName},
Resources: []string{"namespaces"},
})
}
clusterPermissions = append(clusterPermissions, permissions...)
permissions = nil
}
for _, ns := range targetNamespaces {
for _, permission := range permissions {
saName := saNameOrDefault(permission.ServiceAccountName)
name, err := generateName(fmt.Sprintf("%s-%s", in.CSV.Name, saName), permission)
if err != nil {
return nil, err
}
roles = append(roles, newRole(ns, name, permission.Rules))
roleBindings = append(roleBindings, newRoleBinding(ns, name, name, installNamespace, saName))
}
}
for _, permission := range clusterPermissions {
saName := saNameOrDefault(permission.ServiceAccountName)
name, err := generateName(fmt.Sprintf("%s-%s", in.CSV.Name, saName), permission)
if err != nil {
return nil, err
}
clusterRoles = append(clusterRoles, newClusterRole(name, permission.Rules))
clusterRoleBindings = append(clusterRoleBindings, newClusterRoleBinding(name, name, installNamespace, saName))
}
objs := []client.Object{}
for _, obj := range serviceAccounts {
obj := obj
if obj.GetName() != "default" {
objs = append(objs, &obj)
}
}
for _, obj := range roles {
obj := obj
objs = append(objs, &obj)
}
for _, obj := range roleBindings {
obj := obj
objs = append(objs, &obj)
}
for _, obj := range clusterRoles {
obj := obj
objs = append(objs, &obj)
}
for _, obj := range clusterRoleBindings {
obj := obj
objs = append(objs, &obj)
}
for _, obj := range in.CRDs {
obj := obj
objs = append(objs, &obj)
}
for _, obj := range in.Others {
obj := obj
obj.SetNamespace(installNamespace)
objs = append(objs, &obj)
}
for _, obj := range deployments {
obj := obj
objs = append(objs, &obj)
}
return &Plain{Objects: objs}, nil
}