Skip to content

Commit a3a6a16

Browse files
committed
cmd/render: Add --feature-gate-manifest-path option
455abd6 (pkg/payload/render: Include release image (Cluster)ImagePolicy, 2024-07-31, #1076) taught the render command to extract (Cluster)ImagePolicy manifests so the bootstrap machine-config controller could consume them. That got the cluster-update-keys ClusterImagePolicy manifest working on TechPreviewNoUpgrade installs, because that feature-set needs the manifest to get into the boostrap MCC to avoid "missing MachineConfig rendered-..." hash mismatches. But the ClusterImagePolicy manifest and CustomResourceDefinition are currently feature-gated, so the boostrap ClusterImagePolicy render broke default feature-set installs, like [1]: $ curl -s https://gcsweb-ci.apps.ci.l2s4.p1.openshiftapps.com/gcs/test-platform-results/pr-logs/pull/openshift_cluster-update-keys/60/pull-ci-openshift-cluster-update-keys-master-e2e-aws/1821360664451485696/artifacts/e2e-aws/ipi-install-install/artifacts/log-bundle-20240808024008.tar | tar -xOz log-bundle-20240808024008/bootstrap/journals/bootkube.log | grep 'no matches for kind' | tail -n2 Aug 08 02:40:14 ip-10-0-169-200 cluster-bootstrap[4584]: "0000_90_openshift-cluster-image-policy.yaml": unable to get REST mapping for "0000_90_openshift-cluster-image-policy.yaml": no matches for kind "ClusterImagePolicy" in version "config.openshift.io/v1alpha1" Aug 08 02:40:14 ip-10-0-169-200 bootkube.sh[4548]: "0000_90_openshift-cluster-image-policy.yaml": unable to get REST mapping for "0000_90_openshift-cluster-image-policy.yaml": no matches for kind "ClusterImagePolicy" in version "config.openshift.io/v1alpha1" With this commit's new --feature-gate-manifest-path, the installer will be able to update the CVO render call [2] to point at its FeatureGate manifest [3]. I'm cutting some corners here (more of this render processing could use Manifest.Include filtering), but I'm in a hurry to get things set up in the hopes of beating the 4.17 branch cut. I think this might be a sufficient change, and we can polish the development branch up more post-branch. [1]: https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/openshift_cluster-update-keys/60/pull-ci-openshift-cluster-update-keys-master-e2e-aws/1821360664451485696 [2]: https://github.com/openshift/installer/blob/fe126cafe857fa5e4e7f88a2134a19ae2f089b85/data/data/bootstrap/files/usr/local/bin/bootkube.sh.template#L164-L166 [3]: https://github.com/openshift/installer/blob/fe126cafe857fa5e4e7f88a2134a19ae2f089b85/pkg/asset/manifests/featuregate.go#L17
1 parent b9e63d8 commit a3a6a16

File tree

2 files changed

+48
-7
lines changed

2 files changed

+48
-7
lines changed

cmd/render.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,17 @@ var (
1919
}
2020

2121
renderOpts struct {
22-
releaseImage string
23-
outputDir string
22+
releaseImage string
23+
featureGateManifestPath string
24+
outputDir string
2425
}
2526
)
2627

2728
func init() {
2829
rootCmd.AddCommand(renderCmd)
2930
renderCmd.PersistentFlags().StringVar(&renderOpts.outputDir, "output-dir", "", "The output directory where the manifests will be rendered.")
3031
renderCmd.PersistentFlags().StringVar(&renderOpts.releaseImage, "release-image", "", "The Openshift release image url.")
32+
renderCmd.PersistentFlags().StringVar(&renderOpts.featureGateManifestPath, "feature-gate-manifest-path", "", "FeatureGate manifest input path.")
3133
}
3234

