From a050687c35950cfb1024f5d7cf3c1caf4ebf559b Mon Sep 17 00:00:00 2001 From: Craig O'Donnell Date: Tue, 30 Jan 2024 21:42:25 +0000 Subject: [PATCH 1/3] load preflights from helm chart templates as kotskinds --- pkg/kotsutil/kots.go | 14 ++++++-- pkg/pull/pull.go | 31 +++++++++++++++--- pkg/rewrite/rewrite.go | 31 +++++++++++++++--- .../upstream/my-preflight-chart-0.1.0.tgz | Bin 0 -> 631 bytes .../upstream/my-preflight-chart.yaml | 11 +++++++ .../my-preflight-chart-0.1.0.tgz | Bin 0 -> 631 bytes .../helm/my-preflight-chart/values.yaml | 1 + .../wantResults/kotsKinds/helm-preflight.yaml | 23 +++++++++++++ .../kotsKinds/my-preflight-chart.yaml | 11 +++++++ .../helm/my-preflight-chart/all.yaml | 29 ++++++++++++++++ .../upstream/my-preflight-chart-0.1.0.tgz | Bin 0 -> 631 bytes .../upstream/my-preflight-chart.yaml | 11 +++++++ 12 files changed, 151 insertions(+), 11 deletions(-) create mode 100644 pkg/tests/pull/cases/kotskinds/upstream/my-preflight-chart-0.1.0.tgz create mode 100644 pkg/tests/pull/cases/kotskinds/upstream/my-preflight-chart.yaml create mode 100644 pkg/tests/pull/cases/kotskinds/wantResults/helm/my-preflight-chart/my-preflight-chart-0.1.0.tgz create mode 100644 pkg/tests/pull/cases/kotskinds/wantResults/helm/my-preflight-chart/values.yaml create mode 100644 pkg/tests/pull/cases/kotskinds/wantResults/kotsKinds/helm-preflight.yaml create mode 100644 pkg/tests/pull/cases/kotskinds/wantResults/kotsKinds/my-preflight-chart.yaml create mode 100644 pkg/tests/pull/cases/kotskinds/wantResults/rendered/this-cluster/helm/my-preflight-chart/all.yaml create mode 100644 pkg/tests/pull/cases/kotskinds/wantResults/upstream/my-preflight-chart-0.1.0.tgz create mode 100644 pkg/tests/pull/cases/kotskinds/wantResults/upstream/my-preflight-chart.yaml diff --git a/pkg/kotsutil/kots.go b/pkg/kotsutil/kots.go index 8e939dd79e..a559eebdbd 100644 --- a/pkg/kotsutil/kots.go +++ b/pkg/kotsutil/kots.go @@ -1475,14 +1475,22 @@ func FilterV1Beta1ChartsWithV1Beta2Charts(v1Beta1Charts []kotsv1beta1.HelmChart, } func MustMarshalInstallation(installation *kotsv1beta1.Installation) []byte { + b, err := MarshalRuntimeObject(installation) + if err != nil { + panic(err) + } + return b +} + +func MarshalRuntimeObject(obj runtime.Object) ([]byte, error) { s := json.NewYAMLSerializer(json.DefaultMetaFactory, scheme.Scheme, scheme.Scheme) var b bytes.Buffer - if err := s.Encode(installation, &b); err != nil { - panic(err) + if err := s.Encode(obj, &b); err != nil { + return nil, errors.Wrap(err, "failed to encode object") } - return b.Bytes() + return b.Bytes(), nil } // this is here to avoid a circular dependency diff --git a/pkg/pull/pull.go b/pkg/pull/pull.go index 26679f2add..bb06fd6bac 100644 --- a/pkg/pull/pull.go +++ b/pkg/pull/pull.go @@ -33,6 +33,8 @@ import ( "github.com/replicatedhq/kots/pkg/util" kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1" kotsv1beta2 "github.com/replicatedhq/kotskinds/apis/kots/v1beta2" + troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2" + troubleshootpreflight "github.com/replicatedhq/troubleshoot/pkg/preflight" k8sjson "k8s.io/apimachinery/pkg/runtime/serializer/json" "k8s.io/client-go/kubernetes/scheme" ) @@ -585,10 +587,6 @@ func Pull(upstreamURI string, pullOptions PullOptions) (string, error) { } renderedKotsKindsMap["userdata/installation.yaml"] = []byte(installationBytes) - if err := kotsutil.WriteKotsKinds(renderedKotsKindsMap, u.GetKotsKindsDir(writeUpstreamOptions)); err != nil { - return "", errors.Wrap(err, "failed to write the rendered kots kinds") - } - if err := rendered.WriteRenderedApp(&rendered.WriteOptions{ BaseDir: u.GetBaseDir(writeUpstreamOptions), OverlaysDir: u.GetOverlaysDir(writeUpstreamOptions), @@ -604,6 +602,31 @@ func Pull(upstreamURI string, pullOptions PullOptions) (string, error) { return "", errors.Wrap(err, "failed to write rendered") } + // preflights may also be included within helm chart templates, so load any from the rendered dir + tsKinds, err := kotsutil.LoadTSKindsFromPath(u.GetRenderedDir(writeUpstreamOptions)) + if err != nil { + return "", errors.Wrap(err, fmt.Sprintf("failed to load troubleshoot kinds from path: %s", u.GetRenderedDir(writeUpstreamOptions))) + } + + if tsKinds.PreflightsV1Beta2 != nil { + var renderedPreflight *troubleshootv1beta2.Preflight + for _, v := range tsKinds.PreflightsV1Beta2 { + renderedPreflight = troubleshootpreflight.ConcatPreflightSpec(renderedPreflight, &v) + } + + if renderedPreflight != nil { + renderedPreflightBytes, err := kotsutil.MarshalRuntimeObject(renderedPreflight) + if err != nil { + return "", errors.Wrap(err, "failed to marshal rendered preflight") + } + renderedKotsKindsMap["helm-preflight.yaml"] = renderedPreflightBytes + } + } + + if err := kotsutil.WriteKotsKinds(renderedKotsKindsMap, u.GetKotsKindsDir(writeUpstreamOptions)); err != nil { + return "", errors.Wrap(err, "failed to write the rendered kots kinds") + } + return filepath.Join(pullOptions.RootDir, u.Name), nil } diff --git a/pkg/rewrite/rewrite.go b/pkg/rewrite/rewrite.go index dd77a670f8..96f042b557 100644 --- a/pkg/rewrite/rewrite.go +++ b/pkg/rewrite/rewrite.go @@ -25,6 +25,8 @@ import ( "github.com/replicatedhq/kots/pkg/upstream" upstreamtypes "github.com/replicatedhq/kots/pkg/upstream/types" kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1" + troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2" + troubleshootpreflight "github.com/replicatedhq/troubleshoot/pkg/preflight" ) type RewriteOptions struct { @@ -320,10 +322,6 @@ func Rewrite(rewriteOptions RewriteOptions) error { } renderedKotsKindsMap["userdata/installation.yaml"] = installationBytes - if err := kotsutil.WriteKotsKinds(renderedKotsKindsMap, u.GetKotsKindsDir(writeUpstreamOptions)); err != nil { - return errors.Wrap(err, "failed to write kots base") - } - if err := rendered.WriteRenderedApp(&rendered.WriteOptions{ BaseDir: u.GetBaseDir(writeUpstreamOptions), OverlaysDir: u.GetOverlaysDir(writeUpstreamOptions), @@ -339,6 +337,31 @@ func Rewrite(rewriteOptions RewriteOptions) error { return errors.Wrap(err, "failed to write rendered") } + // preflights may also be included within helm chart templates, so load any from the rendered dir + tsKinds, err := kotsutil.LoadTSKindsFromPath(u.GetRenderedDir(writeUpstreamOptions)) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("failed to load troubleshoot kinds from path: %s", u.GetRenderedDir(writeUpstreamOptions))) + } + + if tsKinds.PreflightsV1Beta2 != nil { + var renderedPreflight *troubleshootv1beta2.Preflight + for _, v := range tsKinds.PreflightsV1Beta2 { + renderedPreflight = troubleshootpreflight.ConcatPreflightSpec(renderedPreflight, &v) + } + + if renderedPreflight != nil { + renderedPreflightBytes, err := kotsutil.MarshalRuntimeObject(renderedPreflight) + if err != nil { + return errors.Wrap(err, "failed to marshal rendered preflight") + } + renderedKotsKindsMap["helm-preflight.yaml"] = renderedPreflightBytes + } + } + + if err := kotsutil.WriteKotsKinds(renderedKotsKindsMap, u.GetKotsKindsDir(writeUpstreamOptions)); err != nil { + return errors.Wrap(err, "failed to write the rendered kots kinds") + } + log.FinishSpinner() return nil diff --git a/pkg/tests/pull/cases/kotskinds/upstream/my-preflight-chart-0.1.0.tgz b/pkg/tests/pull/cases/kotskinds/upstream/my-preflight-chart-0.1.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..a43c1e8bade219230f0b27c35a5c63d4d2ab71e8 GIT binary patch literal 631 zcmV--0*L(|iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PI!YYuhjo&a?lDBhQT@r-=h*FJpTc493{TV2nLn>`N>vS(_17WSWulwA5-<@u;ZK^Y~T!D;hL<@H~)G%4|CA zo>I!=r<};?Af3);*(96J=a&PSPUmSh0QpS(k0J&}Kafx6Iu`ej0G;|wJ}6t~a6L)T zx&5mYsgOxYq43IaXL<>5NE_(t1eVsr+qfWK6H`cPG?c^rdP=x)lmj}aRe|j~$@L+{ z-`<1&84vV7lW`iE!q_w$)1Aw2jfE5apJrKh*#DFCa(?drKZ1k)Pm?QEmpOc-!V@Qk z7)xZ#69A11(xLqaz~07%rchbSB2?o|(7r|zfXyrz-rRurK$_@8(*-e3I=@XS?|Z2L^kuZzB!|kc(2atzS2SV@y&~`Y zf}>&=QCO|1VCzE;U%zdQSfg%!kPkaAfDsfr1}4ADb^oP>ja*nm;n3PfEm7%XYm0S7 zbq>Q9kc#wD$l(JnhC;v<2F$e$v literal 0 HcmV?d00001 diff --git a/pkg/tests/pull/cases/kotskinds/upstream/my-preflight-chart.yaml b/pkg/tests/pull/cases/kotskinds/upstream/my-preflight-chart.yaml new file mode 100644 index 0000000000..40a858c9bd --- /dev/null +++ b/pkg/tests/pull/cases/kotskinds/upstream/my-preflight-chart.yaml @@ -0,0 +1,11 @@ +# this chart validates that preflights inside helm chart templates are processed correctly as kotskinds +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: my-preflight-chart + annotations: + kots.io/exclude: "true" +spec: + chart: + name: my-preflight-chart + chartVersion: 0.1.0 diff --git a/pkg/tests/pull/cases/kotskinds/wantResults/helm/my-preflight-chart/my-preflight-chart-0.1.0.tgz b/pkg/tests/pull/cases/kotskinds/wantResults/helm/my-preflight-chart/my-preflight-chart-0.1.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..a43c1e8bade219230f0b27c35a5c63d4d2ab71e8 GIT binary patch literal 631 zcmV--0*L(|iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PI!YYuhjo&a?lDBhQT@r-=h*FJpTc493{TV2nLn>`N>vS(_17WSWulwA5-<@u;ZK^Y~T!D;hL<@H~)G%4|CA zo>I!=r<};?Af3);*(96J=a&PSPUmSh0QpS(k0J&}Kafx6Iu`ej0G;|wJ}6t~a6L)T zx&5mYsgOxYq43IaXL<>5NE_(t1eVsr+qfWK6H`cPG?c^rdP=x)lmj}aRe|j~$@L+{ z-`<1&84vV7lW`iE!q_w$)1Aw2jfE5apJrKh*#DFCa(?drKZ1k)Pm?QEmpOc-!V@Qk z7)xZ#69A11(xLqaz~07%rchbSB2?o|(7r|zfXyrz-rRurK$_@8(*-e3I=@XS?|Z2L^kuZzB!|kc(2atzS2SV@y&~`Y zf}>&=QCO|1VCzE;U%zdQSfg%!kPkaAfDsfr1}4ADb^oP>ja*nm;n3PfEm7%XYm0S7 zbq>Q9kc#wD$l(JnhC;v<2F$e$v literal 0 HcmV?d00001 diff --git a/pkg/tests/pull/cases/kotskinds/wantResults/helm/my-preflight-chart/values.yaml b/pkg/tests/pull/cases/kotskinds/wantResults/helm/my-preflight-chart/values.yaml new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pkg/tests/pull/cases/kotskinds/wantResults/helm/my-preflight-chart/values.yaml @@ -0,0 +1 @@ +{} diff --git a/pkg/tests/pull/cases/kotskinds/wantResults/kotsKinds/helm-preflight.yaml b/pkg/tests/pull/cases/kotskinds/wantResults/kotsKinds/helm-preflight.yaml new file mode 100644 index 0000000000..4aa57bd50b --- /dev/null +++ b/pkg/tests/pull/cases/kotskinds/wantResults/kotsKinds/helm-preflight.yaml @@ -0,0 +1,23 @@ +apiVersion: troubleshoot.sh/v1beta2 +kind: Preflight +metadata: + creationTimestamp: null + name: airgap-smoke-test-preflight +spec: + analyzers: + - clusterVersion: + outcomes: + - fail: + message: The application requires at Kubernetes 1.13.0 or later, and recommends + 1.15.0. + uri: https://www.kubernetes.io + when: < 1.13.0 + - warn: + message: Your cluster meets the minimum version of Kubernetes, but we recommend + you update to 1.15.0 or later. + uri: https://kubernetes.io + when: < 1.15.0 + - pass: + message: Your cluster meets the minimum version of Kubernetes recommended + by the application. +status: {} diff --git a/pkg/tests/pull/cases/kotskinds/wantResults/kotsKinds/my-preflight-chart.yaml b/pkg/tests/pull/cases/kotskinds/wantResults/kotsKinds/my-preflight-chart.yaml new file mode 100644 index 0000000000..40a858c9bd --- /dev/null +++ b/pkg/tests/pull/cases/kotskinds/wantResults/kotsKinds/my-preflight-chart.yaml @@ -0,0 +1,11 @@ +# this chart validates that preflights inside helm chart templates are processed correctly as kotskinds +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: my-preflight-chart + annotations: + kots.io/exclude: "true" +spec: + chart: + name: my-preflight-chart + chartVersion: 0.1.0 diff --git a/pkg/tests/pull/cases/kotskinds/wantResults/rendered/this-cluster/helm/my-preflight-chart/all.yaml b/pkg/tests/pull/cases/kotskinds/wantResults/rendered/this-cluster/helm/my-preflight-chart/all.yaml new file mode 100644 index 0000000000..cab3760d2b --- /dev/null +++ b/pkg/tests/pull/cases/kotskinds/wantResults/rendered/this-cluster/helm/my-preflight-chart/all.yaml @@ -0,0 +1,29 @@ +--- +# Source: my-preflight-chart/templates/my-chart-preflight.yaml +apiVersion: v1 +kind: Secret +metadata: + labels: + troubleshoot.sh/kind: preflight + name: "my-preflight-chart-preflight-config" +stringData: + preflight.yaml: | + apiVersion: troubleshoot.sh/v1beta2 + kind: Preflight + metadata: + name: airgap-smoke-test-preflight + spec: + collectors: [] + analyzers: + - clusterVersion: + outcomes: + - fail: + when: "< 1.13.0" + message: The application requires at Kubernetes 1.13.0 or later, and recommends 1.15.0. + uri: https://www.kubernetes.io + - warn: + when: "< 1.15.0" + message: Your cluster meets the minimum version of Kubernetes, but we recommend you update to 1.15.0 or later. + uri: https://kubernetes.io + - pass: + message: Your cluster meets the minimum version of Kubernetes recommended by the application. diff --git a/pkg/tests/pull/cases/kotskinds/wantResults/upstream/my-preflight-chart-0.1.0.tgz b/pkg/tests/pull/cases/kotskinds/wantResults/upstream/my-preflight-chart-0.1.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..a43c1e8bade219230f0b27c35a5c63d4d2ab71e8 GIT binary patch literal 631 zcmV--0*L(|iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PI!YYuhjo&a?lDBhQT@r-=h*FJpTc493{TV2nLn>`N>vS(_17WSWulwA5-<@u;ZK^Y~T!D;hL<@H~)G%4|CA zo>I!=r<};?Af3);*(96J=a&PSPUmSh0QpS(k0J&}Kafx6Iu`ej0G;|wJ}6t~a6L)T zx&5mYsgOxYq43IaXL<>5NE_(t1eVsr+qfWK6H`cPG?c^rdP=x)lmj}aRe|j~$@L+{ z-`<1&84vV7lW`iE!q_w$)1Aw2jfE5apJrKh*#DFCa(?drKZ1k)Pm?QEmpOc-!V@Qk z7)xZ#69A11(xLqaz~07%rchbSB2?o|(7r|zfXyrz-rRurK$_@8(*-e3I=@XS?|Z2L^kuZzB!|kc(2atzS2SV@y&~`Y zf}>&=QCO|1VCzE;U%zdQSfg%!kPkaAfDsfr1}4ADb^oP>ja*nm;n3PfEm7%XYm0S7 zbq>Q9kc#wD$l(JnhC;v<2F$e$v literal 0 HcmV?d00001 diff --git a/pkg/tests/pull/cases/kotskinds/wantResults/upstream/my-preflight-chart.yaml b/pkg/tests/pull/cases/kotskinds/wantResults/upstream/my-preflight-chart.yaml new file mode 100644 index 0000000000..40a858c9bd --- /dev/null +++ b/pkg/tests/pull/cases/kotskinds/wantResults/upstream/my-preflight-chart.yaml @@ -0,0 +1,11 @@ +# this chart validates that preflights inside helm chart templates are processed correctly as kotskinds +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: my-preflight-chart + annotations: + kots.io/exclude: "true" +spec: + chart: + name: my-preflight-chart + chartVersion: 0.1.0 From a45c26f129b9f7a8f2b9eac924d34d12af523d52 Mon Sep 17 00:00:00 2001 From: Craig O'Donnell Date: Tue, 30 Jan 2024 21:43:06 +0000 Subject: [PATCH 2/3] re-fetch app details after initial config is saved --- .../AppConfig/components/AppConfig.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/web/src/features/AppConfig/components/AppConfig.tsx b/web/src/features/AppConfig/components/AppConfig.tsx index e9214d58f2..ff9057648d 100644 --- a/web/src/features/AppConfig/components/AppConfig.tsx +++ b/web/src/features/AppConfig/components/AppConfig.tsx @@ -141,8 +141,10 @@ class AppConfig extends Component { } window.addEventListener("resize", this.determineSidebarHeight); - if (!this.props.app) { - this.getApp(); + if (!app) { + this.fetchApp(); + } else { + this.setState({ app }); } this.getConfig(); } @@ -204,11 +206,7 @@ class AppConfig extends Component { } }; - getApp = async () => { - if (this.props.app) { - return; - } - + fetchApp = async (): Promise => { try { const { slug } = this.props.params; const res = await fetch(`${process.env.API_ENDPOINT}/app/${slug}`, { @@ -221,6 +219,7 @@ class AppConfig extends Component { if (res.ok && res.status == 200) { const app = await res.json(); this.setState({ app }); + return app; } } catch (err) { console.log(err); @@ -416,7 +415,8 @@ class AppConfig extends Component { } if (fromLicenseFlow) { - const hasPreflight = this.props.app.hasPreflight; + const app = await this.fetchApp(); + const hasPreflight = app?.hasPreflight; if (hasPreflight) { navigate(`/${slug}/preflight`, { replace: true }); @@ -661,6 +661,7 @@ class AppConfig extends Component { render() { const { + app, changed, showConfigError, configErrorMessage, @@ -675,7 +676,6 @@ class AppConfig extends Component { showValidationError, } = this.state; const { fromLicenseFlow, params, isHelmManaged } = this.props; - const app = this.props.app; if (configLoading || !app) { return ( From c56130ee3b124530ad3d435b59a08dac6eddffaa Mon Sep 17 00:00:00 2001 From: Craig O'Donnell Date: Fri, 2 Feb 2024 14:02:27 +0000 Subject: [PATCH 3/3] read installation just before writing kotskinds --- pkg/pull/pull.go | 14 +++++++------- pkg/rewrite/rewrite.go | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pkg/pull/pull.go b/pkg/pull/pull.go index bb06fd6bac..8efa3df09a 100644 --- a/pkg/pull/pull.go +++ b/pkg/pull/pull.go @@ -580,13 +580,6 @@ func Pull(upstreamURI string, pullOptions PullOptions) (string, error) { } } - // installation spec gets updated during the process, ensure the map has the latest version - installationBytes, err := os.ReadFile(filepath.Join(u.GetUpstreamDir(writeUpstreamOptions), "userdata", "installation.yaml")) - if err != nil { - return "", errors.Wrap(err, "failed to read installation file") - } - renderedKotsKindsMap["userdata/installation.yaml"] = []byte(installationBytes) - if err := rendered.WriteRenderedApp(&rendered.WriteOptions{ BaseDir: u.GetBaseDir(writeUpstreamOptions), OverlaysDir: u.GetOverlaysDir(writeUpstreamOptions), @@ -623,6 +616,13 @@ func Pull(upstreamURI string, pullOptions PullOptions) (string, error) { } } + // installation spec gets updated during the process, ensure the map has the latest version + installationBytes, err := os.ReadFile(filepath.Join(u.GetUpstreamDir(writeUpstreamOptions), "userdata", "installation.yaml")) + if err != nil { + return "", errors.Wrap(err, "failed to read installation file") + } + renderedKotsKindsMap["userdata/installation.yaml"] = []byte(installationBytes) + if err := kotsutil.WriteKotsKinds(renderedKotsKindsMap, u.GetKotsKindsDir(writeUpstreamOptions)); err != nil { return "", errors.Wrap(err, "failed to write the rendered kots kinds") } diff --git a/pkg/rewrite/rewrite.go b/pkg/rewrite/rewrite.go index 96f042b557..45981575e2 100644 --- a/pkg/rewrite/rewrite.go +++ b/pkg/rewrite/rewrite.go @@ -315,13 +315,6 @@ func Rewrite(rewriteOptions RewriteOptions) error { return errors.Wrap(err, "failed to update installation spec") } - // installation spec gets updated during the process, ensure the map has the latest version - installationBytes, err := os.ReadFile(filepath.Join(u.GetUpstreamDir(writeUpstreamOptions), "userdata", "installation.yaml")) - if err != nil { - return errors.Wrap(err, "failed to read installation file") - } - renderedKotsKindsMap["userdata/installation.yaml"] = installationBytes - if err := rendered.WriteRenderedApp(&rendered.WriteOptions{ BaseDir: u.GetBaseDir(writeUpstreamOptions), OverlaysDir: u.GetOverlaysDir(writeUpstreamOptions), @@ -358,6 +351,13 @@ func Rewrite(rewriteOptions RewriteOptions) error { } } + // installation spec gets updated during the process, ensure the map has the latest version + installationBytes, err := os.ReadFile(filepath.Join(u.GetUpstreamDir(writeUpstreamOptions), "userdata", "installation.yaml")) + if err != nil { + return errors.Wrap(err, "failed to read installation file") + } + renderedKotsKindsMap["userdata/installation.yaml"] = installationBytes + if err := kotsutil.WriteKotsKinds(renderedKotsKindsMap, u.GetKotsKindsDir(writeUpstreamOptions)); err != nil { return errors.Wrap(err, "failed to write the rendered kots kinds") }