-
Notifications
You must be signed in to change notification settings - Fork 172
CNTRLPLANE-2847: render: Read FeatureGate CR from rendered manifests #1648
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -24,6 +24,7 @@ import ( | |||||||||||||||||||||||||||||||||||||||||||||||||||
| configv1alpha1 "github.com/openshift/api/config/v1alpha1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| features "github.com/openshift/api/features" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/openshift/library-go/pkg/assets" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/openshift/library-go/pkg/operator/configobserver/featuregates" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/openshift/library-go/pkg/pki" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/spf13/cobra" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/spf13/pflag" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -47,6 +48,9 @@ type renderOpts struct { | |||||||||||||||||||||||||||||||||||||||||||||||||||
| clusterConfigMapFile string | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| infraConfigFile string | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| renderedManifestFiles []string | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| payloadVersion string | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| delayedHABootstrapScalingStrategyMarker string | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| bootstrapIPLocator BootstrapIPLocator | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -86,6 +90,8 @@ func (r *renderOpts) AddFlags(fs *pflag.FlagSet) { | |||||||||||||||||||||||||||||||||||||||||||||||||||
| fs.StringVar(&r.networkConfigFile, "network-config-file", "", "File containing the network.config.openshift.io manifest.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| fs.StringVar(&r.clusterConfigMapFile, "cluster-configmap-file", "", "File containing the cluster-config-v1 configmap.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| fs.StringVar(&r.infraConfigFile, "infra-config-file", "", "File containing infrastructure.config.openshift.io manifest.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| fs.StringArrayVar(&r.renderedManifestFiles, "rendered-manifest-files", nil, "Files or directories containing pre-rendered manifests, used to determine FeatureGate status.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| fs.StringVar(&r.payloadVersion, "payload-version", "", "Version that will eventually be placed into ClusterOperator.status. This normally comes from the CVO set via env var: OPERATOR_IMAGE_VERSION.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO(marun) Discover scaling strategy with less hack | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| fs.StringVar(&r.delayedHABootstrapScalingStrategyMarker, "delayed-ha-bootstrap-scaling-marker-file", "/assets/assisted-install-bootstrap", "Marker file that, if present, enables the delayed HA bootstrap scaling strategy") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -279,7 +285,10 @@ func newTemplateData(opts *renderOpts) (*TemplateData, error) { | |||||||||||||||||||||||||||||||||||||||||||||||||||
| base64.StdEncoding.WithPadding(base64.NoPadding).EncodeToString([]byte(templateData.BootstrapIP)), templateData.BootstrapIP) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabledFeatureGates, disabledFeatureGates := getFeatureGatesStatus(installConfig) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabledFeatureGates, disabledFeatureGates, err := opts.getFeatureGates(installConfig) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf("failed to get feature gates: %w", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| var pkiProfileProvider pki.PKIProfileProvider | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if enabledFeatureGates.Has(features.FeatureGateConfigurablePKI) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -794,29 +803,136 @@ func getBootstrapScalingStrategy(installConfig map[string]any, delayedHAMarkerFi | |||||||||||||||||||||||||||||||||||||||||||||||||||
| return strategy, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // getFeatureGatesStatus returns the enabled and disabled feature gates. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| func getFeatureGatesStatus(installConfig map[string]any) (sets.Set[configv1.FeatureGateName], sets.Set[configv1.FeatureGateName]) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled, disabled := sets.Set[configv1.FeatureGateName]{}, sets.Set[configv1.FeatureGateName]{} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // getFeatureGates returns the enabled and disabled feature gate sets. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Primary path: when --rendered-manifest-files and --payload-version are | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // provided, reads the pre-resolved FeatureGate CR from rendered manifests. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // This is the standard operator render pattern used by CKASO and CKCMO. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Fallback path: when rendered manifests are not available, resolves | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // feature gates from the install-config's featureSet and featureGates | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // fields directly. This fallback exists for transition until the | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // installer passes the new flags to the etcd-render invocation, and | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // should be removed once openshift/installer carries the change. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| func (r *renderOpts) getFeatureGates(installConfig map[string]any) (sets.Set[configv1.FeatureGateName], sets.Set[configv1.FeatureGateName], error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if len(r.renderedManifestFiles) > 0 && len(r.payloadVersion) > 0 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return r.getFeatureGatesFromManifests() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| klog.Warningf("--rendered-manifest-files or --payload-version not provided, falling back to install-config feature gate parsing") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled, disabled := getFeatureGatesFromInstallConfig(installConfig) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return enabled, disabled, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // On bootstrap we might not be able to fetch a list of all feature gates | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Hardcode a list of necessary for bootstrap here | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| necessaryFeatureGates := []configv1.FeatureGateName{"ShortCertRotation"} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled.Insert(necessaryFeatureGates...) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // getFeatureGatesFromManifests reads the FeatureGate CR from pre-rendered | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // manifests and returns enabled/disabled sets. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| func (r *renderOpts) getFeatureGatesFromManifests() (sets.Set[configv1.FeatureGateName], sets.Set[configv1.FeatureGateName], error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| fg, err := r.readFeatureGate() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, nil, err | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| accessor, err := featuregates.NewHardcodedFeatureGateAccessFromFeatureGate(fg, r.payloadVersion) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, nil, err | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| featureGate, err := accessor.CurrentFeatureGates() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, nil, err | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled := sets.New[configv1.FeatureGateName]() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled := sets.New[configv1.FeatureGateName]() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, name := range featureGate.KnownFeatures() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if featureGate.Enabled(name) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled.Insert(name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled.Insert(name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return enabled, disabled, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| featureGates, found := installConfig["featureGates"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if !found { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return enabled, disabled | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, featureGate := range featureGates.([]any) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| key := strings.Split(featureGate.(string), "=")[0] | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| value := strings.Split(featureGate.(string), "=")[1] | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if value == "true" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled = enabled.Insert(configv1.FeatureGateName(key)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled = disabled.Delete(configv1.FeatureGateName(key)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if value == "false" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled = enabled.Delete(configv1.FeatureGateName(key)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled = disabled.Insert(configv1.FeatureGateName(key)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // readFeatureGate scans rendered manifest files/directories for a FeatureGate CR. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| func (r *renderOpts) readFeatureGate() (*configv1.FeatureGate, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, manifestPath := range r.renderedManifestFiles { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| info, err := os.Stat(manifestPath) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf("failed to stat %s: %w", manifestPath, err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| var files []string | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if info.IsDir() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| entries, err := os.ReadDir(manifestPath) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf("failed to read directory %s: %w", manifestPath, err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, entry := range entries { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if entry.IsDir() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| files = append(files, filepath.Join(manifestPath, entry.Name())) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| files = []string{manifestPath} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, file := range files { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| data, err := os.ReadFile(file) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| jsonBytes, err := yaml.YAMLToJSON(data) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| fg := &configv1.FeatureGate{} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err := json.Unmarshal(jsonBytes, fg); err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+877
to
+888
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win Preserve manifest read and decoding errors. These Proposed fix data, err := os.ReadFile(file)
if err != nil {
- continue
+ return nil, fmt.Errorf("failed to read manifest %s: %w", file, err)
}
jsonBytes, err := yaml.YAMLToJSON(data)
if err != nil {
- continue
+ return nil, fmt.Errorf("failed to convert manifest %s to JSON: %w", file, err)
}
fg := &configv1.FeatureGate{}
if err := json.Unmarshal(jsonBytes, fg); err != nil {
- continue
+ return nil, fmt.Errorf("failed to decode manifest %s: %w", file, err)
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI AgentsSource: Path instructions
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
✏️ Learnings added
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if fg.APIVersion == "config.openshift.io/v1" && fg.Kind == "FeatureGate" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return fg, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf("no FeatureGate manifest found in %v", r.renderedManifestFiles) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // getFeatureGatesFromInstallConfig resolves feature gates from the | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // install-config featureSet and featureGates fields. This is the fallback | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // for when rendered manifests are not available. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO: Remove this fallback once the installer passes --rendered-manifest-files | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // and --payload-version to the etcd-render invocation. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| func getFeatureGatesFromInstallConfig(installConfig map[string]any) (sets.Set[configv1.FeatureGateName], sets.Set[configv1.FeatureGateName]) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled := sets.New[configv1.FeatureGateName]() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled := sets.New[configv1.FeatureGateName]() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| featureSet := configv1.Default | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if featureSetRaw, found := installConfig["featureSet"]; found { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this fallback path is still causing issues on non-techpreview installs. I'm seeing repeated panics in the bootkube logs for etcd-render. Jul 10 03:42:15 ip-10-0-97-204 bootkube.sh[5696]: W0710 03:42:15.634081 1 render.go:821] --rendered-manifest-files or --payload-version not provided, falling back to install-config feature gate parsing
Jul 10 03:42:15 ip-10-0-97-204 bootkube.sh[5696]: panic: feature "ShortCertRotation" is not registered in FeatureGates []
...
Jul 10 03:42:15 ip-10-0-97-204 systemd[1]: bootkube.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
Jul 10 03:42:15 ip-10-0-97-204 systemd[1]: bootkube.service: Failed with result 'exit-code'.
Jul 10 03:42:15 ip-10-0-97-204 systemd[1]: bootkube.service: Consumed 20.897s CPU time, 1.3G memory peak.
Jul 10 03:42:20 ip-10-0-97-204 systemd[1]: bootkube.service: Scheduled restart job, restart counter is at 1.Will share the review bot analysis below for more details.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 When neither panic(fmt.Errorf("feature %q is not registered in FeatureGates %v", key, f.KnownFeatures()))The old CI evidence: The bootkube.log from this job's artifacts Jul 10 03:42:15 bootkube.sh[5696]: etcdcertsignercontroller.go:159 +0x528
Jul 10 03:42:15 bootkube.sh[5696]: certs.go:58 +0xb49
Jul 10 03:42:15 bootkube.sh[5696]: render.go:301 +0xbdb
...
Jul 10 03:42:15 systemd[1]: bootkube.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
Jul 10 03:42:15 systemd[1]: bootkube.service: Failed with result 'exit-code'.
Jul 10 03:42:20 systemd[1]: bootkube.service: Scheduled restart job, restart counter is at 1.Then the same panic repeats at The install-config for this job (install-config.yaml) confirms no Suggested fix: Always resolve the featureSet, defaulting to featureSet := configv1.Default
if featureSetRaw, found := installConfig["featureSet"]; found {
if featureSetStr, ok := featureSetRaw.(string); ok {
featureSet = configv1.FeatureSet(featureSetStr)
}
}
if resolved := features.FeatureSets(0, features.SelfManaged, featureSet); resolved != nil {
// populate enabled/disabled from resolved
}This populates all known gates (including ShortCertRotation in disabled) for every featureSet, making the old hardcode genuinely unnecessary.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this goes away when openshift/installer#10679 lands but this has to come first I think. |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| if featureSetStr, ok := featureSetRaw.(string); ok { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| featureSet = configv1.FeatureSet(featureSetStr) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if resolved := features.FeatureSets(0, features.SelfManaged, featureSet); resolved != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, fg := range resolved.Enabled { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled.Insert(fg.FeatureGateAttributes.Name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, fg := range resolved.Disabled { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled.Insert(fg.FeatureGateAttributes.Name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| if featureGatesRaw, found := installConfig["featureGates"]; found { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, entry := range featureGatesRaw.([]any) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| key, value, found := strings.Cut(entry.(string), "=") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if !found { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| name := configv1.FeatureGateName(key) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if value == "true" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled.Insert(name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled.Delete(name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if value == "false" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled.Delete(name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled.Insert(name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These flags
rendered-manifest-filesandpayload-versionare already defined as generic render flags in openshift/library-go@pkg/operator/render/options/generic.go#L57-L59, right? I'm referencing kube-controller-render, which also accepts the 2 flags.We may already have existing feature-gate funcs to help us here too, for example 👀
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, CKCMO and CKASO embed
genericrenderoptions.GenericOptionswhich providesrendered-manifest-files,payload-version, andFeatureGates()out of the box.The etcd render command does not use library-go's generic render options infrastructure at all, it has its own
renderOptsstruct with manually-defined flags. Refactoring it to embedGenericOptionswould be a much larger change (the entire render pipeline would need to be restructured to match the pattern CKCMO uses withManifestOptions+GenericOptions).This PR takes the narrower approach doing the minimum needed to unblock the configurable PKI work. A full refactor to align with the generic render framework is worth doing but can be a followup effort.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh whoops, my bad, I didn't realize that at all! Thanks for the details 🙏