Skip to content

Commit

Permalink
[helm/v3] Pass provider options to helm invokes (#1919)
Browse files Browse the repository at this point in the history
* Add support for Go, python and type script

* Fix python

* Fix go

* Add nodejs test

* Changelog
  • Loading branch information
viveklak committed Mar 30, 2022
1 parent a1d3466 commit 01f18f4
Show file tree
Hide file tree
Showing 12 changed files with 157 additions and 43 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
## Unreleased
(None)
- Pass provider options to helm invokes in Python, Go and TS (https://github.com/pulumi/pulumi-kubernetes/pull/1919)

## 3.17.0 (March 14, 2022)
- Make ConfigMaps mutable unless marked explicitly (enabled with provider config option) (https://github.com/pulumi/pulumi-kubernetes/pull/1926)
Expand Down
32 changes: 20 additions & 12 deletions provider/pkg/gen/_go-templates/helm/v3/chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,13 @@ func NewChart(ctx *pulumi.Context,
Type: pulumi.String("kubernetes:helm.sh/v2:Chart"),
},
})

var resourceOrInvokeOptions []pulumi.ResourceOrInvokeOption
for _, o := range opts {
if asResOrInv, ok := o.(pulumi.ResourceOrInvokeOption); ok {
resourceOrInvokeOptions = append(resourceOrInvokeOptions, asResOrInv)
}
}
opts = append(opts, aliases)
err := ctx.RegisterComponentResource("kubernetes:helm.sh/v3:Chart", name, chart, opts...)
if err != nil {
Expand All @@ -239,8 +246,9 @@ func NewChart(ctx *pulumi.Context,
name = args.ResourcePrefix + "-" + name
}

resourceOrInvokeOptions = append(resourceOrInvokeOptions, pulumi.Parent(chart))
resources := args.ToChartArgsOutput().ApplyT(func(args chartArgs) (map[string]pulumi.Resource, error) {
return parseChart(ctx, name, args, pulumi.Parent(chart))
return parseChart(ctx, name, args, resourceOrInvokeOptions...)
})
chart.Resources = resources

Expand All @@ -264,7 +272,7 @@ func NewChart(ctx *pulumi.Context,
return chart, nil
}

func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi.ResourceOption,
func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi.ResourceOrInvokeOption,
) (map[string]pulumi.Resource, error) {
type jsonOptsArgs struct {
chartArgs
Expand All @@ -281,7 +289,13 @@ func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi
return nil, err
}

objs, err := helmTemplate(ctx, string(b), opts...)
var invokeOpts []pulumi.InvokeOption
var resourceOpts []pulumi.ResourceOption
for _, o := range opts {
invokeOpts = append(invokeOpts, o)
resourceOpts = append(resourceOpts, o)
}
objs, err := helmTemplate(ctx, string(b), invokeOpts...)
if err != nil {
return nil, err
}
Expand All @@ -291,7 +305,7 @@ func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi
transformations = yaml.AddSkipAwaitTransformation(transformations)
}

resources, err := yaml.ParseYamlObjects(ctx, objs, transformations, args.ResourcePrefix, opts...)
resources, err := yaml.ParseYamlObjects(ctx, objs, transformations, args.ResourcePrefix, resourceOpts...)
if err != nil {
return nil, err
}
Expand All @@ -300,22 +314,16 @@ func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi

// helmTemplate invokes the function to fetch and template a Helm Chart and decompose it into object structures.
func helmTemplate(
ctx *pulumi.Context, jsonOpts string, opts ...pulumi.ResourceOption,
ctx *pulumi.Context, jsonOpts string, opts ...pulumi.InvokeOption,
) ([]map[string]interface{}, error) {
args := struct {
JsonOpts string `pulumi:"jsonOpts"`
}{JsonOpts: jsonOpts}
var ret struct {
Result []map[string]interface{} `pulumi:"result"`
}
invokeOptions := []pulumi.InvokeOption{}
for _, opt := range opts {
if opt, ok := opt.(pulumi.InvokeOption); ok {
invokeOptions = append(invokeOptions, opt)
}
}

if err := ctx.Invoke("kubernetes:helm:template", &args, &ret, invokeOptions...); err != nil {
if err := ctx.Invoke("kubernetes:helm:template", &args, &ret, opts...); err != nil {
return nil, errors.Wrap(err, "failed to invoke helm template")
}
return ret.Result, nil
Expand Down
21 changes: 13 additions & 8 deletions provider/pkg/gen/nodejs-templates/helm/v3/helm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import * as pulumi from "@pulumi/pulumi";
import * as path from "../../path";
import { getVersion } from "../../utilities";
import {getVersion} from "../../utilities";
import * as yaml from "../../yaml/index";

/**
Expand Down Expand Up @@ -141,7 +141,7 @@ export class Chart extends yaml.CollectionComponentResource {
if (config.resourcePrefix !== undefined) {
releaseName = `${config.resourcePrefix}-${releaseName}`
}
const aliasOpts: pulumi.ComponentResourceOptions = {...opts, aliases: [{type:"kubernetes:helm.sh/v2:Chart"}]}
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);
Expand All @@ -155,13 +155,13 @@ export class Chart extends yaml.CollectionComponentResource {
});

this.resources = allConfig.apply(cfg => {
return this.parseChart(cfg, releaseName)
return this.parseChart(cfg, releaseName, opts);
});

this.ready = this.resources.apply(m => Object.values(m));
}

parseChart(config: ChartOpts | LocalChartOpts, releaseName: string) {
parseChart(config: ChartOpts | LocalChartOpts, releaseName: string, opts?: pulumi.ComponentResourceOptions) {
const blob = {
...config,
releaseName,
Expand All @@ -170,7 +170,7 @@ export class Chart extends yaml.CollectionComponentResource {
let obj: any = {};
for (const [key, value] of Object.entries(this)) {
if (value) {
switch(key) {
switch (key) {
case "apiVersions": {
obj["api_versions"] = value;
break;
Expand Down Expand Up @@ -226,16 +226,21 @@ export class Chart extends yaml.CollectionComponentResource {

// 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() };
let invokeOpts: pulumi.InvokeOptions = {
async: true,
version: opts?.version ?? getVersion(),
provider: opts?.provider,
parent: opts?.parent
};

const promise = pulumi.runtime.invoke("kubernetes:helm:template", {jsonOpts}, invokeOpts);
return pulumi.output(promise).apply<{[key: string]: pulumi.CustomResource}>(p => yaml.parse(
return pulumi.output(promise).apply<{ [key: string]: pulumi.CustomResource }>(p => yaml.parse(
{
resourcePrefix: config.resourcePrefix,
objs: p.result,
transformations,
},
{ parent: this }
{parent: this}
));
}
}
Expand Down
4 changes: 3 additions & 1 deletion provider/pkg/gen/python-templates/helm/v3/helm.py
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,9 @@ def _parse_chart(all_config: Tuple[Union[ChartOpts, LocalChartOpts], pulumi.Reso

# Rather than using the default provider for the following invoke call, use the version specified
# in package.json.
invoke_opts = pulumi.InvokeOptions(version=_utilities.get_version())
invoke_opts = pulumi.InvokeOptions(version=_utilities.get_version() if not opts.version else opts.version,
parent=opts.parent if opts.parent else None,
provider=opts.provider if opts.provider else None)

transformations = config.transformations if config.transformations is not None else []
if config.skip_await:
Expand Down
32 changes: 20 additions & 12 deletions sdk/go/kubernetes/helm/v3/chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,13 @@ func NewChart(ctx *pulumi.Context,
Type: pulumi.String("kubernetes:helm.sh/v2:Chart"),
},
})

var resourceOrInvokeOptions []pulumi.ResourceOrInvokeOption
for _, o := range opts {
if asResOrInv, ok := o.(pulumi.ResourceOrInvokeOption); ok {
resourceOrInvokeOptions = append(resourceOrInvokeOptions, asResOrInv)
}
}
opts = append(opts, aliases)
err := ctx.RegisterComponentResource("kubernetes:helm.sh/v3:Chart", name, chart, opts...)
if err != nil {
Expand All @@ -239,8 +246,9 @@ func NewChart(ctx *pulumi.Context,
name = args.ResourcePrefix + "-" + name
}

resourceOrInvokeOptions = append(resourceOrInvokeOptions, pulumi.Parent(chart))
resources := args.ToChartArgsOutput().ApplyT(func(args chartArgs) (map[string]pulumi.Resource, error) {
return parseChart(ctx, name, args, pulumi.Parent(chart))
return parseChart(ctx, name, args, resourceOrInvokeOptions...)
})
chart.Resources = resources

Expand All @@ -264,7 +272,7 @@ func NewChart(ctx *pulumi.Context,
return chart, nil
}

func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi.ResourceOption,
func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi.ResourceOrInvokeOption,
) (map[string]pulumi.Resource, error) {
type jsonOptsArgs struct {
chartArgs
Expand All @@ -281,7 +289,13 @@ func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi
return nil, err
}

objs, err := helmTemplate(ctx, string(b), opts...)
var invokeOpts []pulumi.InvokeOption
var resourceOpts []pulumi.ResourceOption
for _, o := range opts {
invokeOpts = append(invokeOpts, o)
resourceOpts = append(resourceOpts, o)
}
objs, err := helmTemplate(ctx, string(b), invokeOpts...)
if err != nil {
return nil, err
}
Expand All @@ -291,7 +305,7 @@ func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi
transformations = yaml.AddSkipAwaitTransformation(transformations)
}

resources, err := yaml.ParseYamlObjects(ctx, objs, transformations, args.ResourcePrefix, opts...)
resources, err := yaml.ParseYamlObjects(ctx, objs, transformations, args.ResourcePrefix, resourceOpts...)
if err != nil {
return nil, err
}
Expand All @@ -300,22 +314,16 @@ func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi

// helmTemplate invokes the function to fetch and template a Helm Chart and decompose it into object structures.
func helmTemplate(
ctx *pulumi.Context, jsonOpts string, opts ...pulumi.ResourceOption,
ctx *pulumi.Context, jsonOpts string, opts ...pulumi.InvokeOption,
) ([]map[string]interface{}, error) {
args := struct {
JsonOpts string `pulumi:"jsonOpts"`
}{JsonOpts: jsonOpts}
var ret struct {
Result []map[string]interface{} `pulumi:"result"`
}
invokeOptions := []pulumi.InvokeOption{}
for _, opt := range opts {
if opt, ok := opt.(pulumi.InvokeOption); ok {
invokeOptions = append(invokeOptions, opt)
}
}

if err := ctx.Invoke("kubernetes:helm:template", &args, &ret, invokeOptions...); err != nil {
if err := ctx.Invoke("kubernetes:helm:template", &args, &ret, opts...); err != nil {
return nil, errors.Wrap(err, "failed to invoke helm template")
}
return ret.Result, nil
Expand Down
21 changes: 13 additions & 8 deletions sdk/nodejs/helm/v3/helm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import * as pulumi from "@pulumi/pulumi";
import * as path from "../../path";
import { getVersion } from "../../utilities";
import {getVersion} from "../../utilities";
import * as yaml from "../../yaml/index";

/**
Expand Down Expand Up @@ -141,7 +141,7 @@ export class Chart extends yaml.CollectionComponentResource {
if (config.resourcePrefix !== undefined) {
releaseName = `${config.resourcePrefix}-${releaseName}`
}
const aliasOpts: pulumi.ComponentResourceOptions = {...opts, aliases: [{type:"kubernetes:helm.sh/v2:Chart"}]}
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);
Expand All @@ -155,13 +155,13 @@ export class Chart extends yaml.CollectionComponentResource {
});

this.resources = allConfig.apply(cfg => {
return this.parseChart(cfg, releaseName)
return this.parseChart(cfg, releaseName, opts);
});

this.ready = this.resources.apply(m => Object.values(m));
}

parseChart(config: ChartOpts | LocalChartOpts, releaseName: string) {
parseChart(config: ChartOpts | LocalChartOpts, releaseName: string, opts?: pulumi.ComponentResourceOptions) {
const blob = {
...config,
releaseName,
Expand All @@ -170,7 +170,7 @@ export class Chart extends yaml.CollectionComponentResource {
let obj: any = {};
for (const [key, value] of Object.entries(this)) {
if (value) {
switch(key) {
switch (key) {
case "apiVersions": {
obj["api_versions"] = value;
break;
Expand Down Expand Up @@ -226,16 +226,21 @@ export class Chart extends yaml.CollectionComponentResource {

// 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() };
let invokeOpts: pulumi.InvokeOptions = {
async: true,
version: opts?.version ?? getVersion(),
provider: opts?.provider,
parent: opts?.parent
};

const promise = pulumi.runtime.invoke("kubernetes:helm:template", {jsonOpts}, invokeOpts);
return pulumi.output(promise).apply<{[key: string]: pulumi.CustomResource}>(p => yaml.parse(
return pulumi.output(promise).apply<{ [key: string]: pulumi.CustomResource }>(p => yaml.parse(
{
resourcePrefix: config.resourcePrefix,
objs: p.result,
transformations,
},
{ parent: this }
{parent: this}
));
}
}
Expand Down
4 changes: 3 additions & 1 deletion sdk/python/pulumi_kubernetes/helm/v3/helm.py
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,9 @@ def _parse_chart(all_config: Tuple[Union[ChartOpts, LocalChartOpts], pulumi.Reso

# Rather than using the default provider for the following invoke call, use the version specified
# in package.json.
invoke_opts = pulumi.InvokeOptions(version=_utilities.get_version())
invoke_opts = pulumi.InvokeOptions(version=_utilities.get_version() if not opts.version else opts.version,
parent=opts.parent if opts.parent else None,
provider=opts.provider if opts.provider else None)

transformations = config.transformations if config.transformations is not None else []
if config.skip_await:
Expand Down
14 changes: 14 additions & 0 deletions tests/sdk/nodejs/examples/examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,20 @@ func TestAccHelm(t *testing.T) {
integration.ProgramTest(t, &test)
}

func TestHelmNoDefaultProvider(t *testing.T) {
skipIfShort(t)
test := getBaseOptions(t).
With(integration.ProgramTestOptions{
Dir: filepath.Join(getCwd(t), "helm-no-default-provider"),
SkipRefresh: true,
Verbose: true,
Quick: true,
Config: map[string]string{"disable-default-providers": `["kubernetes"]`},
})

integration.ProgramTest(t, &test)
}

func TestAccHelmApiVersions(t *testing.T) {
skipIfShort(t)
test := getBaseOptions(t).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: helm-no-default-provider
runtime: nodejs
description: A minimal Kubernetes TypeScript Pulumi program
38 changes: 38 additions & 0 deletions tests/sdk/nodejs/examples/helm-no-default-provider/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2016-2022, 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'

const k8sProvider = new k8s.Provider(`k8s-provider`, {
kubeconfig: '~/.kube/config',
})

const namespace = new k8s.core.v1.Namespace("release-ns");

new k8s.helm.v3.Chart(
'wordpress',
{
fetchOpts: {
repo: 'https://charts.bitnami.com/bitnami',
},
namespace: namespace.metadata.name,
chart: 'wordpress',
values: {
"service": {"type": "ClusterIP"},
},
},
{
provider: k8sProvider,
}
)
Loading

0 comments on commit 01f18f4

Please sign in to comment.