diff --git a/CHANGELOG.md b/CHANGELOG.md index 2991d38387..d9727af392 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Upgrade to Pulumi v2.9.0, which adds type annotations and input/output classes to Python (https://github.com/pulumi/pulumi-kubernetes/pull/1276) - Switch Helm v3 logic to use native library. (https://github.com/pulumi/pulumi-kubernetes/pull/1263) - Bump python requests version dependency. (https://github.com/pulumi/pulumi-kubernetes/pull/1274) +- Update NodeJS Helm v3 to use native client. (https://github.com/pulumi/pulumi-kubernetes/pull/1279) ## 2.5.0 (August 26, 2020) diff --git a/provider/cmd/pulumi-gen-kubernetes/main.go b/provider/cmd/pulumi-gen-kubernetes/main.go index c31e57bf7f..7390d52d44 100644 --- a/provider/cmd/pulumi-gen-kubernetes/main.go +++ b/provider/cmd/pulumi-gen-kubernetes/main.go @@ -194,7 +194,7 @@ func writeNodeJSClient(pkg *schema.Package, outdir, templateDir string) { overlays := map[string][]byte{ "apiextensions/customResource.ts": mustLoadFile(filepath.Join(templateDir, "apiextensions", "customResource.ts")), "helm/v2/helm.ts": mustLoadFile(filepath.Join(templateDir, "helm", "v2", "helm.ts")), - "helm/v3/helm.ts": mustLoadFile(filepath.Join(templateDir, "helm", "v2", "helm.ts")), // v3 support is currently identical to v2 + "helm/v3/helm.ts": mustLoadFile(filepath.Join(templateDir, "helm", "v3", "helm.ts")), "kustomize/kustomize.ts": mustLoadFile(filepath.Join(templateDir, "kustomize", "kustomize.ts")), "yaml/yaml.ts": mustRenderTemplate(filepath.Join(templateDir, "yaml", "yaml.tmpl"), templateResources), } diff --git a/provider/pkg/gen/nodejs-templates/helm/v2/helm.ts b/provider/pkg/gen/nodejs-templates/helm/v2/helm.ts index ce08578a2e..2fc7cddd39 100644 --- a/provider/pkg/gen/nodejs-templates/helm/v2/helm.ts +++ b/provider/pkg/gen/nodejs-templates/helm/v2/helm.ts @@ -43,7 +43,7 @@ import * as yaml from "../../yaml/index"; * ```typescript * import * as k8s from "@pulumi/kubernetes"; * - * const nginxIngress = new k8s.helm.v3.Chart("nginx-ingress", { + * const nginxIngress = new k8s.helm.v2.Chart("nginx-ingress", { * path: "./nginx-ingress", * }); * ``` @@ -52,7 +52,7 @@ import * as yaml from "../../yaml/index"; * ```typescript * import * as k8s from "@pulumi/kubernetes"; * - * const nginxIngress = new k8s.helm.v3.Chart("nginx-ingress", { + * const nginxIngress = new k8s.helm.v2.Chart("nginx-ingress", { * chart: "nginx-ingress", * version: "1.24.4", * fetchOpts:{ @@ -65,7 +65,7 @@ import * as yaml from "../../yaml/index"; * ```typescript * import * as k8s from "@pulumi/kubernetes"; * - * const nginxIngress = new k8s.helm.v3.Chart("nginx-ingress", { + * const nginxIngress = new k8s.helm.v2.Chart("nginx-ingress", { * chart: "nginx-ingress", * version: "1.24.4", * fetchOpts:{ @@ -85,7 +85,7 @@ import * as yaml from "../../yaml/index"; * ```typescript * import * as k8s from "@pulumi/kubernetes"; * - * const nginxIngress = new k8s.helm.v3.Chart("nginx-ingress", { + * const nginxIngress = new k8s.helm.v2.Chart("nginx-ingress", { * chart: "nginx-ingress", * version: "1.24.4", * namespace: "test-namespace", @@ -99,7 +99,7 @@ import * as yaml from "../../yaml/index"; * ```typescript * import * as k8s from "@pulumi/kubernetes"; * - * const nginxIngress = new k8s.helm.v3.Chart("nginx-ingress", { + * const nginxIngress = new k8s.helm.v2.Chart("nginx-ingress", { * chart: "nginx-ingress", * version: "1.24.4", * fetchOpts:{ @@ -204,12 +204,10 @@ export class Chart extends yaml.CollectionComponentResource { const release = shell.quote([releaseName]); const values = path.quotePath(overrides.name); const apiVersionsArgs = cfg.apiVersions - ? cfg.apiVersions.length > 1 - ? `--api-versions={${cfg.apiVersions - .map(apiVersion => shell.quote([apiVersion])) - .join(',')}}` - : `--api-versions=${shell.quote(cfg.apiVersions)}` - : ''; + ? cfg.apiVersions + .map(v => `--api-versions=${v}`) + .join(" ") + : ""; const namespaceArg = cfg.namespace ? `--namespace ${shell.quote([cfg.namespace])}` : ""; diff --git a/provider/pkg/gen/nodejs-templates/helm/v3/helm.ts b/provider/pkg/gen/nodejs-templates/helm/v3/helm.ts new file mode 100644 index 0000000000..140995314b --- /dev/null +++ b/provider/pkg/gen/nodejs-templates/helm/v3/helm.ts @@ -0,0 +1,356 @@ +// Copyright 2016-2020, Pulumi Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// *** WARNING: this file was generated by the pulumigen. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as path from "../../path"; +import { getVersion } from "../../utilities"; +import * as yaml from "../../yaml/index"; + +/** + * Chart is a component representing a collection of resources described by an arbitrary Helm + * Chart. The Chart can be fetched from any source that is accessible to the `helm` command + * line. Values in the `values.yml` file can be overridden using `ChartOpts.values` (equivalent + * to `--set` or having multiple `values.yml` files). Objects can be transformed arbitrarily by + * supplying callbacks to `ChartOpts.transformations`. + * + * `Chart` does not use Tiller. The Chart specified is copied and expanded locally; the semantics + * are equivalent to running `helm template` and then using Pulumi to manage the resulting YAML + * manifests. Any values that would be retrieved in-cluster are assigned fake values, and + * none of Tiller's server-side validity testing is executed. + * + * ## Example Usage + * ### Local Chart Directory + * + * ```typescript + * import * as k8s from "@pulumi/kubernetes"; + * + * const nginxIngress = new k8s.helm.v3.Chart("nginx-ingress", { + * path: "./nginx-ingress", + * }); + * ``` + * ### Remote Chart + * + * ```typescript + * import * as k8s from "@pulumi/kubernetes"; + * + * const nginxIngress = new k8s.helm.v3.Chart("nginx-ingress", { + * chart: "nginx-ingress", + * version: "1.24.4", + * fetchOpts:{ + * repo: "https://kubernetes-charts.storage.googleapis.com/", + * }, + * }); + * ``` + * ### Set Chart values + * + * ```typescript + * import * as k8s from "@pulumi/kubernetes"; + * + * const nginxIngress = new k8s.helm.v3.Chart("nginx-ingress", { + * chart: "nginx-ingress", + * version: "1.24.4", + * fetchOpts:{ + * repo: "https://kubernetes-charts.storage.googleapis.com/", + * }, + * values: { + * controller: { + * metrics: { + * enabled: true, + * } + * } + * }, + * }); + * ``` + * ### Deploy Chart into Namespace + * + * ```typescript + * import * as k8s from "@pulumi/kubernetes"; + * + * const nginxIngress = new k8s.helm.v3.Chart("nginx-ingress", { + * chart: "nginx-ingress", + * version: "1.24.4", + * namespace: "test-namespace", + * fetchOpts:{ + * repo: "https://kubernetes-charts.storage.googleapis.com/", + * }, + * }); + * ``` + * ### Chart with Transformations + * + * ```typescript + * import * as k8s from "@pulumi/kubernetes"; + * + * const nginxIngress = new k8s.helm.v3.Chart("nginx-ingress", { + * chart: "nginx-ingress", + * version: "1.24.4", + * fetchOpts:{ + * repo: "https://kubernetes-charts.storage.googleapis.com/", + * }, + * transformations: [ + * // Make every service private to the cluster, i.e., turn all services into ClusterIP instead of LoadBalancer. + * (obj: any, opts: pulumi.CustomResourceOptions) => { + * if (obj.kind === "Service" && obj.apiVersion === "v1") { + * if (obj.spec && obj.spec.type && obj.spec.type === "LoadBalancer") { + * obj.spec.type = "ClusterIP"; + * } + * } + * }, + * + * // Set a resource alias for a previous name. + * (obj: any, opts: pulumi.CustomResourceOptions) => { + * if (obj.kind === "Deployment") { + * opts.aliases = [{ name: "oldName" }] + * }, + * + * // Omit a resource from the Chart by transforming the specified resource definition to an empty List. + * (obj: any, opts: pulumi.CustomResourceOptions) => { + * if (obj.kind === "Pod" && obj.metadata.name === "test") { + * obj.apiVersion = "v1" + * obj.kind = "List" + * }, + * ], + * }); + * ``` + */ +export class Chart extends yaml.CollectionComponentResource { + /** + * Create an instance of the specified Helm chart. + * @param releaseName Name of the Chart (e.g., nginx-ingress). + * @param config Configuration options for the Chart. + * @param opts A bag of options that control this resource's behavior. + */ + constructor( + releaseName: string, + config: ChartOpts | LocalChartOpts, + opts?: pulumi.ComponentResourceOptions + ) { + if (config.resourcePrefix !== undefined) { + releaseName = `${config.resourcePrefix}-${releaseName}` + } + const aliasOpts: pulumi.ComponentResourceOptions = {...opts, aliases: [{type:"kubernetes:helm.sh/v2:Chart"}]} + super("kubernetes:helm.sh/v3:Chart", releaseName, config, aliasOpts); + + const allConfig = pulumi.output(config); + + (allConfig).isKnown.then((isKnown: boolean) => { + if (!isKnown) { + // Note that this can only happen during a preview. + pulumi.log.info("[Can't preview] all chart values must be known ahead of time to generate an " + + "accurate preview.", this); + } + }); + + this.resources = allConfig.apply(cfg => { + return this.parseChart(cfg, releaseName, opts) + }); + } + + parseChart(config: ChartOpts | LocalChartOpts, releaseName: string, opts?: pulumi.ComponentResourceOptions) { + const blob = { + ...config, + releaseName, + + toJSON() { + let obj: any = {}; + for (const [key, value] of Object.entries(this)) { + if (value) { + switch(key) { + case "apiVersions": { + obj["api_versions"] = value; + break; + } + case "caFile": { + obj["ca_file"] = value; + break; + } + case "certFile": { + obj["cert_file"] = value; + break; + } + case "fetchOpts": { + obj["fetch_opts"] = value; + break; + } + case "releaseName": { + obj["release_name"] = value; + break; + } + case "resourcePrefix": { + obj["resource_prefix"] = value; + break; + } + case "untardir": { + obj["untar_dir"] = value; + break; + } + default: { + obj[key] = value; + } + } + } + } + return obj + } + } + + const jsonOpts = JSON.stringify(blob) + + // Rather than using the default provider for the following invoke call, use the version specified + // in package.json. + let invokeOpts: pulumi.InvokeOptions = { async: true, version: getVersion() }; + + const promise = pulumi.runtime.invoke("kubernetes:helm:template", {jsonOpts}, invokeOpts); + return pulumi.output(promise).apply<{[key: string]: pulumi.CustomResource}>(p => yaml.parse( + { + resourcePrefix: config.resourcePrefix, + objs: p.result, + transformations: config.transformations || [], + }, + { ...opts, parent: this } + )); + } +} + +interface BaseChartOpts { + /** + * The optional kubernetes api versions used for Capabilities.APIVersions. + */ + apiVersions?: pulumi.Input[]>; + /** + * The optional namespace to install chart resources into. + */ + namespace?: pulumi.Input; + /** + * Overrides for chart values. + */ + values?: pulumi.Inputs; + /** + * A set of transformations to apply to Kubernetes resource definitions before registering + * with engine. + */ + transformations?: ((o: any, opts: pulumi.CustomResourceOptions) => void)[]; + /** + * An optional prefix for the auto-generated resource names. + * Example: A resource created with resourcePrefix="foo" would produce a resource named "foo-resourceName". + */ + resourcePrefix?: string +} + +/** + * The set of arguments for constructing a Chart resource from a remote source. + */ +export interface ChartOpts extends BaseChartOpts { + /** + * The repository name of the chart to deploy. + * Example: "stable" + */ + repo?: pulumi.Input; + + /** + * The name of the chart to deploy. If [repo] is provided, this chart name will be prefixed by the repo name. + * Example: repo: "stable", chart: "nginx-ingress" -> "stable/nginx-ingress" + * Example: chart: "stable/nginx-ingress" -> "stable/nginx-ingress" + */ + chart: pulumi.Input; + + /** + * The version of the chart to deploy. If not provided, the latest version will be deployed. + */ + version?: pulumi.Input; + + /** + * Additional options to customize the fetching of the Helm chart. + */ + fetchOpts?: pulumi.Input; +} + +function isChartOpts(o: any): o is ChartOpts { + return "chart" in o; +} + +/** + * The set of arguments for constructing a Chart resource from a local source. + */ +export interface LocalChartOpts extends BaseChartOpts { + /** + * The path to the chart directory which contains the `Chart.yaml` file. + */ + path: string; +} + +function isLocalChartOpts(o: any): o is LocalChartOpts { + return "path" in o; +} + +/** + * Additional options to customize the fetching of the Helm chart. + */ +export interface FetchOpts { + /** Specific version of a chart. Without this, the latest version is fetched. */ + version?: pulumi.Input; + + /** Verify certificates of HTTPS-enabled servers using this CA bundle. */ + caFile?: pulumi.Input; + + /** Identify HTTPS client using this SSL certificate file. */ + certFile?: pulumi.Input; + + /** Identify HTTPS client using this SSL key file. */ + keyFile?: pulumi.Input; + + /** + * Location to write the chart. If this and tardir are specified, tardir is appended to this + * (default "."). + */ + destination?: pulumi.Input; + + /** Keyring containing public keys (default "/Users/alex/.gnupg/pubring.gpg"). */ + keyring?: pulumi.Input; + + /** Chart repository password. */ + password?: pulumi.Input; + + /** Chart repository url where to locate the requested chart. */ + repo?: pulumi.Input; + + /** + * If untar is specified, this flag specifies the name of the directory into which the chart is + * expanded (default "."). + */ + untardir?: pulumi.Input; + + /** Chart repository username. */ + username?: pulumi.Input; + + /** Location of your Helm config. Overrides $HELM_HOME (default "/Users/alex/.helm"). */ + home?: pulumi.Input; + + /** + * Use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is + * ignored. + */ + devel?: pulumi.Input; + + /** Fetch the provenance file, but don't perform verification. */ + prov?: pulumi.Input; + + /** If set to false, will leave the chart as a tarball after downloading. */ + untar?: pulumi.Input; + + /** Verify the package against its signature. */ + verify?: pulumi.Input; +} diff --git a/provider/pkg/provider/invoke_helm_template.go b/provider/pkg/provider/invoke_helm_template.go index 5fc6880cc3..670027bb5b 100644 --- a/provider/pkg/provider/invoke_helm_template.go +++ b/provider/pkg/provider/invoke_helm_template.go @@ -176,10 +176,8 @@ func (c *chart) template() (string, error) { Capabilities: chartutil.DefaultCapabilities, Releases: storage.Init(driver.NewMemory()), } - - if c.opts.APIVersions != nil { - cfg.Capabilities.APIVersions = c.opts.APIVersions - // TODO: add support for overriding kube version + if len(c.opts.APIVersions) > 0 { + cfg.Capabilities.APIVersions = append(cfg.Capabilities.APIVersions, c.opts.APIVersions...) } installAction := action.NewInstall(cfg) diff --git a/sdk/nodejs/helm/v2/helm.ts b/sdk/nodejs/helm/v2/helm.ts index ce08578a2e..2fc7cddd39 100644 --- a/sdk/nodejs/helm/v2/helm.ts +++ b/sdk/nodejs/helm/v2/helm.ts @@ -43,7 +43,7 @@ import * as yaml from "../../yaml/index"; * ```typescript * import * as k8s from "@pulumi/kubernetes"; * - * const nginxIngress = new k8s.helm.v3.Chart("nginx-ingress", { + * const nginxIngress = new k8s.helm.v2.Chart("nginx-ingress", { * path: "./nginx-ingress", * }); * ``` @@ -52,7 +52,7 @@ import * as yaml from "../../yaml/index"; * ```typescript * import * as k8s from "@pulumi/kubernetes"; * - * const nginxIngress = new k8s.helm.v3.Chart("nginx-ingress", { + * const nginxIngress = new k8s.helm.v2.Chart("nginx-ingress", { * chart: "nginx-ingress", * version: "1.24.4", * fetchOpts:{ @@ -65,7 +65,7 @@ import * as yaml from "../../yaml/index"; * ```typescript * import * as k8s from "@pulumi/kubernetes"; * - * const nginxIngress = new k8s.helm.v3.Chart("nginx-ingress", { + * const nginxIngress = new k8s.helm.v2.Chart("nginx-ingress", { * chart: "nginx-ingress", * version: "1.24.4", * fetchOpts:{ @@ -85,7 +85,7 @@ import * as yaml from "../../yaml/index"; * ```typescript * import * as k8s from "@pulumi/kubernetes"; * - * const nginxIngress = new k8s.helm.v3.Chart("nginx-ingress", { + * const nginxIngress = new k8s.helm.v2.Chart("nginx-ingress", { * chart: "nginx-ingress", * version: "1.24.4", * namespace: "test-namespace", @@ -99,7 +99,7 @@ import * as yaml from "../../yaml/index"; * ```typescript * import * as k8s from "@pulumi/kubernetes"; * - * const nginxIngress = new k8s.helm.v3.Chart("nginx-ingress", { + * const nginxIngress = new k8s.helm.v2.Chart("nginx-ingress", { * chart: "nginx-ingress", * version: "1.24.4", * fetchOpts:{ @@ -204,12 +204,10 @@ export class Chart extends yaml.CollectionComponentResource { const release = shell.quote([releaseName]); const values = path.quotePath(overrides.name); const apiVersionsArgs = cfg.apiVersions - ? cfg.apiVersions.length > 1 - ? `--api-versions={${cfg.apiVersions - .map(apiVersion => shell.quote([apiVersion])) - .join(',')}}` - : `--api-versions=${shell.quote(cfg.apiVersions)}` - : ''; + ? cfg.apiVersions + .map(v => `--api-versions=${v}`) + .join(" ") + : ""; const namespaceArg = cfg.namespace ? `--namespace ${shell.quote([cfg.namespace])}` : ""; diff --git a/sdk/nodejs/helm/v3/helm.ts b/sdk/nodejs/helm/v3/helm.ts index ce08578a2e..140995314b 100644 --- a/sdk/nodejs/helm/v3/helm.ts +++ b/sdk/nodejs/helm/v3/helm.ts @@ -16,11 +16,6 @@ // *** Do not edit by hand unless you're certain you know what you are doing! *** import * as pulumi from "@pulumi/pulumi"; -import { execSync } from "child_process"; -import * as fs from "fs"; -import * as nodepath from "path"; -import * as shell from "shell-quote"; -import * as tmp from "tmp"; import * as path from "../../path"; import { getVersion } from "../../utilities"; import * as yaml from "../../yaml/index"; @@ -146,137 +141,86 @@ export class Chart extends yaml.CollectionComponentResource { if (config.resourcePrefix !== undefined) { releaseName = `${config.resourcePrefix}-${releaseName}` } - super("kubernetes:helm.sh/v2:Chart", releaseName, config, opts); + const aliasOpts: pulumi.ComponentResourceOptions = {...opts, aliases: [{type:"kubernetes:helm.sh/v2:Chart"}]} + super("kubernetes:helm.sh/v3:Chart", releaseName, config, aliasOpts); const allConfig = pulumi.output(config); - const configDeps = Array.from(>(allConfig).resources()); (allConfig).isKnown.then((isKnown: boolean) => { if (!isKnown) { // Note that this can only happen during a preview. - pulumi.log.info("[Can't preview] all chart values must be known ahead of time to generate an accurate preview.", this); + pulumi.log.info("[Can't preview] all chart values must be known ahead of time to generate an " + + "accurate preview.", this); } }); this.resources = allConfig.apply(cfg => { - // Create temporary directories and files to hold chart data and override values. - const overrides = tmp.fileSync({ postfix: ".yaml" }); - const chartDir = tmp.dirSync({ unsafeCleanup: true }); - - try { - let chart: string; - let defaultValues: string; - let cmd: string; - if (isChartOpts(cfg)) { - // Fetch chart. - if (cfg.repo && cfg.repo.includes("http")) { - pulumi.log.error( - "`repo` specifies the name of the Helm chart repo. Use `fetchOpts.repo` to specify a URL.", this); - } - const chartToFetch = cfg.repo ? `${cfg.repo}/${cfg.chart}` : cfg.chart; - const fetchOpts = Object.assign({}, cfg.fetchOpts, { - destination: chartDir.name, - version: cfg.version - }); - fetch(chartToFetch, fetchOpts); - const fetchedChartName = fs.readdirSync(chartDir.name).sort()[0]; - chart = path.quotePath(nodepath.join(chartDir.name, fetchedChartName)); - defaultValues = path.quotePath( - nodepath.join(chartDir.name, fetchedChartName, "values.yaml") - ); - } else { - chart = cfg.path; - defaultValues = path.quotePath(nodepath.join(chart, "values.yaml")); - } - - // Write overrides file. - const data = JSON.stringify(cfg.values || {}, undefined, " "); - fs.writeFileSync(overrides.name, data); - - // Does not require Tiller. From the `helm template` documentation: - // - // > Render chart templates locally and display the output. - // > - // > This does not require Tiller. However, any values that would normally be - // > looked up or retrieved in-cluster will be faked locally. Additionally, none - // > of the server-side testing of chart validity (e.g. whether an API is supported) - // > is done. - const release = shell.quote([releaseName]); - const values = path.quotePath(overrides.name); - const apiVersionsArgs = cfg.apiVersions - ? cfg.apiVersions.length > 1 - ? `--api-versions={${cfg.apiVersions - .map(apiVersion => shell.quote([apiVersion])) - .join(',')}}` - : `--api-versions=${shell.quote(cfg.apiVersions)}` - : ''; - const namespaceArg = cfg.namespace - ? `--namespace ${shell.quote([cfg.namespace])}` - : ""; - - // Check the helm version - v2 or v3 - let helmVerCmd = `helm version --short || true`; - var helmVer; - try { - helmVer = execSync( - helmVerCmd, - { - stdio: ['pipe', 'pipe', 'ignore'], // Suppress tiller version error - }, - ).toString(); - } catch (e) { - helmVer = e.stdout.toString(); - } + return this.parseChart(cfg, releaseName, opts) + }); + } - cmd = `helm template ${chart} --name-template ${release} --values ${defaultValues} --values ${values} ${apiVersionsArgs} ${namespaceArg}`; - // Helm v2 returns version like this: - // Client: v2.16.7+g5f2584f - // Helm v3 returns a version like this: - // v3.1.2+gd878d4d - // --include-crds is available in helm v3.1+ so check for a regex matching that version - if (RegExp('^v3\.[1-9]').test(helmVer)) { - cmd += ` --include-crds` + parseChart(config: ChartOpts | LocalChartOpts, releaseName: string, opts?: pulumi.ComponentResourceOptions) { + const blob = { + ...config, + releaseName, + + toJSON() { + let obj: any = {}; + for (const [key, value] of Object.entries(this)) { + if (value) { + switch(key) { + case "apiVersions": { + obj["api_versions"] = value; + break; + } + case "caFile": { + obj["ca_file"] = value; + break; + } + case "certFile": { + obj["cert_file"] = value; + break; + } + case "fetchOpts": { + obj["fetch_opts"] = value; + break; + } + case "releaseName": { + obj["release_name"] = value; + break; + } + case "resourcePrefix": { + obj["resource_prefix"] = value; + break; + } + case "untardir": { + obj["untar_dir"] = value; + break; + } + default: { + obj[key] = value; + } + } + } } - - const yamlStream = execSync( - cmd, - { - env: {...process.env}, - maxBuffer: 512 * 1024 * 1024 // 512 MB - }, - ).toString(); - return this.parseTemplate( - yamlStream, cfg.transformations, cfg.resourcePrefix, configDeps, cfg.namespace); - } catch (e) { - // Shed stack trace, only emit the error. - throw new pulumi.RunError(e.toString()); - } finally { - // Clean up temporary files and directories. - chartDir.removeCallback(); - overrides.removeCallback(); + return obj } - }); - } + } + + const jsonOpts = JSON.stringify(blob) - parseTemplate( - text: string, - transformations: ((o: any, opts: pulumi.CustomResourceOptions) => void)[] | undefined, - resourcePrefix: string | undefined, - dependsOn: pulumi.Resource[], - defaultNamespace: string | undefined, - ): pulumi.Output<{ [key: string]: pulumi.CustomResource }> { // Rather than using the default provider for the following invoke call, use the version specified // in package.json. let invokeOpts: pulumi.InvokeOptions = { async: true, version: getVersion() }; - const promise = pulumi.runtime.invoke("kubernetes:yaml:decode", {text, defaultNamespace}, invokeOpts); + const promise = pulumi.runtime.invoke("kubernetes:helm:template", {jsonOpts}, invokeOpts); return pulumi.output(promise).apply<{[key: string]: pulumi.CustomResource}>(p => yaml.parse( { - resourcePrefix: resourcePrefix, + resourcePrefix: config.resourcePrefix, objs: p.result, - transformations: transformations || [], + transformations: config.transformations || [], }, - { parent: this, dependsOn: dependsOn } + { ...opts, parent: this } )); } } @@ -410,66 +354,3 @@ export interface FetchOpts { /** Verify the package against its signature. */ verify?: pulumi.Input; } - -interface ResolvedFetchOpts { - version?: string; - caFile?: string; - certFile?: string; - keyFile?: string; - destination?: string; - keyring?: string; - password?: string; - repo?: string; - untardir?: string; - username?: string; - home?: string; - devel?: boolean; - prov?: boolean; - untar?: boolean; - verify?: boolean; -} - -/** - * Retrieve a package from a package repository, and download it locally. - * - * This is useful for fetching packages to inspect, modify, or repackage. It can also be used to - * perform cryptographic verification of a chart without installing the chart. - * - * There are options for unpacking the chart after download. This will create a directory for the - * chart and uncompress into that directory. - * - * If the `verify` option is specified, the requested chart MUST have a provenance file, and MUST - * pass the verification process. Failure in any part of this will result in an error, and the chart - * will not be saved locally. - * - * @ignore - */ -export function fetch(chart: string, opts?: ResolvedFetchOpts) { - const flags: string[] = []; - const env: { [key: string]: string | undefined } = {...process.env}; - if (opts !== undefined) { - // Untar by default. - if(opts.untar !== false) { flags.push(`--untar`); } - - // Helm v3 removed the `--home` flag, so we must use an env var instead. - if (opts.home) { env['HELM_HOME'] = path.quotePath(opts.home) } - - // For arguments that are not paths to files, it is sufficient to use shell.quote to quote the arguments. - // However, for arguments that are actual paths to files we use path.quotePath (note that path here is - // not the node path builtin module). This ensures proper escaping of paths on Windows. - if (opts.version !== undefined) { flags.push(`--version ${shell.quote([opts.version])}`); } - if (opts.caFile !== undefined) { flags.push(`--ca-file ${path.quotePath(opts.caFile)}`); } - if (opts.certFile !== undefined) { flags.push(`--cert-file ${path.quotePath(opts.certFile)}`); } - if (opts.keyFile !== undefined) { flags.push(`--key-file ${path.quotePath(opts.keyFile)}`); } - if (opts.destination !== undefined) { flags.push(`--destination ${path.quotePath(opts.destination)}`); } - if (opts.keyring !== undefined) { flags.push(`--keyring ${path.quotePath(opts.keyring)}`); } - if (opts.password !== undefined) { flags.push(`--password ${shell.quote([opts.password])}`); } - if (opts.repo !== undefined) { flags.push(`--repo ${path.quotePath(opts.repo)}`); } - if (opts.untardir !== undefined) { flags.push(`--untardir ${path.quotePath(opts.untardir)}`); } - if (opts.username !== undefined) { flags.push(`--username ${shell.quote([opts.username])}`); } - if (opts.devel === true) { flags.push(`--devel`); } - if (opts.prov === true) { flags.push(`--prov`); } - if (opts.verify === true) { flags.push(`--verify`); } - } - execSync(`helm fetch ${shell.quote([chart])} ${flags.join(" ")}`, { env }); -} diff --git a/tests/sdk/nodejs/examples/examples_test.go b/tests/sdk/nodejs/examples/examples_test.go index 6272d5205a..f6a09ccb1c 100644 --- a/tests/sdk/nodejs/examples/examples_test.go +++ b/tests/sdk/nodejs/examples/examples_test.go @@ -17,7 +17,7 @@ package examples import ( "fmt" "os" - "path" + "path/filepath" "sort" "testing" @@ -32,7 +32,7 @@ import ( func TestAccMinimal(t *testing.T) { test := getBaseOptions(t). With(integration.ProgramTestOptions{ - Dir: path.Join(getCwd(t), "minimal"), + Dir: filepath.Join(getCwd(t), "minimal"), }) integration.ProgramTest(t, &test) @@ -42,7 +42,7 @@ func TestAccGuestbook(t *testing.T) { skipIfShort(t) test := getBaseOptions(t). With(integration.ProgramTestOptions{ - Dir: path.Join(getCwd(t), "guestbook"), + Dir: filepath.Join(getCwd(t), "guestbook"), ExtraRuntimeValidation: func( t *testing.T, stackInfo integration.RuntimeValidationStackInfo, ) { @@ -132,7 +132,7 @@ func TestAccHelm(t *testing.T) { skipIfShort(t) test := getBaseOptions(t). With(integration.ProgramTestOptions{ - Dir: path.Join(getCwd(t), "helm"), + Dir: filepath.Join(getCwd(t), "helm", "step1"), SkipRefresh: true, Verbose: true, ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { @@ -149,6 +149,13 @@ func TestAccHelm(t *testing.T) { } } }, + EditDirs: []integration.EditDir{ + { + Dir: filepath.Join(getCwd(t), "helm", "step2"), + Additive: true, + ExpectNoChanges: true, + }, + }, }) integration.ProgramTest(t, &test) @@ -158,13 +165,20 @@ func TestAccHelmApiVersions(t *testing.T) { skipIfShort(t) test := getBaseOptions(t). With(integration.ProgramTestOptions{ - Dir: path.Join(getCwd(t), "helm-api-versions"), + Dir: filepath.Join(getCwd(t), "helm-api-versions", "step1"), SkipRefresh: true, ExtraRuntimeValidation: func( t *testing.T, stackInfo integration.RuntimeValidationStackInfo, ) { assert.NotNil(t, stackInfo.Deployment) - assert.Equal(t, 6, len(stackInfo.Deployment.Resources)) + assert.Equal(t, 7, len(stackInfo.Deployment.Resources)) + }, + EditDirs: []integration.EditDir{ + { + Dir: filepath.Join(getCwd(t), "helm-api-versions", "step2"), + Additive: true, + ExpectNoChanges: true, + }, }, }) @@ -175,7 +189,7 @@ func TestAccHelmLocal(t *testing.T) { skipIfShort(t) test := getBaseOptions(t). With(integration.ProgramTestOptions{ - Dir: path.Join(getCwd(t), "helm-local"), + Dir: filepath.Join(getCwd(t), "helm-local", "step1"), SkipRefresh: true, // Deployment controller changes object out-of-band. ExtraRuntimeValidation: func( t *testing.T, stackInfo integration.RuntimeValidationStackInfo, @@ -183,6 +197,13 @@ func TestAccHelmLocal(t *testing.T) { assert.NotNil(t, stackInfo.Deployment) assert.Equal(t, 15, len(stackInfo.Deployment.Resources)) }, + EditDirs: []integration.EditDir{ + { + Dir: filepath.Join(getCwd(t), "helm-local", "step2"), + Additive: true, + ExpectNoChanges: true, + }, + }, }) integration.ProgramTest(t, &test) @@ -192,7 +213,7 @@ func TestAccPrometheusOperator(t *testing.T) { skipIfShort(t) test := getBaseOptions(t). With(integration.ProgramTestOptions{ - Dir: path.Join(getCwd(t), "prometheus-operator"), + Dir: filepath.Join(getCwd(t), "prometheus-operator"), SkipRefresh: true, ExtraRuntimeValidation: func( t *testing.T, stackInfo integration.RuntimeValidationStackInfo, @@ -202,7 +223,7 @@ func TestAccPrometheusOperator(t *testing.T) { }, EditDirs: []integration.EditDir{ { - Dir: path.Join(getCwd(t), "prometheus-operator", "step1"), + Dir: filepath.Join(getCwd(t), "prometheus-operator", "step1"), Additive: true, ExtraRuntimeValidation: func( t *testing.T, stackInfo integration.RuntimeValidationStackInfo, @@ -221,7 +242,7 @@ func TestAccMariadb(t *testing.T) { skipIfShort(t) test := getBaseOptions(t). With(integration.ProgramTestOptions{ - Dir: path.Join(getCwd(t), "mariadb"), + Dir: filepath.Join(getCwd(t), "mariadb"), }) integration.ProgramTest(t, &test) @@ -231,7 +252,7 @@ func TestAccProvider(t *testing.T) { skipIfShort(t) test := getBaseOptions(t). With(integration.ProgramTestOptions{ - Dir: path.Join(getCwd(t), "provider"), + Dir: filepath.Join(getCwd(t), "provider"), }) integration.ProgramTest(t, &test) diff --git a/tests/sdk/nodejs/examples/helm-api-versions/.gitignore b/tests/sdk/nodejs/examples/helm-api-versions/step1/.gitignore similarity index 100% rename from tests/sdk/nodejs/examples/helm-api-versions/.gitignore rename to tests/sdk/nodejs/examples/helm-api-versions/step1/.gitignore diff --git a/tests/sdk/nodejs/examples/helm-api-versions/Pulumi.yaml b/tests/sdk/nodejs/examples/helm-api-versions/step1/Pulumi.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-api-versions/Pulumi.yaml rename to tests/sdk/nodejs/examples/helm-api-versions/step1/Pulumi.yaml diff --git a/tests/sdk/nodejs/examples/helm-api-versions/helm-api-versions/.helmignore b/tests/sdk/nodejs/examples/helm-api-versions/step1/helm-api-versions/.helmignore similarity index 100% rename from tests/sdk/nodejs/examples/helm-api-versions/helm-api-versions/.helmignore rename to tests/sdk/nodejs/examples/helm-api-versions/step1/helm-api-versions/.helmignore diff --git a/tests/sdk/nodejs/examples/helm-api-versions/helm-api-versions/Chart.yaml b/tests/sdk/nodejs/examples/helm-api-versions/step1/helm-api-versions/Chart.yaml similarity index 87% rename from tests/sdk/nodejs/examples/helm-api-versions/helm-api-versions/Chart.yaml rename to tests/sdk/nodejs/examples/helm-api-versions/step1/helm-api-versions/Chart.yaml index f76f922aa7..73650a05a4 100755 --- a/tests/sdk/nodejs/examples/helm-api-versions/helm-api-versions/Chart.yaml +++ b/tests/sdk/nodejs/examples/helm-api-versions/step1/helm-api-versions/Chart.yaml @@ -1,3 +1,4 @@ +apiVersion: v2 deprecated: true description: Chart to test .Capabilities.APIVersions name: apiversions-test diff --git a/tests/sdk/nodejs/examples/helm-api-versions/helm-api-versions/templates/test-pod.yaml b/tests/sdk/nodejs/examples/helm-api-versions/step1/helm-api-versions/templates/test-pod.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-api-versions/helm-api-versions/templates/test-pod.yaml rename to tests/sdk/nodejs/examples/helm-api-versions/step1/helm-api-versions/templates/test-pod.yaml diff --git a/tests/sdk/nodejs/examples/helm-api-versions/helm-api-versions/values.yaml b/tests/sdk/nodejs/examples/helm-api-versions/step1/helm-api-versions/values.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-api-versions/helm-api-versions/values.yaml rename to tests/sdk/nodejs/examples/helm-api-versions/step1/helm-api-versions/values.yaml diff --git a/tests/sdk/nodejs/examples/helm-api-versions/helm-single-api-version/.helmignore b/tests/sdk/nodejs/examples/helm-api-versions/step1/helm-single-api-version/.helmignore similarity index 100% rename from tests/sdk/nodejs/examples/helm-api-versions/helm-single-api-version/.helmignore rename to tests/sdk/nodejs/examples/helm-api-versions/step1/helm-single-api-version/.helmignore diff --git a/tests/sdk/nodejs/examples/helm-api-versions/helm-single-api-version/Chart.yaml b/tests/sdk/nodejs/examples/helm-api-versions/step1/helm-single-api-version/Chart.yaml similarity index 87% rename from tests/sdk/nodejs/examples/helm-api-versions/helm-single-api-version/Chart.yaml rename to tests/sdk/nodejs/examples/helm-api-versions/step1/helm-single-api-version/Chart.yaml index f76f922aa7..73650a05a4 100755 --- a/tests/sdk/nodejs/examples/helm-api-versions/helm-single-api-version/Chart.yaml +++ b/tests/sdk/nodejs/examples/helm-api-versions/step1/helm-single-api-version/Chart.yaml @@ -1,3 +1,4 @@ +apiVersion: v2 deprecated: true description: Chart to test .Capabilities.APIVersions name: apiversions-test diff --git a/tests/sdk/nodejs/examples/helm-api-versions/helm-single-api-version/templates/test-pod.yaml b/tests/sdk/nodejs/examples/helm-api-versions/step1/helm-single-api-version/templates/test-pod.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-api-versions/helm-single-api-version/templates/test-pod.yaml rename to tests/sdk/nodejs/examples/helm-api-versions/step1/helm-single-api-version/templates/test-pod.yaml diff --git a/tests/sdk/nodejs/examples/helm-api-versions/helm-single-api-version/values.yaml b/tests/sdk/nodejs/examples/helm-api-versions/step1/helm-single-api-version/values.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-api-versions/helm-single-api-version/values.yaml rename to tests/sdk/nodejs/examples/helm-api-versions/step1/helm-single-api-version/values.yaml diff --git a/tests/sdk/nodejs/examples/helm-api-versions/index.ts b/tests/sdk/nodejs/examples/helm-api-versions/step1/index.ts similarity index 100% rename from tests/sdk/nodejs/examples/helm-api-versions/index.ts rename to tests/sdk/nodejs/examples/helm-api-versions/step1/index.ts diff --git a/tests/sdk/nodejs/examples/helm-api-versions/package.json b/tests/sdk/nodejs/examples/helm-api-versions/step1/package.json similarity index 100% rename from tests/sdk/nodejs/examples/helm-api-versions/package.json rename to tests/sdk/nodejs/examples/helm-api-versions/step1/package.json diff --git a/tests/sdk/nodejs/examples/helm-api-versions/tsconfig.json b/tests/sdk/nodejs/examples/helm-api-versions/step1/tsconfig.json similarity index 100% rename from tests/sdk/nodejs/examples/helm-api-versions/tsconfig.json rename to tests/sdk/nodejs/examples/helm-api-versions/step1/tsconfig.json diff --git a/tests/sdk/nodejs/examples/helm-api-versions/step2/index.ts b/tests/sdk/nodejs/examples/helm-api-versions/step2/index.ts new file mode 100644 index 0000000000..81bb44cc63 --- /dev/null +++ b/tests/sdk/nodejs/examples/helm-api-versions/step2/index.ts @@ -0,0 +1,15 @@ +import * as k8s from "@pulumi/kubernetes"; + +const namespace = new k8s.core.v1.Namespace("test"); + +new k8s.helm.v3.Chart("api-versions", { + apiVersions: ["foo", "bar"], + namespace: namespace.metadata.name, + path: "helm-api-versions", +}); + +new k8s.helm.v3.Chart("single-api-version", { + apiVersions: ["foo"], + namespace: namespace.metadata.name, + path: "helm-single-api-version", +}); diff --git a/tests/sdk/nodejs/examples/helm-local/.gitignore b/tests/sdk/nodejs/examples/helm-local/step1/.gitignore similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/.gitignore rename to tests/sdk/nodejs/examples/helm-local/step1/.gitignore diff --git a/tests/sdk/nodejs/examples/helm-local/Pulumi.yaml b/tests/sdk/nodejs/examples/helm-local/step1/Pulumi.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/Pulumi.yaml rename to tests/sdk/nodejs/examples/helm-local/step1/Pulumi.yaml diff --git a/tests/sdk/nodejs/examples/helm-local/index.ts b/tests/sdk/nodejs/examples/helm-local/step1/index.ts similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/index.ts rename to tests/sdk/nodejs/examples/helm-local/step1/index.ts diff --git a/tests/sdk/nodejs/examples/helm-local/nginx-lego/.helmignore b/tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/.helmignore similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/nginx-lego/.helmignore rename to tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/.helmignore diff --git a/tests/sdk/nodejs/examples/helm-local/nginx-lego/Chart.yaml b/tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/Chart.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/nginx-lego/Chart.yaml rename to tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/Chart.yaml diff --git a/tests/sdk/nodejs/examples/helm-local/nginx-lego/README.md b/tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/README.md similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/nginx-lego/README.md rename to tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/README.md diff --git a/tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/NOTES.txt b/tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/NOTES.txt similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/NOTES.txt rename to tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/NOTES.txt diff --git a/tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/_helpers.tpl b/tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/_helpers.tpl similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/_helpers.tpl rename to tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/_helpers.tpl diff --git a/tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/default-deployment.yaml b/tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/default-deployment.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/default-deployment.yaml rename to tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/default-deployment.yaml diff --git a/tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/default-service.yaml b/tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/default-service.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/default-service.yaml rename to tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/default-service.yaml diff --git a/tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/lego-configmap.yaml b/tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/lego-configmap.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/lego-configmap.yaml rename to tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/lego-configmap.yaml diff --git a/tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/lego-deployment.yaml b/tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/lego-deployment.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/lego-deployment.yaml rename to tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/lego-deployment.yaml diff --git a/tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/nginx-configmap.yaml b/tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/nginx-configmap.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/nginx-configmap.yaml rename to tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/nginx-configmap.yaml diff --git a/tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/nginx-deployment.yaml b/tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/nginx-deployment.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/nginx-deployment.yaml rename to tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/nginx-deployment.yaml diff --git a/tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/nginx-monitoring.yaml b/tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/nginx-monitoring.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/nginx-monitoring.yaml rename to tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/nginx-monitoring.yaml diff --git a/tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/nginx-service.yaml b/tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/nginx-service.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/nginx-lego/templates/nginx-service.yaml rename to tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/templates/nginx-service.yaml diff --git a/tests/sdk/nodejs/examples/helm-local/nginx-lego/values.yaml b/tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/values.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/nginx-lego/values.yaml rename to tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/values.yaml diff --git a/tests/sdk/nodejs/examples/helm-local/package.json b/tests/sdk/nodejs/examples/helm-local/step1/package.json similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/package.json rename to tests/sdk/nodejs/examples/helm-local/step1/package.json diff --git a/tests/sdk/nodejs/examples/helm-local/tsconfig.json b/tests/sdk/nodejs/examples/helm-local/step1/tsconfig.json similarity index 100% rename from tests/sdk/nodejs/examples/helm-local/tsconfig.json rename to tests/sdk/nodejs/examples/helm-local/step1/tsconfig.json diff --git a/tests/sdk/nodejs/examples/helm-local/step2/index.ts b/tests/sdk/nodejs/examples/helm-local/step2/index.ts new file mode 100644 index 0000000000..9227cc5bb5 --- /dev/null +++ b/tests/sdk/nodejs/examples/helm-local/step2/index.ts @@ -0,0 +1,60 @@ +// Copyright 2016-2019, Pulumi Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import * as k8s from "@pulumi/kubernetes"; +import * as pulumi from "@pulumi/pulumi"; + +const namespace = new k8s.core.v1.Namespace("test"); +const namespaceName = namespace.metadata.name; + +function chart(resourcePrefix?: string): k8s.helm.v3.Chart { + return new k8s.helm.v3.Chart("nginx-lego", { + // Represents chart `stable/nginx-lego@v0.3.1`. + path: "nginx-lego", + version: "0.3.1", + namespace: namespaceName, + resourcePrefix: resourcePrefix, + values: { + // Override for the Chart's `values.yml` file. Use `null` to zero out resource requests so it + // can be scheduled on our (wimpy) CI cluster. (Setting these values to `null` is the "normal" + // way to delete values.) + nginx: {resources: null}, + default: {resources: null}, + lego: {resources: null} + }, + transformations: [ + // Make every service private to the cluster, i.e., turn all services into ClusterIP instead of + // LoadBalancer. + (obj: any) => { + if (obj.kind == "Service" && obj.apiVersion == "v1") { + if (obj.spec && obj.spec.type && obj.spec.type == "LoadBalancer") { + obj.spec.type = "ClusterIP"; + } + } + }, + ] + }); +} + +// Create the first instance of the Chart. +const nginx = chart(); + +// Export the (cluster-private) IP address of the Guestbook frontend. +const frontendServiceSpec = pulumi.all([namespaceName, nginx]).apply(([nsName, nginx]) => + nginx.getResourceProperty("v1/Service", nsName, "nginx-lego-nginx-lego", "spec")); +export const frontendServiceIP = frontendServiceSpec.clusterIP; + +// Deploy a duplicate chart with a different resource prefix to verify that multiple instances of the Chart +// can be managed in the same stack. +chart("dup"); diff --git a/tests/sdk/nodejs/examples/helm/.gitignore b/tests/sdk/nodejs/examples/helm/step1/.gitignore similarity index 100% rename from tests/sdk/nodejs/examples/helm/.gitignore rename to tests/sdk/nodejs/examples/helm/step1/.gitignore diff --git a/tests/sdk/nodejs/examples/helm/Pulumi.yaml b/tests/sdk/nodejs/examples/helm/step1/Pulumi.yaml similarity index 100% rename from tests/sdk/nodejs/examples/helm/Pulumi.yaml rename to tests/sdk/nodejs/examples/helm/step1/Pulumi.yaml diff --git a/tests/sdk/nodejs/examples/helm/index.ts b/tests/sdk/nodejs/examples/helm/step1/index.ts similarity index 98% rename from tests/sdk/nodejs/examples/helm/index.ts rename to tests/sdk/nodejs/examples/helm/step1/index.ts index 1487e9f539..94be5f29f1 100644 --- a/tests/sdk/nodejs/examples/helm/index.ts +++ b/tests/sdk/nodejs/examples/helm/step1/index.ts @@ -19,7 +19,7 @@ import * as pulumi from "@pulumi/pulumi"; const namespace = new k8s.core.v1.Namespace("test"); const namespaceName = namespace.metadata.name; -const nginx = new k8s.helm.v3.Chart("simple-nginx", { +const nginx = new k8s.helm.v2.Chart("simple-nginx", { // Represents chart `stable/nginx-lego@v0.3.1`. repo: "stable", chart: "nginx-lego", diff --git a/tests/sdk/nodejs/examples/helm/package.json b/tests/sdk/nodejs/examples/helm/step1/package.json similarity index 100% rename from tests/sdk/nodejs/examples/helm/package.json rename to tests/sdk/nodejs/examples/helm/step1/package.json diff --git a/tests/sdk/nodejs/examples/helm/tsconfig.json b/tests/sdk/nodejs/examples/helm/step1/tsconfig.json similarity index 100% rename from tests/sdk/nodejs/examples/helm/tsconfig.json rename to tests/sdk/nodejs/examples/helm/step1/tsconfig.json diff --git a/tests/sdk/nodejs/examples/helm/step2/index.ts b/tests/sdk/nodejs/examples/helm/step2/index.ts new file mode 100644 index 0000000000..f698fa6b17 --- /dev/null +++ b/tests/sdk/nodejs/examples/helm/step2/index.ts @@ -0,0 +1,80 @@ +// Copyright 2016-2019, Pulumi Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import * as k8s from "@pulumi/kubernetes"; +import * as os from "os"; +import * as pulumi from "@pulumi/pulumi"; + +const namespace = new k8s.core.v1.Namespace("test"); +const namespaceName = namespace.metadata.name; + +const nginx = new k8s.helm.v3.Chart("simple-nginx", { + // Represents chart `stable/nginx-lego@v0.3.1`. + repo: "stable", + chart: "nginx-lego", + version: "0.3.1", + namespace: namespaceName, + fetchOpts: { + home: os.homedir(), + }, + values: { + // Override for the Chart's `values.yml` file. Use `null` to zero out resource requests so it + // can be scheduled on our (wimpy) CI cluster. (Setting these values to `null` is the "normal" + // way to delete values.) + nginx: { resources: null }, + default: { resources: null }, + lego: { resources: null } + }, + transformations: [ + // Make every service private to the cluster, i.e., turn all services into ClusterIP instead of + // LoadBalancer. + (obj: any) => { + if (obj.kind == "Service" && obj.apiVersion == "v1") { + if (obj.spec && obj.spec.type && obj.spec.type == "LoadBalancer") { + obj.spec.type = "ClusterIP"; + } + } + }, + (obj: any, opts: pulumi.CustomResourceOptions) => { + if (obj.kind == "Service" && obj.apiVersion == "v1") { + opts.additionalSecretOutputs = ["status"]; + } + } + ] +}); + +// Export the (cluster-private) IP address of the Guestbook frontend. +const frontendServiceSpec = pulumi.all([namespaceName, nginx]).apply(([nsName, nginx]) => + nginx.getResourceProperty("v1/Service", nsName, "simple-nginx-nginx-lego", "spec")); +export const frontendServiceIP = frontendServiceSpec.clusterIP; + +// Test a variety of other inputs on a chart that creates no resources. +const empty1 = new k8s.helm.v3.Chart("empty1", { + chart: "https://kubernetes-charts-incubator.storage.googleapis.com/raw-0.1.0.tgz", +}); + +const empty2 = new k8s.helm.v3.Chart("empty2", { + chart: "raw", + version: "0.1.0", + fetchOpts: { + repo: "https://kubernetes-charts-incubator.storage.googleapis.com/", + }, +}); + +const empty3 = new k8s.helm.v3.Chart("empty3", { + chart: "raw", + fetchOpts: { + repo: "https://kubernetes-charts-incubator.storage.googleapis.com/", + }, +});