diff --git a/control-plane-operator/controllers/hostedcontrolplane/ignitionserver/ignitionserver.go b/control-plane-operator/controllers/hostedcontrolplane/ignitionserver/ignitionserver.go index b564885d262..b0766c29465 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/ignitionserver/ignitionserver.go +++ b/control-plane-operator/controllers/hostedcontrolplane/ignitionserver/ignitionserver.go @@ -437,7 +437,7 @@ func reconcileDeployment(deployment *appsv1.Deployment, }, Args: []string{ "-c", - invokeFeatureGateRenderScript("/shared", releaseVersion, string(featureGateYAML)), + invokeFeatureGateRenderScript("/shared", string(featureGateYAML)), }, Resources: corev1.ResourceRequirements{ Requests: corev1.ResourceList{ @@ -575,7 +575,8 @@ func reconcilePodMonitor(podMonitor *prometheusoperatorv1.PodMonitor, return nil } -func invokeFeatureGateRenderScript(workDir, payloadVersion, featureGateYAML string) string { +// invokeFeatureGateRenderScript writes the passed yaml to disk in a given dir. +func invokeFeatureGateRenderScript(workDir, featureGateYAML string) string { var script = `#!/bin/bash set -e cd /tmp @@ -583,16 +584,10 @@ mkdir input output manifests touch /tmp/manifests/99_feature-gate.yaml cat </tmp/manifests/99_feature-gate.yaml -%[3]s +%[2]s EOF -/usr/bin/cluster-config-operator render \ - --config-output-file config \ - --asset-input-dir /tmp/input \ - --asset-output-dir /tmp/output \ - --rendered-manifest-files=/tmp/manifests \ - --payload-version=%[2]s cp /tmp/manifests/99_feature-gate.yaml %[1]s/99_feature-gate.yaml ` - return fmt.Sprintf(script, workDir, payloadVersion, featureGateYAML) + return fmt.Sprintf(script, workDir, featureGateYAML) } diff --git a/ignition-server/controllers/local_ignitionprovider.go b/ignition-server/controllers/local_ignitionprovider.go index dc5cc79497a..5dd624625aa 100644 --- a/ignition-server/controllers/local_ignitionprovider.go +++ b/ignition-server/controllers/local_ignitionprovider.go @@ -240,23 +240,6 @@ func (p *LocalIgnitionProvider) GetPayload(ctx context.Context, releaseImage str return nil, fmt.Errorf("failed to extract templates from image: %w", err) } - // Write out the feature gate manifest to the MCC dir. - // Use the feature gate from the hosted control plane which should reflect the feature gate of the cluster. - if err := func() error { - featureGateBytes, err := os.ReadFile(p.FeatureGateManifest) - if err != nil { - return fmt.Errorf("failed to read feature gate: %w", err) - } - - if err := os.WriteFile(filepath.Join(mccBaseDir, "99_feature-gate.yaml"), featureGateBytes, 0644); err != nil { - return fmt.Errorf("failed to write feature gate: %w", err) - } - - return nil - }(); err != nil { - return nil, fmt.Errorf("failed to extract feature gate: %w", err) - } - // Extract binaries from the MCO image into the bin directory err = func() error { start := time.Now() @@ -276,6 +259,28 @@ func (p *LocalIgnitionProvider) GetPayload(ctx context.Context, releaseImage str return fmt.Errorf("failed to close file: %w", err) } } + + component := "cluster-config-operator" + clusterConfigOperatorImage, ok := imageProvider.ImageExist(component) + if !ok { + return fmt.Errorf("release image does not contain cluster-config-operator (images: %v)", imageProvider.ComponentImages()) + } + log.Info("discovered cluster config operator image", "image", clusterConfigOperatorImage) + + file, err := os.Create(filepath.Join(binDir, component)) + if err != nil { + return fmt.Errorf("failed to create file: %w", err) + } + if err := file.Chmod(0777); err != nil { + return fmt.Errorf("failed to chmod file: %w", err) + } + if err := p.ImageFileCache.extractImageFile(ctx, clusterConfigOperatorImage, pullSecret, filepath.Join("usr/bin/", component), file); err != nil { + return fmt.Errorf("failed to extract image file: %w", err) + } + if err := file.Close(); err != nil { + return fmt.Errorf("failed to close file: %w", err) + } + log.Info("downloaded binaries", "time", time.Since(start).Round(time.Second).String()) return nil }() @@ -288,6 +293,31 @@ func (p *LocalIgnitionProvider) GetPayload(ctx context.Context, releaseImage str return nil, fmt.Errorf("failed to parse payload version: %w", err) } + featureGateBytes, err := os.ReadFile(p.FeatureGateManifest) + if err != nil { + return nil, fmt.Errorf("failed to read feature gate: %w", err) + } + + err = func() error { + start := time.Now() + + args := []string{ + "-c", + invokeFeatureGateRenderScript(mccBaseDir, payloadVersion.String(), string(featureGateBytes)), + } + + cmd := exec.CommandContext(ctx, "/bin/bash", args...) + out, err := cmd.CombinedOutput() + log.Info("cluster-config-operator process completed", "time", time.Since(start).Round(time.Second).String(), "output", string(out)) + if err != nil { + return fmt.Errorf("cluster-config-operator process failed: %w", err) + } + return nil + }() + if err != nil { + return nil, fmt.Errorf("failed to execute cluster-config-operator: %w", err) + } + // First, run the MCO using templates and image refs as input. This generates // output for the MCC. err = func() error { @@ -678,3 +708,25 @@ func findMatchingManifest(imageRef string, deserializedManifestList *manifestlis return "", fmt.Errorf("imageRef is an unknown format to parse, imageRef: %s", imageRef) } + +func invokeFeatureGateRenderScript(workDir, payloadVersion, featureGateYAML string) string { + var script = `#!/bin/bash +set -e +cd /tmp +mkdir input output manifests + +touch /tmp/manifests/99_feature-gate.yaml +cat </tmp/manifests/99_feature-gate.yaml +%[3]s +EOF + +/usr/bin/cluster-config-operator render \ + --config-output-file config \ + --asset-input-dir /tmp/input \ + --asset-output-dir /tmp/output \ + --rendered-manifest-files=/tmp/manifests \ + --payload-version=%[2]s +cp /tmp/manifests/99_feature-gate.yaml %[1]s/99_feature-gate.yaml +` + return fmt.Sprintf(script, workDir, payloadVersion, featureGateYAML) +}