3335
func runRenderCmd(cmd *cobra.Command, args []string) {
@@ -40,7 +42,7 @@ func runRenderCmd(cmd *cobra.Command, args []string) {
4042
if renderOpts.releaseImage == "" {
4143
klog.Fatalf("missing --release-image flag, it is required")
4244
}
43-
if err := payload.Render(renderOpts.outputDir, renderOpts.releaseImage, clusterProfile()); err != nil {
45+
if err := payload.Render(renderOpts.outputDir, renderOpts.releaseImage, renderOpts.featureGateManifestPath, clusterProfile()); err != nil {
4446
klog.Fatalf("Render command failed: %v", err)
4547
}
4648
}

pkg/payload/render.go

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,19 @@ import (
99
"text/template"
1010

1111
"github.com/openshift/api/config"
12+
configv1 "github.com/openshift/api/config/v1"
1213
"github.com/openshift/library-go/pkg/manifest"
1314
"github.com/pkg/errors"
15+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1416
"k8s.io/apimachinery/pkg/runtime/schema"
1517
utilerrors "k8s.io/apimachinery/pkg/util/errors"
1618
"k8s.io/apimachinery/pkg/util/sets"
19+
"k8s.io/klog/v2"
20+
"k8s.io/utils/ptr"
1721
)
1822

1923
// Render renders critical manifests from /manifests to outputDir.
20-
func Render(outputDir, releaseImage, clusterProfile string) error {
24+
func Render(outputDir, releaseImage, featureGateManifestPath, clusterProfile string) error {
2125
var (
2226
manifestsDir = filepath.Join(DefaultPayloadDir, CVOManifestDir)
2327
releaseManifestsDir = filepath.Join(DefaultPayloadDir, ReleaseManifestDir)
@@ -31,6 +35,35 @@ func Render(outputDir, releaseImage, clusterProfile string) error {
3135
}
3236
)
3337

38+
var requiredFeatureSet *string
39+
if featureGateManifestPath != "" {
40+
manifests, err := manifest.ManifestsFromFiles([]string{featureGateManifestPath})
41+
if err != nil {
42+
return fmt.Errorf("loading FeatureGate manifest: %w", err)
43+
}
44+
if len(manifests) != 1 {
45+
return fmt.Errorf("FeatureGate manifest %s contains %d manifests, but expected only one", featureGateManifestPath, len(manifests))
46+
}
47+
featureGateManifest := manifests[0]
48+
expectedGVK := schema.GroupVersionKind{Kind: "FeatureGate", Version: configv1.GroupVersion.Version, Group: config.GroupName}
49+
if featureGateManifest.GVK != expectedGVK {
50+
return fmt.Errorf("FeatureGate manifest %s GroupVersionKind %v, but expected %v", featureGateManifest.OriginalFilename, featureGateManifest.GVK, expectedGVK)
51+
}
52+
featureSet, found, err := unstructured.NestedString(featureGateManifest.Obj.Object, "spec", "featureSet")
53+
if err != nil {
54+
return fmt.Errorf("%s spec.featureSet lookup was not a string: %w", featureGateManifest.String(), err)
55+
} else if found {
56+
requiredFeatureSet = &featureSet
57+
klog.Infof("--feature-gate-manifest-path=%s results in feature set %q", featureGateManifest.OriginalFilename, featureSet)
58+
} else {
59+
requiredFeatureSet = ptr.To[string]("")
60+
klog.Infof("--feature-gate-manifest-path=%s does not set spec.featureSet, using the default feature set", featureGateManifest.OriginalFilename)
61+
}
62+
} else {
63+
requiredFeatureSet = ptr.To[string]("")
64+
klog.Info("--feature-gate-manifest-path is unset, using the default feature set")
65+
}
66+
3467
tasks := []struct {
3568
idir string
3669
odir string
@@ -61,7 +94,7 @@ func Render(outputDir, releaseImage, clusterProfile string) error {
6194
}}
6295
var errs []error
6396
for _, task := range tasks {
64-
if err := renderDir(renderConfig, task.idir, task.odir, task.processTemplate, task.skipFiles, task.filterGroupKind); err != nil {
97+
if err := renderDir(renderConfig, task.idir, task.odir, requiredFeatureSet, &clusterProfile, task.processTemplate, task.skipFiles, task.filterGroupKind); err != nil {
6598
errs = append(errs, err)
6699
}
67100
}
@@ -73,7 +106,7 @@ func Render(outputDir, releaseImage, clusterProfile string) error {
73106
return nil
74107
}
75108

76-
func renderDir(renderConfig manifestRenderConfig, idir, odir string, processTemplate bool, skipFiles sets.Set[string], filterGroupKind sets.Set[schema.GroupKind]) error {
109+
func renderDir(renderConfig manifestRenderConfig, idir, odir string, requiredFeatureSet *string, clusterProfile *string, processTemplate bool, skipFiles sets.Set[string], filterGroupKind sets.Set[schema.GroupKind]) error {
77110
if err := os.MkdirAll(odir, 0666); err != nil {
78111
return err
79112
}
@@ -97,6 +130,7 @@ func renderDir(renderConfig manifestRenderConfig, idir, odir string, processTemp
97130
// CustomNoUpgrade, TechPreviewNoUpgrade and DevPreviewNoUpgrade may add features to manifests like the ClusterVersion CRD,
98131
// but we do not need those features during bootstrap-render time. In those clusters, the production
99132
// CVO will be along shortly to update the manifests and deliver the gated features.
133+
// fixme: now that we have requiredFeatureSet, use it to do Manifest.Include() filtering here instead of making filename assumptions
100134
continue
101135
}
102136

@@ -127,8 +161,13 @@ func renderDir(renderConfig manifestRenderConfig, idir, odir string, processTemp
127161

128162
filteredManifests := make([]string, 0, len(manifests))
129163
for _, manifest := range manifests {
130-
if filterGroupKind.Has(manifest.GVK.GroupKind()) {
164+
if !filterGroupKind.Has(manifest.GVK.GroupKind()) {
165+
klog.Infof("excluding %s because we do not render that group/kind", manifest.String())
166+
} else if err := manifest.Include(nil, requiredFeatureSet, clusterProfile, nil, nil); err != nil {
167+
klog.Infof("excluding %s: %v", manifest.String(), err)
168+
} else {
131169
filteredManifests = append(filteredManifests, string(manifest.Raw))
170+
klog.Infof("including %s filtered by feature set %v and cluster profile %v", manifest.String(), requiredFeatureSet, clusterProfile)
132171
}
133172
}
134173

0 commit comments

Comments
 (0)