github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/registry/resolver/steps.go (about) 1 package resolver 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "strings" 8 9 olmerrors "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/errors" 10 "github.com/operator-framework/operator-registry/pkg/api" 11 extScheme "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme" 12 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 14 "k8s.io/apimachinery/pkg/runtime" 15 k8sjson "k8s.io/apimachinery/pkg/runtime/serializer/json" 16 utilruntime "k8s.io/apimachinery/pkg/util/runtime" 17 "k8s.io/apimachinery/pkg/util/yaml" 18 k8sscheme "k8s.io/client-go/kubernetes/scheme" 19 20 "github.com/operator-framework/api/pkg/operators/v1alpha1" 21 "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/cache" 22 "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/projection" 23 "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil" 24 ) 25 26 const ( 27 secretKind = "Secret" 28 BundleSecretKind = "BundleSecret" 29 ) 30 31 var ( 32 scheme = runtime.NewScheme() 33 ) 34 35 func init() { 36 utilruntime.Must(k8sscheme.AddToScheme(scheme)) 37 utilruntime.Must(extScheme.AddToScheme(scheme)) 38 utilruntime.Must(v1alpha1.AddToScheme(scheme)) 39 } 40 41 // NewStepResourceForObject returns a new StepResource for the provided object 42 func NewStepResourceFromObject(obj runtime.Object, catalogSourceName, catalogSourceNamespace string) (v1alpha1.StepResource, error) { 43 var resource v1alpha1.StepResource 44 45 // set up object serializer 46 serializer := k8sjson.NewSerializer(k8sjson.DefaultMetaFactory, scheme, scheme, false) 47 48 // create an object manifest 49 var manifest bytes.Buffer 50 err := serializer.Encode(obj, &manifest) 51 if err != nil { 52 return resource, err 53 } 54 55 if err := ownerutil.InferGroupVersionKind(obj); err != nil { 56 return resource, err 57 } 58 59 gvk := obj.GetObjectKind().GroupVersionKind() 60 61 metaObj, ok := obj.(metav1.Object) 62 if !ok { 63 return resource, fmt.Errorf("couldn't get object metadata") 64 } 65 66 name := metaObj.GetName() 67 if name == "" { 68 name = metaObj.GetGenerateName() 69 } 70 71 // create the resource 72 resource = v1alpha1.StepResource{ 73 Name: name, 74 Kind: gvk.Kind, 75 Group: gvk.Group, 76 Version: gvk.Version, 77 Manifest: manifest.String(), 78 CatalogSource: catalogSourceName, 79 CatalogSourceNamespace: catalogSourceNamespace, 80 } 81 82 // BundleSecret is a synthetic kind that OLM uses to distinguish between secrets included in the bundle and 83 // pull secrets included in the installplan 84 if obj.GetObjectKind().GroupVersionKind().Kind == secretKind { 85 resource.Kind = BundleSecretKind 86 } 87 88 return resource, nil 89 } 90 91 func NewSubscriptionStepResource(namespace string, info cache.OperatorSourceInfo) (v1alpha1.StepResource, error) { 92 return NewStepResourceFromObject(&v1alpha1.Subscription{ 93 ObjectMeta: metav1.ObjectMeta{ 94 Namespace: namespace, 95 Name: strings.Join([]string{info.Package, info.Channel, info.Catalog.Name, info.Catalog.Namespace}, "-"), 96 }, 97 Spec: &v1alpha1.SubscriptionSpec{ 98 CatalogSource: info.Catalog.Name, 99 CatalogSourceNamespace: info.Catalog.Namespace, 100 Package: info.Package, 101 Channel: info.Channel, 102 StartingCSV: info.StartingCSV, 103 InstallPlanApproval: v1alpha1.ApprovalAutomatic, 104 }, 105 }, info.Catalog.Name, info.Catalog.Namespace) 106 } 107 108 func V1alpha1CSVFromBundle(bundle *api.Bundle) (*v1alpha1.ClusterServiceVersion, error) { 109 csv := &v1alpha1.ClusterServiceVersion{} 110 if err := json.Unmarshal([]byte(bundle.CsvJson), csv); err != nil { 111 return nil, err 112 } 113 return csv, nil 114 } 115 116 func NewStepResourceFromBundle(bundle *api.Bundle, namespace, replaces, catalogSourceName, catalogSourceNamespace string) ([]v1alpha1.StepResource, error) { 117 csv, err := V1alpha1CSVFromBundle(bundle) 118 if err != nil { 119 return nil, err 120 } 121 122 // Check unpacked bundled for for missing APIVersion or Kind 123 if csv.APIVersion == "" { 124 return nil, olmerrors.NewFatalError(fmt.Errorf("bundle CSV %s missing APIVersion", csv.Name)) 125 } 126 127 if csv.Kind == "" { 128 return nil, olmerrors.NewFatalError(fmt.Errorf("bundle CSV %s missing Kind", csv.Name)) 129 } 130 131 csv.SetNamespace(namespace) 132 csv.Spec.Replaces = replaces 133 anno, err := projection.PropertiesAnnotationFromPropertyList(bundle.Properties) 134 if err != nil { 135 return nil, fmt.Errorf("failed to construct properties annotation for %q: %w", csv.GetName(), err) 136 } 137 138 annos := csv.GetAnnotations() 139 if annos == nil { 140 annos = make(map[string]string) 141 } 142 annos[projection.PropertiesAnnotationKey] = anno 143 csv.SetAnnotations(annos) 144 145 step, err := NewStepResourceFromObject(csv, catalogSourceName, catalogSourceNamespace) 146 if err != nil { 147 return nil, err 148 } 149 steps := []v1alpha1.StepResource{step} 150 151 for _, object := range bundle.Object { 152 dec := yaml.NewYAMLOrJSONDecoder(strings.NewReader(object), 10) 153 unst := &unstructured.Unstructured{} 154 if err := dec.Decode(unst); err != nil { 155 return nil, err 156 } 157 158 if unst.GetObjectKind().GroupVersionKind().Kind == v1alpha1.ClusterServiceVersionKind { 159 continue 160 } 161 162 step, err := NewStepResourceFromObject(unst, catalogSourceName, catalogSourceNamespace) 163 if err != nil { 164 return nil, err 165 } 166 steps = append(steps, step) 167 } 168 169 operatorServiceAccountSteps, err := NewServiceAccountStepResources(csv, catalogSourceName, catalogSourceNamespace) 170 if err != nil { 171 return nil, err 172 } 173 steps = append(steps, operatorServiceAccountSteps...) 174 return steps, nil 175 } 176 177 func NewStepsFromBundle(bundle *api.Bundle, namespace, replaces, catalogSourceName, catalogSourceNamespace string) ([]*v1alpha1.Step, error) { 178 bundleSteps, err := NewStepResourceFromBundle(bundle, namespace, replaces, catalogSourceName, catalogSourceNamespace) 179 if err != nil { 180 return nil, err 181 } 182 183 var steps []*v1alpha1.Step 184 for _, s := range bundleSteps { 185 steps = append(steps, &v1alpha1.Step{ 186 Resolving: bundle.CsvName, 187 Resource: s, 188 Status: v1alpha1.StepStatusUnknown, 189 }) 190 } 191 192 return steps, nil 193 } 194 195 // NewServiceAccountStepResources returns a list of step resources required to satisfy the RBAC requirements of the given CSV's InstallStrategy 196 func NewServiceAccountStepResources(csv *v1alpha1.ClusterServiceVersion, catalogSourceName, catalogSourceNamespace string) ([]v1alpha1.StepResource, error) { 197 var rbacSteps []v1alpha1.StepResource 198 199 operatorPermissions, err := RBACForClusterServiceVersion(csv) 200 if err != nil { 201 return nil, err 202 } 203 204 for _, perms := range operatorPermissions { 205 if perms.ServiceAccount.Name != "default" { 206 step, err := NewStepResourceFromObject(perms.ServiceAccount, catalogSourceName, catalogSourceNamespace) 207 if err != nil { 208 return nil, err 209 } 210 rbacSteps = append(rbacSteps, step) 211 } 212 for _, role := range perms.Roles { 213 step, err := NewStepResourceFromObject(role, catalogSourceName, catalogSourceNamespace) 214 if err != nil { 215 return nil, err 216 } 217 rbacSteps = append(rbacSteps, step) 218 } 219 for _, roleBinding := range perms.RoleBindings { 220 step, err := NewStepResourceFromObject(roleBinding, catalogSourceName, catalogSourceNamespace) 221 if err != nil { 222 return nil, err 223 } 224 rbacSteps = append(rbacSteps, step) 225 } 226 for _, clusterRole := range perms.ClusterRoles { 227 step, err := NewStepResourceFromObject(clusterRole, catalogSourceName, catalogSourceNamespace) 228 if err != nil { 229 return nil, err 230 } 231 rbacSteps = append(rbacSteps, step) 232 } 233 for _, clusterRoleBinding := range perms.ClusterRoleBindings { 234 step, err := NewStepResourceFromObject(clusterRoleBinding, catalogSourceName, catalogSourceNamespace) 235 if err != nil { 236 return nil, err 237 } 238 rbacSteps = append(rbacSteps, step) 239 } 240 } 241 return rbacSteps, nil 242 }