From fa90bf37d3ad476ef619eefd422ff02eee29b2b6 Mon Sep 17 00:00:00 2001 From: David Eads Date: Tue, 2 May 2023 08:55:13 -0400 Subject: [PATCH 1/2] update library-go for rendering readers --- go.mod | 2 +- go.sum | 4 +- .../featuregates/featuregate.go | 47 ++++++ .../hardcoded_featuregate_reader.go | 4 +- .../featuregates/observe_featuregates.go | 31 ++-- .../featuregates/simple_featuregate_reader.go | 12 +- .../pkg/operator/render/options/config.go | 147 ++++++++++++++++-- .../pkg/operator/render/options/generic.go | 102 +++++++++--- vendor/modules.txt | 2 +- 9 files changed, 285 insertions(+), 66 deletions(-) create mode 100644 vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/featuregate.go diff --git a/go.mod b/go.mod index 11a80f3cd..b6513d0db 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/openshift/api v0.0.0-20230426193520-54a14470e5dc github.com/openshift/build-machinery-go v0.0.0-20220913142420-e25cf57ea46d github.com/openshift/client-go v0.0.0-20230120202327-72f107311084 - github.com/openshift/library-go v0.0.0-20230427133628-add9892da47e + github.com/openshift/library-go v0.0.0-20230502125217-e45be8351afe github.com/spf13/cobra v1.6.0 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.0 diff --git a/go.sum b/go.sum index 0f7f7bdb0..274e21e79 100644 --- a/go.sum +++ b/go.sum @@ -418,8 +418,8 @@ github.com/openshift/build-machinery-go v0.0.0-20220913142420-e25cf57ea46d h1:RR github.com/openshift/build-machinery-go v0.0.0-20220913142420-e25cf57ea46d/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= github.com/openshift/client-go v0.0.0-20230120202327-72f107311084 h1:66uaqNwA+qYyQDwsMWUfjjau8ezmg1dzCqub13KZOcE= github.com/openshift/client-go v0.0.0-20230120202327-72f107311084/go.mod h1:M3h9m001PWac3eAudGG3isUud6yBjr5XpzLYLLTlHKo= -github.com/openshift/library-go v0.0.0-20230427133628-add9892da47e h1:GFyfPd8IsGfsVANMM+WtNxmy0XBvvXF2Ie7Duzjbui0= -github.com/openshift/library-go v0.0.0-20230427133628-add9892da47e/go.mod h1:JLv17uWyQvoK14yxp7h2vBJ8zz2xkWqanOv5TzuFkvY= +github.com/openshift/library-go v0.0.0-20230502125217-e45be8351afe h1:vD0AgG+SQdktMtRKAfrGc91Ib5AJbGqnAfFFYzArAdY= +github.com/openshift/library-go v0.0.0-20230502125217-e45be8351afe/go.mod h1:JLv17uWyQvoK14yxp7h2vBJ8zz2xkWqanOv5TzuFkvY= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= diff --git a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/featuregate.go b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/featuregate.go new file mode 100644 index 000000000..5ff0f3af0 --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/featuregate.go @@ -0,0 +1,47 @@ +package featuregates + +import ( + "fmt" + configv1 "github.com/openshift/api/config/v1" + "k8s.io/apimachinery/pkg/util/sets" +) + +// FeatureGate indicates whether a given feature is enabled or not +// This interface is heavily influenced by k8s.io/component-base, but not exactly compatible. +type FeatureGate interface { + // Enabled returns true if the key is enabled. + Enabled(key configv1.FeatureGateName) bool + // KnownFeatures returns a slice of strings describing the FeatureGate's known features. + KnownFeatures() []configv1.FeatureGateName +} + +type featureGate struct { + enabled sets.Set[configv1.FeatureGateName] + disabled sets.Set[configv1.FeatureGateName] +} + +func NewFeatureGate(enabled, disabled []configv1.FeatureGateName) FeatureGate { + return &featureGate{ + enabled: sets.New[configv1.FeatureGateName](enabled...), + disabled: sets.New[configv1.FeatureGateName](disabled...), + } +} + +func (f *featureGate) Enabled(key configv1.FeatureGateName) bool { + if f.enabled.Has(key) { + return true + } + if f.disabled.Has(key) { + return false + } + + panic(fmt.Errorf("feature %q is not registered in FeatureGates %v", key, f.KnownFeatures())) +} + +func (f *featureGate) KnownFeatures() []configv1.FeatureGateName { + allKnown := sets.NewString() + allKnown.Insert(FeatureGateNamesToStrings(f.enabled.UnsortedList())...) + allKnown.Insert(FeatureGateNamesToStrings(f.disabled.UnsortedList())...) + + return StringsToFeatureGateNames(allKnown.List()) +} diff --git a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/hardcoded_featuregate_reader.go b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/hardcoded_featuregate_reader.go index 9188cfc32..58ae71763 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/hardcoded_featuregate_reader.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/hardcoded_featuregate_reader.go @@ -61,8 +61,8 @@ func (c *hardcodedFeatureGateAccess) AreInitialFeatureGatesObserved() bool { } } -func (c *hardcodedFeatureGateAccess) CurrentFeatureGates() ([]configv1.FeatureGateName, []configv1.FeatureGateName, error) { - return c.enabled, c.disabled, c.readErr +func (c *hardcodedFeatureGateAccess) CurrentFeatureGates() (FeatureGate, error) { + return NewFeatureGate(c.enabled, c.disabled), c.readErr } // NewHardcodedFeatureGateAccessFromFeatureGate returns a FeatureGateAccess that is static and initialised from diff --git a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/observe_featuregates.go b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/observe_featuregates.go index c004bf77c..0f2cb85fd 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/observe_featuregates.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/observe_featuregates.go @@ -13,10 +13,6 @@ import ( "github.com/openshift/library-go/pkg/operator/events" ) -type FeatureGateAccessor interface { - FeatureGates() FeatureGateAccess -} - // NewObserveFeatureFlagsFunc produces a configobserver for feature gates. If non-nil, the featureWhitelist filters // feature gates to a known subset (instead of everything). The featureBlacklist will stop certain features from making // it through the list. The featureBlacklist should be empty, but for a brief time, some featuregates may need to skipped. @@ -51,12 +47,12 @@ func (f *featureFlags) ObserveFeatureFlags(genericListers configobserver.Listers return prunedExistingConfig, nil } - enabledFeatures, disabledFeatures, err := f.featureGateAccess.CurrentFeatureGates() + featureGates, err := f.featureGateAccess.CurrentFeatureGates() if err != nil { return prunedExistingConfig, append(errs, err) } observedConfig := map[string]interface{}{} - newConfigValue := f.getWhitelistedFeatureNames(enabledFeatures, disabledFeatures) + newConfigValue := f.getWhitelistedFeatureNames(featureGates) currentConfigValue, _, err := unstructured.NestedStringSlice(existingConfig, f.configPath...) if err != nil { @@ -75,7 +71,7 @@ func (f *featureFlags) ObserveFeatureFlags(genericListers configobserver.Listers return configobserver.Pruned(observedConfig, f.configPath), errs } -func (f *featureFlags) getWhitelistedFeatureNames(enabledFeatures, disabledFeatures []configv1.FeatureGateName) []string { +func (f *featureFlags) getWhitelistedFeatureNames(featureGates FeatureGate) []string { newConfigValue := []string{} formatEnabledFunc := func(fs configv1.FeatureGateName) string { return fmt.Sprintf("%v=true", fs) @@ -84,25 +80,20 @@ func (f *featureFlags) getWhitelistedFeatureNames(enabledFeatures, disabledFeatu return fmt.Sprintf("%v=false", fs) } - for _, enable := range enabledFeatures { - if f.featureBlacklist.Has(enable) { + for _, knownFeatureGate := range featureGates.KnownFeatures() { + if f.featureBlacklist.Has(knownFeatureGate) { continue } // only add whitelisted feature flags - if !f.allowAll && !f.featureWhitelist.Has(enable) { - continue - } - newConfigValue = append(newConfigValue, formatEnabledFunc(enable)) - } - for _, disable := range disabledFeatures { - if f.featureBlacklist.Has(disable) { + if !f.allowAll && !f.featureWhitelist.Has(knownFeatureGate) { continue } - // only add whitelisted feature flags - if !f.allowAll && !f.featureWhitelist.Has(disable) { - continue + + if featureGates.Enabled(knownFeatureGate) { + newConfigValue = append(newConfigValue, formatEnabledFunc(knownFeatureGate)) + } else { + newConfigValue = append(newConfigValue, formatDisabledFunc(knownFeatureGate)) } - newConfigValue = append(newConfigValue, formatDisabledFunc(disable)) } return newConfigValue diff --git a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/simple_featuregate_reader.go b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/simple_featuregate_reader.go index 247613896..4b2caccd6 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/simple_featuregate_reader.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/simple_featuregate_reader.go @@ -44,7 +44,7 @@ type FeatureGateAccess interface { InitialFeatureGatesObserved() <-chan struct{} // CurrentFeatureGates returns the list of enabled and disabled featuregates. // It returns an error if the current set of featuregates is not known. - CurrentFeatureGates() (enabled []configv1.FeatureGateName, disabled []configv1.FeatureGateName, err error) + CurrentFeatureGates() (FeatureGate, error) // AreInitialFeatureGatesObserved returns true if the initial featuregates have been observed. AreInitialFeatureGatesObserved() bool } @@ -93,8 +93,8 @@ go featureGateAccessor.Run(ctx) select{ case <- featureGateAccessor.InitialFeatureGatesObserved(): - enabled, disabled, _ := featureGateAccessor.CurrentFeatureGates() - klog.Infof("FeatureGates initialized: enabled=%v disabled=%v", enabled, disabled) + featureGates, _ := featureGateAccessor.CurrentFeatureGates() + klog.Infof("FeatureGates initialized: knownFeatureGates=%v", featureGates.KnownFeatures()) case <- time.After(1*time.Minute): klog.Errorf("timed out waiting for FeatureGate detection") return fmt.Errorf("timed out waiting for FeatureGate detection") @@ -254,19 +254,19 @@ func (c *defaultFeatureGateAccess) AreInitialFeatureGatesObserved() bool { } } -func (c *defaultFeatureGateAccess) CurrentFeatureGates() ([]configv1.FeatureGateName, []configv1.FeatureGateName, error) { +func (c *defaultFeatureGateAccess) CurrentFeatureGates() (FeatureGate, error) { c.lock.Lock() defer c.lock.Unlock() if !c.AreInitialFeatureGatesObserved() { - return nil, nil, fmt.Errorf("featureGates not yet observed") + return nil, fmt.Errorf("featureGates not yet observed") } retEnabled := make([]configv1.FeatureGateName, len(c.currentFeatures.Enabled)) retDisabled := make([]configv1.FeatureGateName, len(c.currentFeatures.Disabled)) copy(retEnabled, c.currentFeatures.Enabled) copy(retDisabled, c.currentFeatures.Disabled) - return retEnabled, retDisabled, nil + return NewFeatureGate(retEnabled, retDisabled), nil } func (c *defaultFeatureGateAccess) runWorker(ctx context.Context) { diff --git a/vendor/github.com/openshift/library-go/pkg/operator/render/options/config.go b/vendor/github.com/openshift/library-go/pkg/operator/render/options/config.go index 8aa28116e..2f016f5b5 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/render/options/config.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/render/options/config.go @@ -1,7 +1,16 @@ package options import ( + "fmt" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + + utilerrors "k8s.io/apimachinery/pkg/util/errors" + + "k8s.io/apimachinery/pkg/api/meta" + "github.com/openshift/library-go/pkg/operator/resource/resourceread" + "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/klog/v2" @@ -34,19 +43,16 @@ type ManifestConfig struct { ImagePullPolicy string } -// FileConfig type FileConfig struct { // BootstrapConfig holds the rendered control plane component config file for bootstrapping (phase 1). BootstrapConfig []byte // Assets holds the loaded assets like certs and keys. Assets map[string][]byte - - // RenderedManifests are the files, content, and (optionally) decoded objects that were passed to the command - // as already present to be created by cluster-bootstrap. - RenderedManifests []RenderedManifest } +type RenderedManifests []RenderedManifest + type RenderedManifest struct { OriginalFilename string Content []byte @@ -60,29 +66,148 @@ type TemplateData struct { FileConfig } -func (c *FileConfig) ListManifestOfType(gvk schema.GroupVersionKind) []RenderedManifest { +func (renderedManifests RenderedManifests) ListManifestOfType(gvk schema.GroupVersionKind) []RenderedManifest { ret := []RenderedManifest{} - for i := range c.RenderedManifests { - obj, err := c.RenderedManifests[i].GetDecodedObj() + for i := range renderedManifests { + obj, err := renderedManifests[i].GetDecodedObj() if err != nil { - klog.Warningf("failure to read %q: %v", c.RenderedManifests[i].OriginalFilename, err) + klog.Warningf("failure to read %q: %v", renderedManifests[i].OriginalFilename, err) continue } if obj.GetObjectKind().GroupVersionKind() == gvk { - ret = append(ret, c.RenderedManifests[i]) + ret = append(ret, renderedManifests[i]) } } return ret } +func (renderedManifests RenderedManifests) GetManifest(gvk schema.GroupVersionKind, namespace, name string) (RenderedManifest, error) { + for i := range renderedManifests { + obj, err := renderedManifests[i].GetDecodedObj() + if err != nil { + klog.Warningf("failure to read %q: %v", renderedManifests[i].OriginalFilename, err) + continue + } + if obj.GetObjectKind().GroupVersionKind() != gvk { + continue + } + objMetadata, err := meta.Accessor(obj) + if err != nil { + klog.Warningf("failure to read metadata %q: %v", renderedManifests[i].OriginalFilename, err) + continue + } + + // since validation requires that all of these are the same, it doesn't matterwhich one we return + if objMetadata.GetName() == name && objMetadata.GetNamespace() == namespace { + return renderedManifests[i], nil + } + } + + return RenderedManifest{}, apierrors.NewNotFound( + schema.GroupResource{ + Group: gvk.Group, + Resource: gvk.Kind, + }, + name) +} + +func (renderedManifests RenderedManifests) GetObject(gvk schema.GroupVersionKind, namespace, name string) (runtime.Object, error) { + manifest, err := renderedManifests.GetManifest(gvk, namespace, name) + if err != nil { + return nil, err + } + return manifest.decodedObj, nil +} + +func (renderedManifests RenderedManifests) ValidateManifestPredictability() error { + errs := []error{} + decodeErrorsObserved := map[int]bool{} + metadataErrorsObserved := map[int]bool{} + + type compareTuple struct { + i, j int + } + compareTuplesErrorsObserved := map[compareTuple]bool{} + + for i := range renderedManifests { + lhs := renderedManifests[i] + lhsObj, err := lhs.GetDecodedObj() + if err != nil { + if !decodeErrorsObserved[i] { + errs = append(errs, err) + decodeErrorsObserved[i] = true + } + continue + } + lhsMetadata, err := meta.Accessor(lhsObj) + if err != nil { + if !metadataErrorsObserved[i] { + errs = append(errs, fmt.Errorf("unable to read metadata for %q: %w", lhs.OriginalFilename, err)) + metadataErrorsObserved[i] = true + } + continue + } + + for j := range renderedManifests { + if i == j { + continue + } + rhs := renderedManifests[j] + rhsObj, err := rhs.GetDecodedObj() + if err != nil { + if !decodeErrorsObserved[j] { + errs = append(errs, err) + decodeErrorsObserved[j] = true + } + continue + } + rhsMetadata, err := meta.Accessor(rhsObj) + if err != nil { + if !metadataErrorsObserved[j] { + errs = append(errs, fmt.Errorf("unable to read metadata for %q: %w", rhs.OriginalFilename, err)) + metadataErrorsObserved[j] = true + } + continue + } + if lhsObj.GetObjectKind().GroupVersionKind().GroupKind() != rhsObj.GetObjectKind().GroupVersionKind().GroupKind() { + continue + } + if lhsMetadata.GetName() != rhsMetadata.GetName() { + continue + } + if lhsMetadata.GetNamespace() != rhsMetadata.GetNamespace() { + continue + } + + if !equality.Semantic.DeepEqual(lhsObj, rhsObj) { + if !compareTuplesErrorsObserved[compareTuple{i, j}] { + errs = append(errs, + fmt.Errorf("%q and %q both set %v.%v/%v in ns/%v, but have different values", + lhs.OriginalFilename, + rhs.OriginalFilename, + lhsObj.GetObjectKind().GroupVersionKind().Kind, + lhsObj.GetObjectKind().GroupVersionKind().Group, + lhsMetadata.GetName(), + lhsMetadata.GetNamespace(), + )) + compareTuplesErrorsObserved[compareTuple{i, j}] = true + compareTuplesErrorsObserved[compareTuple{j, i}] = true + } + } + } + } + + return utilerrors.NewAggregate(errs) +} + func (c *RenderedManifest) GetDecodedObj() (runtime.Object, error) { if c.decodedObj != nil { return c.decodedObj, nil } obj, err := resourceread.ReadGenericWithUnstructured(c.Content) if err != nil { - return nil, err + return nil, fmt.Errorf("unable to decode %q: %w", c.OriginalFilename, err) } c.decodedObj = obj diff --git a/vendor/github.com/openshift/library-go/pkg/operator/render/options/generic.go b/vendor/github.com/openshift/library-go/pkg/operator/render/options/generic.go index 48d44607c..c0efaea8c 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/render/options/generic.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/render/options/generic.go @@ -5,17 +5,16 @@ import ( "errors" "fmt" "io/ioutil" - "os" "text/template" "github.com/ghodss/yaml" - "github.com/spf13/pflag" - - "k8s.io/apimachinery/pkg/runtime/schema" - configv1 "github.com/openshift/api/config/v1" "github.com/openshift/library-go/pkg/assets" + "github.com/openshift/library-go/pkg/operator/configobserver/featuregates" "github.com/openshift/library-go/pkg/operator/resource/resourcemerge" + "github.com/spf13/pflag" + "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/runtime/schema" ) // GenericOptions contains the generic render command options. @@ -31,7 +30,8 @@ type GenericOptions struct { AssetInputDir string AssetOutputDir string - FeatureSet string + FeatureSet string + PayloadVersion string } type Template struct { @@ -57,6 +57,8 @@ func (o *GenericOptions) AddFlags(fs *pflag.FlagSet, configGVK schema.GroupVersi fs.StringVar(&o.FeatureSet, "feature-set", o.FeatureSet, "Enables features that are not part of the default feature set.") fs.StringSliceVar(&o.RenderedManifestInputFilenames, "rendered-manifest-files", o.RenderedManifestInputFilenames, "files or directories containing yaml or json manifests that will be created via cluster-bootstrapping.") + fs.StringVar(&o.PayloadVersion, "payload-version", o.PayloadVersion, "Version that will eventually be placed into ClusterOperator.status. This normally comes from the CVO set via env var: OPERATOR_IMAGE_VERSION.") + } type gvkOutput struct { @@ -87,10 +89,11 @@ func (o *GenericOptions) Validate() error { return errors.New("missing required flag: --config-output-file") } - for _, filename := range o.RenderedManifestInputFilenames { - _, err := os.Stat(filename) - if err != nil { - return fmt.Errorf("--rendered-manifest-files, value %q could not be read: %v", filename, err) + if renderedManifests, err := o.ReadInputManifests(); err != nil { + return fmt.Errorf("--rendered-manifest-files, could not be read: %v", err) + } else { + if err := renderedManifests.ValidateManifestPredictability(); err != nil { + return fmt.Errorf("--rendered-manifest-files, are not consistent so results would be unpredictable depending on apply order: %v", err) } } @@ -99,9 +102,75 @@ func (o *GenericOptions) Validate() error { default: return fmt.Errorf("invalid feature-set specified: %q", o.FeatureSet) } + return nil } +func (o *GenericOptions) ReadInputManifests() (RenderedManifests, error) { + ret := RenderedManifests{} + for _, filename := range o.RenderedManifestInputFilenames { + manifestContent, err := assets.LoadFilesRecursively(filename) + if err != nil { + return nil, fmt.Errorf("failed loading rendered manifest inputs from %q: %w", filename, err) + } + for manifestFile, content := range manifestContent { + ret = append(ret, RenderedManifest{ + OriginalFilename: manifestFile, + Content: content, + }) + } + } + + return ret, nil +} + +func (o *GenericOptions) FeatureGates() (featuregates.FeatureGateAccess, error) { + if len(o.PayloadVersion) == 0 { + return nil, fmt.Errorf("cannot return FeatureGate without payload version") + } + if len(o.RenderedManifestInputFilenames) == 0 { + return nil, fmt.Errorf("cannot return FeatureGate without rendered manifests") + } + + inputManifest, err := o.ReadInputManifests() + if err != nil { + return nil, fmt.Errorf("error reading input manifests: %w", err) + } + featureGates := inputManifest.ListManifestOfType(configv1.GroupVersion.WithKind("FeatureGate")) + if len(featureGates) == 0 { + return nil, fmt.Errorf("no FeatureGates found in manfest dir: %v", o.RenderedManifestInputFilenames) + } + var prev *RenderedManifest + var featureGate *configv1.FeatureGate + for i := range featureGates { + curr := featureGates[i] + decodedObj, err := curr.GetDecodedObj() + if err != nil { + return nil, fmt.Errorf("decoding failure for %q: %w", curr.OriginalFilename, err) + } + currFeatureGate, ok := decodedObj.(*configv1.FeatureGate) + if !ok { + return nil, fmt.Errorf("wrong obj type for %q: %T: %v", curr.OriginalFilename, decodedObj, curr.Content) + } + if featureGate == nil { + prev = &curr + featureGate = currFeatureGate + continue + } + + if !equality.Semantic.DeepEqual(featureGate, currFeatureGate) { + return nil, fmt.Errorf("FeatureGate manifests disagree: %q and %q, with \n%v\n%v ", prev.OriginalFilename, curr.OriginalFilename, prev.Content, curr.Content) + } + } + + ret, err := featuregates.NewHardcodedFeatureGateAccessFromFeatureGate(featureGate, o.PayloadVersion) + if err != nil { + return nil, fmt.Errorf("error creating feature accessor: %w", err) + } + + return ret, nil +} + // ApplyTo applies the options to the given config struct using the provided text/template data. func (o *GenericOptions) ApplyTo(cfg *FileConfig, defaultConfig, bootstrapOverrides Template, templateData interface{}, specialCases map[string]resourcemerge.MergeFunc) error { var err error @@ -116,19 +185,6 @@ func (o *GenericOptions) ApplyTo(cfg *FileConfig, defaultConfig, bootstrapOverri return fmt.Errorf("failed loading assets from %q: %v", o.AssetInputDir, err) } - for _, filename := range o.RenderedManifestInputFilenames { - manifestContent, err := assets.LoadFilesRecursively(filename) - if err != nil { - return fmt.Errorf("failed loading rendered manifest inputs from %q: %w", filename, err) - } - for manifestFile, content := range manifestContent { - cfg.RenderedManifests = append(cfg.RenderedManifests, RenderedManifest{ - OriginalFilename: manifestFile, - Content: content, - }) - } - } - return nil } diff --git a/vendor/modules.txt b/vendor/modules.txt index a2f4d71b1..02bc0f39b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -257,7 +257,7 @@ github.com/openshift/client-go/config/informers/externalversions/config/v1alpha1 github.com/openshift/client-go/config/informers/externalversions/internalinterfaces github.com/openshift/client-go/config/listers/config/v1 github.com/openshift/client-go/config/listers/config/v1alpha1 -# github.com/openshift/library-go v0.0.0-20230427133628-add9892da47e +# github.com/openshift/library-go v0.0.0-20230502125217-e45be8351afe ## explicit; go 1.19 github.com/openshift/library-go/pkg/assets github.com/openshift/library-go/pkg/authorization/hardcodedauthorizer From ac668ec135ce5b798e25cd2b50a9e2f66bc7b178 Mon Sep 17 00:00:00 2001 From: David Eads Date: Mon, 1 May 2023 15:13:35 -0400 Subject: [PATCH 2/2] use new rendering helpers --- pkg/cmd/render/render.go | 41 +++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/pkg/cmd/render/render.go b/pkg/cmd/render/render.go index 55e1bbae9..9ef748188 100644 --- a/pkg/cmd/render/render.go +++ b/pkg/cmd/render/render.go @@ -29,16 +29,16 @@ type renderOpts struct { cloudProviderConfigOutputFile string // this file will be both input AND output featureGateManifestFile string - payloadVersion string } // NewRenderCommand creates a render command. func NewRenderCommand() *cobra.Command { renderOpts := renderOpts{ - generic: *genericrenderoptions.NewGenericOptions(), - manifest: *genericrenderoptions.NewManifestOptions("config", "openshift/origin-cluster-config-operator:latest"), - payloadVersion: "0.0.1-snapshot", + generic: *genericrenderoptions.NewGenericOptions(), + manifest: *genericrenderoptions.NewManifestOptions("config", "openshift/origin-cluster-config-operator:latest"), } + renderOpts.generic.PayloadVersion = "0.0.1-snapshot" + cmd := &cobra.Command{ Use: "render", Short: "Render kubernetes API server bootstrap manifests, secrets and configMaps", @@ -76,7 +76,6 @@ func (r *renderOpts) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&r.cloudProviderConfigOutputFile, "cloud-provider-config-output-file", r.cloudProviderConfigOutputFile, "Output path for the generated cloud provider config file.") fs.StringVar(&r.featureGateManifestFile, "featuregate-manifest", r.featureGateManifestFile, "Path for the FeatureGate.config.openshift.io that will be modified with completed status for use in other bootstrapping steps.") - fs.StringVar(&r.payloadVersion, "payload-version", r.payloadVersion, "Version that will eventually be placed into ClusterOperator.status. This normally comes from the CVO set via env var: OPERATOR_IMAGE_VERSION.") } @@ -139,7 +138,7 @@ func (r *renderOpts) Run() error { } featureGates := ReadFeatureGateV1OrDie(featureGateBytes) - currentDetails, err := featuregates.FeaturesGateDetailsFromFeatureSets(configv1.FeatureSets, featureGates, r.payloadVersion) + currentDetails, err := featuregates.FeaturesGateDetailsFromFeatureSets(configv1.FeatureSets, featureGates, r.generic.PayloadVersion) if err != nil { return err } @@ -164,22 +163,25 @@ func (r *renderOpts) Run() error { return err } - featureGateFiles := renderConfig.ListManifestOfType(configv1.GroupVersion.WithKind("FeatureGate")) + featureGateFiles, err := featureGateManifests(r.generic) + if err != nil { + return fmt.Errorf("problem with featuregate manifests: %w", err) + } for _, featureGateFile := range featureGateFiles { featureGatesObj, err := featureGateFile.GetDecodedObj() if err != nil { - return err + return fmt.Errorf("error decoding FeatureGate: %w", err) } featureGates := featureGatesObj.(*configv1.FeatureGate) - currentDetails, err := featuregates.FeaturesGateDetailsFromFeatureSets(configv1.FeatureSets, featureGates, r.payloadVersion) + currentDetails, err := featuregates.FeaturesGateDetailsFromFeatureSets(configv1.FeatureSets, featureGates, r.generic.PayloadVersion) if err != nil { - return err + return fmt.Errorf("error determining FeatureGates: %w", err) } featureGates.Status.FeatureGates = []configv1.FeatureGateDetails{*currentDetails} featureGateOutBytes := WriteFeatureGateV1OrDie(featureGates) if err := os.WriteFile(featureGateFile.OriginalFilename, []byte(featureGateOutBytes), 0644); err != nil { - return err + return fmt.Errorf("error writing FeatureGate manifest: %w", err) } } @@ -199,3 +201,20 @@ func (r *renderOpts) Run() error { return nil } + +func featureGateManifests(o genericrenderoptions.GenericOptions) (genericrenderoptions.RenderedManifests, error) { + if len(o.RenderedManifestInputFilenames) == 0 { + return nil, fmt.Errorf("cannot return FeatureGate without rendered manifests") + } + + inputManifest, err := o.ReadInputManifests() + if err != nil { + return nil, fmt.Errorf("error reading input manifests: %w", err) + } + featureGates := inputManifest.ListManifestOfType(configv1.GroupVersion.WithKind("FeatureGate")) + if len(featureGates) == 0 { + return nil, fmt.Errorf("no FeatureGates found in manfest dir: %v", o.RenderedManifestInputFilenames) + } + + return featureGates, nil +}