github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/operators/catalog/manifests.go (about) 1 package catalog 2 3 import ( 4 "encoding/json" 5 "fmt" 6 7 "github.com/operator-framework/api/pkg/operators/v1alpha1" 8 "github.com/operator-framework/operator-registry/pkg/configmap" 9 errorwrap "github.com/pkg/errors" 10 "github.com/sirupsen/logrus" 11 v1 "k8s.io/client-go/listers/core/v1" 12 13 "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver" 14 "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/projection" 15 ) 16 17 // ManifestResolver can dereference a manifest for a step. Steps may embed manifests directly or reference content 18 // in configmaps 19 type ManifestResolver interface { 20 ManifestForStep(step *v1alpha1.Step) (string, error) 21 } 22 23 // manifestResolver caches manifest from unpacked bundles (via configmaps) 24 type manifestResolver struct { 25 configMapLister v1.ConfigMapLister 26 unpackedSteps map[string][]v1alpha1.StepResource 27 namespace string 28 logger logrus.FieldLogger 29 } 30 31 func newManifestResolver(namespace string, configMapLister v1.ConfigMapLister, logger logrus.FieldLogger) *manifestResolver { 32 return &manifestResolver{ 33 namespace: namespace, 34 configMapLister: configMapLister, 35 unpackedSteps: map[string][]v1alpha1.StepResource{}, 36 logger: logger, 37 } 38 } 39 40 // ManifestForStep always returns the manifest that should be applied to the cluster for a given step 41 // the manifest field in the installplan status can contain a reference to a configmap instead 42 func (r *manifestResolver) ManifestForStep(step *v1alpha1.Step) (string, error) { 43 manifest := step.Resource.Manifest 44 ref := refForStep(step, r.logger) 45 if ref == nil { 46 return manifest, nil 47 } 48 49 log := r.logger.WithFields(logrus.Fields{"resolving": step.Resolving, "step": step.Resource.Name}) 50 log.WithField("ref", ref).Debug("step is a reference to configmap") 51 52 usteps, err := r.unpackedStepsForBundle(step.Resolving, ref) 53 if err != nil { 54 return "", err 55 } 56 57 log.Debugf("checking cache for unpacked step") 58 // need to find the real manifest from the unpacked steps 59 for _, u := range usteps { 60 if u.Name == step.Resource.Name && 61 u.Kind == step.Resource.Kind && 62 u.Version == step.Resource.Version && 63 u.Group == step.Resource.Group { 64 manifest = u.Manifest 65 log.WithField("manifest", manifest).Debug("step replaced with unpacked value") 66 break 67 } 68 } 69 if manifest == step.Resource.Manifest { 70 return "", fmt.Errorf("couldn't find unpacked step for %v", step) 71 } 72 return manifest, nil 73 } 74 75 func (r *manifestResolver) unpackedStepsForBundle(bundleName string, ref *UnpackedBundleReference) ([]v1alpha1.StepResource, error) { 76 usteps, ok := r.unpackedSteps[bundleName] 77 if ok { 78 return usteps, nil 79 } 80 cm, err := r.configMapLister.ConfigMaps(ref.Namespace).Get(ref.Name) 81 if err != nil { 82 return nil, errorwrap.Wrapf(err, "error finding unpacked bundle configmap for ref %v", *ref) 83 } 84 loader := configmap.NewBundleLoader() 85 bundle, err := loader.Load(cm) 86 if err != nil { 87 return nil, errorwrap.Wrapf(err, "error loading unpacked bundle configmap for ref %v", *ref) 88 } 89 90 if ref.Properties != "" { 91 props, err := projection.PropertyListFromPropertiesAnnotation(ref.Properties) 92 if err != nil { 93 return nil, fmt.Errorf("failed to load bundle properties for %q: %w", bundle.CsvName, err) 94 } 95 bundle.Properties = props 96 } 97 98 steps, err := resolver.NewStepResourceFromBundle(bundle, r.namespace, ref.Replaces, ref.CatalogSourceName, ref.CatalogSourceNamespace) 99 if err != nil { 100 return nil, errorwrap.Wrapf(err, "error calculating steps for ref %v", *ref) 101 } 102 r.unpackedSteps[bundleName] = steps 103 return steps, nil 104 } 105 106 func refForStep(step *v1alpha1.Step, log logrus.FieldLogger) *UnpackedBundleReference { 107 log = log.WithFields(logrus.Fields{"resolving": step.Resolving, "step": step.Resource.Name}) 108 var ref UnpackedBundleReference 109 if err := json.Unmarshal([]byte(step.Resource.Manifest), &ref); err != nil { 110 log.Debug("step is not a reference to an unpacked bundle (this is not an error if the step is a manifest)") 111 return nil 112 } 113 log = log.WithField("ref", ref) 114 if ref.Kind != "ConfigMap" || ref.Name == "" || ref.Namespace == "" || ref.CatalogSourceName == "" || ref.CatalogSourceNamespace == "" { 115 log.Debug("step is not a reference to an unpacked bundle (this is not an error if the step is a manifest)") 116 return nil 117 } 118 return &ref 119 }