Skip to content

Commit ce6c0b8

Browse files
Merge pull request #1078 from wking/feature-gated-render
OCPBUGS-37770: cmd/render: Add --feature-gate-manifest-path option
2 parents b9e63d8 + a3a6a16 commit ce6c0b8

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)