Skip to content

CNTRLPLANE-2847: render: Resolve featureSet into individual feature gates during bootstrap#1647

Open
hasbro17 wants to merge 1 commit into
openshift:mainfrom
hasbro17:fix/render-featureset-resolution
Open

CNTRLPLANE-2847: render: Resolve featureSet into individual feature gates during bootstrap#1647
hasbro17 wants to merge 1 commit into
openshift:mainfrom
hasbro17:fix/render-featureset-resolution

Conversation

@hasbro17

@hasbro17 hasbro17 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fix getFeatureGatesStatus to resolve featureSet (e.g., TechPreviewNoUpgrade) into individual feature gates during bootstrap rendering, so that ConfigurablePKI is correctly detected and bootstrap
    etcd-signer certs use the configured key algorithm
  • Add tests for featureSet resolution, featureGates override on top of featureSet, and an end-to-end test that mirrors the real CI install-config structure

Background

PR #1593 added ConfigurablePKI support to the etcd-operator, threading a PKIProfileProvider through both the bootstrap render path and the runtime controller. The installer counterpart
(openshift/installer#10595) creates a PKI CR at install time with the desired key configuration (e.g., RSA-4096).

CI job e2e-aws-ovn-pki-rsa-techpreview on the installer PR showed the etcd-signer cert was still RSA-2048 instead of the configured RSA-4096. All 7 other signers (managed by kube-apiserver-operator,
machine-config-operator, etc.) correctly used RSA-4096, confirming the PKI CR was created correctly and the feature gate was active.

Root cause

The install-config in CI has:

featureSet: TechPreviewNoUpgrade
pki:
  signerCertificates:
    key:
      algorithm: RSA
      rsa:
        keySize: 4096

There are no explicit featureGates entries — the gates are implied by featureSet: TechPreviewNoUpgrade.

getFeatureGatesStatus() in pkg/cmd/render/render.go only parsed explicit featureGates: [Key=Value] strings. It did not resolve featureSet into individual gates. So the enabled set was empty, the
ConfigurablePKI guard was never entered, pkiProfileProvider stayed nil, and the bootstrap certs were created with the legacy fallback (MakeSelfSignedCAConfigForDuration → RSA-2048).

At runtime, the operator correctly detected ConfigurablePKI from the cluster's FeatureGate CR status, but needNewSigningCertKeyPair only checks time-based conditions (expiry, refresh) — it doesn't detect
key algorithm mismatches. So the already-valid RSA-2048 cert was never regenerated.

Fix

Use features.FeatureSets() from openshift/api to resolve the featureSet field into its constituent enabled/disabled gates, then layer explicit featureGates overrides on top (for CustomNoUpgrade
support). This ensures ConfigurablePKI is detected during bootstrap rendering when installed with featureSet: TechPreviewNoUpgrade.

Test plan

  • New Test_getFeatureGates cases for featureSet: TechPreviewNoUpgrade and featureSet + featureGates override
  • New TestTemplateDataWithCustomPKIFeatureSet end-to-end test using featureSet: TechPreviewNoUpgrade with PKI config (mirrors real CI install-config)
  • Existing TestTemplateDataWithCustomPKI (explicit featureGates) still passes
  • make verify passes
  • Re-run e2e-aws-ovn-pki-rsa-techpreview on installer PR with this change in the payload

Summary by CodeRabbit

  • New Features

    • Feature-gate detection now respects the cluster’s feature set, improving how enabled and disabled capabilities are determined.
    • Rendered output now better reflects custom PKI settings when a feature set is configured.
  • Bug Fixes

    • Fixed an issue where explicit feature-gate settings could be skipped when a feature set was present.
    • Preserved previously determined feature gates instead of dropping them when feature-gate overrides are absent.

…trap

The render path's getFeatureGatesStatus only parsed explicit
featureGates key=value entries from the install-config. It did not
resolve featureSet (e.g. TechPreviewNoUpgrade) into the constituent
gate list. When a cluster is installed with featureSet:
TechPreviewNoUpgrade and no explicit featureGates entries, the
ConfigurablePKI gate was never detected, causing bootstrap etcd-signer
certs to be generated with legacy RSA-2048 instead of the configured
algorithm.

Use features.FeatureSets() from openshift/api to resolve the featureSet
into enabled/disabled gates, then layer explicit featureGates overrides
on top for CustomNoUpgrade support.

Assisted-by: Claude Code (Opus 4.6)
@hasbro17 hasbro17 requested review from dusk125 and rh-roman July 9, 2026 20:10
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 9, 2026
@openshift-ci-robot

openshift-ci-robot commented Jul 9, 2026

Copy link
Copy Markdown

@hasbro17: This pull request references CNTRLPLANE-2847 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Summary

  • Fix getFeatureGatesStatus to resolve featureSet (e.g., TechPreviewNoUpgrade) into individual feature gates during bootstrap rendering, so that ConfigurablePKI is correctly detected and bootstrap
    etcd-signer certs use the configured key algorithm
  • Add tests for featureSet resolution, featureGates override on top of featureSet, and an end-to-end test that mirrors the real CI install-config structure

Background

PR #1593 added ConfigurablePKI support to the etcd-operator, threading a PKIProfileProvider through both the bootstrap render path and the runtime controller. The installer counterpart
(openshift/installer#10595) creates a PKI CR at install time with the desired key configuration (e.g., RSA-4096).

CI job e2e-aws-ovn-pki-rsa-techpreview on the installer PR showed the etcd-signer cert was still RSA-2048 instead of the configured RSA-4096. All 7 other signers (managed by kube-apiserver-operator,
machine-config-operator, etc.) correctly used RSA-4096, confirming the PKI CR was created correctly and the feature gate was active.

Root cause

The install-config in CI has:

featureSet: TechPreviewNoUpgrade
pki:
  signerCertificates:
    key:
      algorithm: RSA
      rsa:
        keySize: 4096

There are no explicit featureGates entries — the gates are implied by featureSet: TechPreviewNoUpgrade.

getFeatureGatesStatus() in pkg/cmd/render/render.go only parsed explicit featureGates: [Key=Value] strings. It did not resolve featureSet into individual gates. So the enabled set was empty, the
ConfigurablePKI guard was never entered, pkiProfileProvider stayed nil, and the bootstrap certs were created with the legacy fallback (MakeSelfSignedCAConfigForDuration → RSA-2048).

At runtime, the operator correctly detected ConfigurablePKI from the cluster's FeatureGate CR status, but needNewSigningCertKeyPair only checks time-based conditions (expiry, refresh) — it doesn't detect
key algorithm mismatches. So the already-valid RSA-2048 cert was never regenerated.

Fix

Use features.FeatureSets() from openshift/api to resolve the featureSet field into its constituent enabled/disabled gates, then layer explicit featureGates overrides on top (for CustomNoUpgrade
support). This ensures ConfigurablePKI is detected during bootstrap rendering when installed with featureSet: TechPreviewNoUpgrade.

Test plan

  • New Test_getFeatureGates cases for featureSet: TechPreviewNoUpgrade and featureSet + featureGates override
  • New TestTemplateDataWithCustomPKIFeatureSet end-to-end test using featureSet: TechPreviewNoUpgrade with PKI config (mirrors real CI install-config)
  • Existing TestTemplateDataWithCustomPKI (explicit featureGates) still passes
  • make verify passes
  • Re-run e2e-aws-ovn-pki-rsa-techpreview on installer PR with this change in the payload

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Walkthrough

The change extends feature-gate resolution in render.go to consider installConfig's featureSet field, resolving it through features.FeatureSets and merging results into enabled/disabled gate sets. featureGates parsing no longer early-returns when absent. Tests and fixtures cover TechPreviewNoUpgrade scenarios.

Changes

FeatureSet feature gate support

Layer / File(s) Summary
FeatureSet resolution and featureGates merge logic
pkg/cmd/render/render.go
getFeatureGatesStatus reads installConfig's featureSet, resolves it via features.FeatureSets, and merges enabled/disabled gates; featureGates parsing now applies conditionally instead of returning early when missing.
Tests and fixtures for featureSet handling
pkg/cmd/render/render_test.go
Adds a featureSet-based PKI fixture and test verifying P521 signer cert generation, new Test_getFeatureGates subtests for featureSet and featureSet+featureGates override cases, and helper functions computing expected TechPreviewNoUpgrade gate sets.

Estimated code review effort: 2 (Simple) | ~15 minutes

🚥 Pre-merge checks | ✅ 15
✅ Passed checks (15 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: resolving featureSet into individual feature gates during bootstrap rendering.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed Static test titles only; new names are literal and deterministic, with no dynamic suffixes or runtime-generated data.
Test Structure And Quality ✅ Passed The added tests are plain unit tests, not Ginkgo; they use t.TempDir, no cluster ops or waits, and follow existing repo test patterns.
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the changes are plain Go unit tests in render_test.go, so MicroShift-specific API checks don't apply.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No Ginkgo e2e tests added in this PR. Changes are limited to unit tests in render_test.go using standard Go testing package.
Topology-Aware Scheduling Compatibility ✅ Passed Only feature-gate parsing and PKI tests changed; no nodeSelector, affinity, topology spread, or replica scheduling logic was added.
Ote Binary Stdout Contract ✅ Passed Changed files add only helper logic and tests; no main/init/TestMain/RunSpecs setup or stdout writes were added.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed Added tests are plain Go unit tests; no Ginkgo e2e, public internet access, or IPv6-host URL assumptions were introduced.
No-Weak-Crypto ✅ Passed No weak cryptography algorithms (MD5, SHA1, DES, RC4, 3DES, Blowfish, ECB) or custom crypto implementations were introduced. The PR uses standard Go crypto libraries appropriately for certificate c...
Container-Privileges ✅ Passed The PR only changes feature-gate/PKI logic and tests; no modified file adds privileged, hostPID/Network/IPC, SYS_ADMIN, root, or allowPrivilegeEscalation settings.
No-Sensitive-Data-In-Logs ✅ Passed No new logging was added in the touched render paths; the patch only changes feature-gate parsing/tests and adds no sensitive-data emission.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


Comment @coderabbitai help to get the list of available commands.

@hasbro17

hasbro17 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

/test e2e-aws-ovn-pki-default-techpreview
/test e2e-aws-ovn-pki-rsa-techpreview

@openshift-ci openshift-ci Bot requested review from atiratree and everettraven July 9, 2026 20:12
@openshift-ci

openshift-ci Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign everettraven for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@hasbro17

hasbro17 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

/jira refresh

@openshift-ci-robot

openshift-ci-robot commented Jul 9, 2026

Copy link
Copy Markdown

@hasbro17: This pull request references CNTRLPLANE-2847 which is a valid jira issue.

Details

In response to this:

/jira refresh

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
pkg/cmd/render/render_test.go (1)

668-714: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate validation closure.

validateECDSAP521Signer here is a verbatim copy of the one in TestTemplateDataWithCustomPKI (lines 622-657). Extract it into a single shared helper function to avoid drift between the two tests.

♻️ Proposed refactor: extract shared validator
+func validateEtcdSignerECDSAP521(t *testing.T, td *TemplateData) {
+	if len(td.certificates) == 0 {
+		t.Fatal("no certificates generated")
+	}
+
+	var signerCert []byte
+	for _, cert := range td.certificates {
+		if cert.Name == "etcd-signer" {
+			signerCert = cert.Data["tls.crt"]
+			break
+		}
+	}
+
+	if signerCert == nil {
+		t.Fatal("etcd-signer certificate not found in generated certificates")
+	}
+
+	block, _ := pem.Decode(signerCert)
+	if block == nil {
+		t.Fatal("failed to decode PEM block from etcd-signer certificate")
+	}
+
+	x509Cert, err := x509.ParseCertificate(block.Bytes)
+	if err != nil {
+		t.Fatalf("failed to parse x509 certificate: %v", err)
+	}
+
+	ecdsaKey, ok := x509Cert.PublicKey.(*ecdsa.PublicKey)
+	if !ok {
+		t.Fatalf("expected ECDSA public key, got %T", x509Cert.PublicKey)
+	}
+
+	if ecdsaKey.Curve != elliptic.P521() {
+		t.Errorf("expected P521 curve, got %v", ecdsaKey.Curve.Params().Name)
+	}
+}
+
 func TestTemplateDataWithCustomPKIFeatureSet(t *testing.T) {
-	validateECDSAP521Signer := func(t *testing.T, td *TemplateData) {
-		...
-	}
-
 	config := &testConfig{
 		clusterNetworkConfig: networkConfigIpv4,
 		infraConfig:          infraConfig,
 		clusterConfigMap:     clusterConfigMapWithCustomPKIAndFeatureSet,
 	}
-	testTemplateData(t, config, validateECDSAP521Signer)
+	testTemplateData(t, config, validateEtcdSignerECDSAP521)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/cmd/render/render_test.go` around lines 668 - 714,
`validateECDSAP521Signer` is duplicated in
`TestTemplateDataWithCustomPKIFeatureSet` and `TestTemplateDataWithCustomPKI`,
so extract the validator into a shared test helper and reuse it from both tests.
Move the certificate/key assertions into a single helper near `testTemplateData`
or alongside the test functions, then call that helper from each test to keep
the validation logic in one place and prevent drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/cmd/render/render.go`:
- Around line 821-833: The featureGates parsing in the render logic is indexing
the result of strings.Split without validation, which can panic on malformed
entries. Update the feature gate handling in render.go to parse each entry
safely in the same block that iterates featureGates, using a bounded split or
equivalent validation before reading key/value. If an entry does not contain a
valid key=value pair, report it as a configuration error instead of crashing,
and keep the enabled/disabled set updates in the existing render flow.
- Around line 806-807: The featureSet handling in render.go uses an unchecked
type assertion on installConfig["featureSet"], which can panic on malformed
external config. Update the featureSetRaw handling in the render path to use a
comma-ok string assertion (and skip or error out gracefully when the value is
not a string) so the bootstrap rendering flow does not crash. Use the existing
installConfig["featureSet"] lookup and configv1.FeatureSet assignment location
to apply the fix.

---

Nitpick comments:
In `@pkg/cmd/render/render_test.go`:
- Around line 668-714: `validateECDSAP521Signer` is duplicated in
`TestTemplateDataWithCustomPKIFeatureSet` and `TestTemplateDataWithCustomPKI`,
so extract the validator into a shared test helper and reuse it from both tests.
Move the certificate/key assertions into a single helper near `testTemplateData`
or alongside the test functions, then call that helper from each test to keep
the validation logic in one place and prevent drift.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 10ace7cb-2337-415c-b85f-fd41b932b21c

📥 Commits

Reviewing files that changed from the base of the PR and between 831d5e6 and 8de0005.

📒 Files selected for processing (2)
  • pkg/cmd/render/render.go
  • pkg/cmd/render/render_test.go

Comment thread pkg/cmd/render/render.go
Comment on lines +806 to +807
if featureSetRaw, found := installConfig["featureSet"]; found {
featureSet := configv1.FeatureSet(featureSetRaw.(string))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Unchecked type assertion on featureSetRaw.

featureSetRaw.(string) will panic if installConfig["featureSet"] is present but not a string (e.g., malformed YAML producing an int/bool/nil). This runs on the bootstrap render path, so a malformed install-config would crash rendering instead of degrading gracefully.

As per path instructions, Go code should "Never ignore error returns"; the same principle applies to unchecked type assertions on values sourced from external config here.

🛡️ Proposed fix using comma-ok assertion
 	if featureSetRaw, found := installConfig["featureSet"]; found {
-		featureSet := configv1.FeatureSet(featureSetRaw.(string))
-		if resolved := features.FeatureSets(0, features.SelfManaged, featureSet); resolved != nil {
+		featureSetStr, ok := featureSetRaw.(string)
+		if !ok {
+			return enabled, disabled
+		}
+		featureSet := configv1.FeatureSet(featureSetStr)
+		if resolved := features.FeatureSets(0, features.SelfManaged, featureSet); resolved != nil {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if featureSetRaw, found := installConfig["featureSet"]; found {
featureSet := configv1.FeatureSet(featureSetRaw.(string))
if featureSetRaw, found := installConfig["featureSet"]; found {
featureSetStr, ok := featureSetRaw.(string)
if !ok {
return enabled, disabled
}
featureSet := configv1.FeatureSet(featureSetStr)
if resolved := features.FeatureSets(0, features.SelfManaged, featureSet); resolved != nil {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/cmd/render/render.go` around lines 806 - 807, The featureSet handling in
render.go uses an unchecked type assertion on installConfig["featureSet"], which
can panic on malformed external config. Update the featureSetRaw handling in the
render path to use a comma-ok string assertion (and skip or error out gracefully
when the value is not a string) so the bootstrap rendering flow does not crash.
Use the existing installConfig["featureSet"] lookup and configv1.FeatureSet
assignment location to apply the fix.

Source: Path instructions

Comment thread pkg/cmd/render/render.go
Comment on lines +821 to 833
if featureGates, found := installConfig["featureGates"]; found {
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))
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Unbounded index access on strings.Split result.

strings.Split(featureGate.(string), "=")[1] panics with an index-out-of-range if the entry has no = (e.g., a bare "FooBar" in the list). Since this is bootstrap-critical rendering, a single malformed entry crashes the whole render rather than being reported as a config error.

🛡️ Proposed fix using SplitN with a length check
 		for _, featureGate := range featureGates.([]any) {
-			key := strings.Split(featureGate.(string), "=")[0]
-			value := strings.Split(featureGate.(string), "=")[1]
+			parts := strings.SplitN(featureGate.(string), "=", 2)
+			if len(parts) != 2 {
+				continue
+			}
+			key, value := parts[0], parts[1]
 			if value == "true" {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if featureGates, found := installConfig["featureGates"]; found {
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))
}
}
}
if featureGates, found := installConfig["featureGates"]; found {
for _, featureGate := range featureGates.([]any) {
parts := strings.SplitN(featureGate.(string), "=", 2)
if len(parts) != 2 {
continue
}
key, value := parts[0], parts[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))
}
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/cmd/render/render.go` around lines 821 - 833, The featureGates parsing in
the render logic is indexing the result of strings.Split without validation,
which can panic on malformed entries. Update the feature gate handling in
render.go to parse each entry safely in the same block that iterates
featureGates, using a bounded split or equivalent validation before reading
key/value. If an entry does not contain a valid key=value pair, report it as a
configuration error instead of crashing, and keep the enabled/disabled set
updates in the existing render flow.

@hasbro17

hasbro17 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Waiting for e2e-aws-ovn-pki-rsa-techpreview to validate that the operator picks up the ConfigurablePKI featuregate from TechPreview.

Comment thread pkg/cmd/render/render.go

if featureGates, found := installConfig["featureGates"]; found {
for _, featureGate := range featureGates.([]any) {
key := strings.Split(featureGate.(string), "=")[0]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could do key, value, found := strings.Cut(featureGate.(string), "=") and that would address CodeRabbit's complaint

@hasbro17

hasbro17 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Need a multi PR test to include the installer PKI support.

@hasbro17

hasbro17 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

/testwith e2e-aws-ovn-pki-rsa-techpreview openshift/installer#10595

@openshift-ci

openshift-ci Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

@hasbro17, testwith: Error processing request. ERROR:

could not determine job runs: requested job is invalid. needs to be formatted like: <org>/<repo>/<branch>/<variant?>/<job>. instead it was: e2e-aws-ovn-pki-rsa-techpreview

@hasbro17

hasbro17 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

/testwith openshift/cluster-etcd-operator/main/e2e-aws-ovn-pki-rsa-techpreview openshift/installer#10595

@openshift-ci

openshift-ci Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

@hasbro17: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-aws-ovn-pki-default-techpreview 8de0005 link false /test e2e-aws-ovn-pki-default-techpreview
ci/prow/e2e-metal-ipi-ovn-ipv6 8de0005 link true /test e2e-metal-ipi-ovn-ipv6
ci/prow/e2e-aws-ovn-pki-rsa-techpreview 8de0005 link false /test e2e-aws-ovn-pki-rsa-techpreview

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@sanchezl sanchezl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CEO render should not parse the feature gates from the raw install-config. Looking at other operator render (CKASO, CKCMO, MCO) , they read the pre-resolved FeatureGate CR from /assets/manifests/ via --rendered-manifest-files and --payload-version. The api-render step in bootkube.sh already runs before etcd-render and produces the fully-resolved CR with featureSet expanded into individual gates, the CEO just never consumed it.

That architectural gap is why this bug exists in the first place: the other operators don't have this class of bug because they don't resolve feature gates themselves.

I've opened an alternative set of PRs that aligns CEO with the standard pattern, eliminating the entire class of feature-gate-resolution bugs rather than patching getFeatureGatesStatus for each new case:

  1. #1648 — Adds --rendered-manifest-files and --payload-version support to the render command. When provided, reads the FeatureGate CR from pre-rendered manifests (the same pattern CKASO/CKCMO use). Includes a fallback that resolves featureSet from the install-config (covering this bug) so it can land independently without waiting for the installer change.

  2. openshift/installer#10679 — Passes the two new flags to the etcd-render invocation in bootkube.sh, matching what's already done for kube-apiserver-render, kube-controller-manager-render, and config-render.

  3. #1649 — Cleanup: removes the install-config fallback and makes both flags required, once the installer PR has merged.

A few additional notes on this PR if it moves forward instead:

  • features.FeatureSets(0, ...) passes version 0. Other callers (the installer, MCO tests) use the real major version (4). Today this is a no-op because no gate uses inVersion(), but if any gate adds a version constraint in the future, version 0 would silently exclude it.
  • The unchecked type assertion on featureSetRaw.(string) (line 807) can panic on malformed install-config YAML — should use the comma-ok pattern.
  • validateECDSAP521Signer is duplicated between TestTemplateDataWithCustomPKI and TestTemplateDataWithCustomPKIFeatureSet — worth extracting to a shared helper.

@sanchezl sanchezl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants