Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[sdk/nodejs] Add a ready attribute to await Helm Charts #1364

Merged
merged 8 commits into from
Nov 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- Add support for previewing Create and Update operations for API servers that support dry-run (https://github.com/pulumi/pulumi-kubernetes/pull/1355)
- Fix panic introduced in #1355 (https://github.com/pulumi/pulumi-kubernetes/pull/1368)
- Add ready attribute to await Helm charts (https://github.com/pulumi/pulumi-kubernetes/pull/1364)
- Update Helm to v3.4.0 and client-go to v1.19.2 (https://github.com/pulumi/pulumi-kubernetes/pull/1360)
- Fix concurrency issue in Helm + .NET SDK [#1311](https://github.com/pulumi/pulumi-kubernetes/issues/1311) and [#1374](https://github.com/pulumi/pulumi-kubernetes/issues/1374)

Expand Down
2 changes: 2 additions & 0 deletions provider/pkg/gen/nodejs-templates/helm/v2/helm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ export class Chart extends yaml.CollectionComponentResource {
overrides.removeCallback();
}
});

this.ready = this.resources.apply(m => Object.values(m));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah nice, I was just gonna say the same thing ✅

}

parseTemplate(
Expand Down
2 changes: 2 additions & 0 deletions provider/pkg/gen/nodejs-templates/helm/v3/helm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ export class Chart extends yaml.CollectionComponentResource {
this.resources = allConfig.apply(cfg => {
return this.parseChart(cfg, releaseName, opts)
});

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

parseChart(config: ChartOpts | LocalChartOpts, releaseName: string, opts?: pulumi.ComponentResourceOptions) {
Expand Down
1 change: 1 addition & 0 deletions provider/pkg/gen/nodejs-templates/yaml/yaml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { getVersion } from "../utilities";

export abstract class CollectionComponentResource extends pulumi.ComponentResource {
resources!: pulumi.Output<{ [key: string]: pulumi.CustomResource }>;
ready!: pulumi.Output<pulumi.CustomResource[]>;

protected constructor(
resourceType: string, name: string, config: any, opts?: pulumi.ComponentResourceOptions,
Expand Down
2 changes: 2 additions & 0 deletions sdk/nodejs/helm/v2/helm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ export class Chart extends yaml.CollectionComponentResource {
overrides.removeCallback();
}
});

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

parseTemplate(
Expand Down
2 changes: 2 additions & 0 deletions sdk/nodejs/helm/v3/helm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ export class Chart extends yaml.CollectionComponentResource {
this.resources = allConfig.apply(cfg => {
return this.parseChart(cfg, releaseName, opts)
});

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

parseChart(config: ChartOpts | LocalChartOpts, releaseName: string, opts?: pulumi.ComponentResourceOptions) {
Expand Down
1 change: 1 addition & 0 deletions sdk/nodejs/yaml/yaml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { getVersion } from "../utilities";

export abstract class CollectionComponentResource extends pulumi.ComponentResource {
resources!: pulumi.Output<{ [key: string]: pulumi.CustomResource }>;
ready!: pulumi.Output<pulumi.CustomResource[]>;

protected constructor(
resourceType: string, name: string, config: any, opts?: pulumi.ComponentResourceOptions,
Expand Down
34 changes: 31 additions & 3 deletions tests/sdk/nodejs/examples/examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"fmt"
"os"
"path/filepath"
"regexp"
"sort"
"testing"

Expand Down Expand Up @@ -189,13 +190,40 @@ func TestAccHelmLocal(t *testing.T) {
skipIfShort(t)
test := getBaseOptions(t).
With(integration.ProgramTestOptions{
Dir: filepath.Join(getCwd(t), "helm-local", "step1"),
SkipRefresh: true, // Deployment controller changes object out-of-band.
Dir: filepath.Join(getCwd(t), "helm-local", "step1"),
ExpectRefreshChanges: true,
ExtraRuntimeValidation: func(
t *testing.T, stackInfo integration.RuntimeValidationStackInfo,
) {
assert.NotNil(t, stackInfo.Deployment)
assert.Equal(t, 15, len(stackInfo.Deployment.Resources))
assert.Equal(t, 12, len(stackInfo.Deployment.Resources))

// Verify resource creation order using the Event stream. The Chart resources must be created
// first, followed by the dependent ConfigMap. (The ConfigMap doesn't actually need the Chart, but
// it creates almost instantly, so it's a good choice to test creation ordering)
cmRegex := regexp.MustCompile(`ConfigMap::test-.*/nginx-server-block`)
svcRegex := regexp.MustCompile(`Service::test-.*/nginx`)
deployRegex := regexp.MustCompile(`Deployment::test-.*/nginx`)
dependentRegex := regexp.MustCompile(`ConfigMap::foo`)

var configmapFound, serviceFound, deploymentFound, dependentFound bool
for _, e := range stackInfo.Events {
if e.ResOutputsEvent != nil {
switch {
case cmRegex.MatchString(e.ResOutputsEvent.Metadata.URN):
configmapFound = true
case svcRegex.MatchString(e.ResOutputsEvent.Metadata.URN):
serviceFound = true
case deployRegex.MatchString(e.ResOutputsEvent.Metadata.URN):
deploymentFound = true
case dependentRegex.MatchString(e.ResOutputsEvent.Metadata.URN):
dependentFound = true
}
assert.Falsef(t, dependentFound && !(configmapFound && serviceFound && deploymentFound),
"dependent ConfigMap created before all chart resources were ready")
fmt.Println(e.ResOutputsEvent.Metadata.URN)
}
}
},
EditDirs: []integration.EditDir{
{
Expand Down
34 changes: 15 additions & 19 deletions tests/sdk/nodejs/examples/helm-local/step1/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2016-2019, Pulumi Corporation.
// 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.
Expand All @@ -19,40 +19,36 @@ const namespace = new k8s.core.v1.Namespace("test");
const namespaceName = namespace.metadata.name;

function chart(resourcePrefix?: string): k8s.helm.v2.Chart {
return new k8s.helm.v2.Chart("nginx-lego", {
// Represents chart `stable/nginx-lego@v0.3.1`.
path: "nginx-lego",
version: "0.3.1",
return new k8s.helm.v2.Chart("nginx", {
path: "nginx",
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}
service: { type: "ClusterIP" }
},
transformations: [
// Make every service private to the cluster, i.e., turn all services into ClusterIP instead of
// LoadBalancer.
(obj: any) => {
(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";
}
opts.additionalSecretOutputs = ["status"];
}
},
}
]
});
}

// Create the first instance of the Chart.
const nginx = chart();

// Create a ConfigMap depending on the Chart. The ConfigMap should not be created until after all of the Chart
// resources are ready.
new k8s.core.v1.ConfigMap("foo", {
metadata: { namespace: namespaceName },
data: {foo: "bar"}
}, {dependsOn: nginx.ready})

// 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"));
nginx.getResourceProperty("v1/Service", nsName, "nginx", "spec"));
export const frontendServiceIP = frontendServiceSpec.clusterIP;

// Deploy a duplicate chart with a different resource prefix to verify that multiple instances of the Chart
Expand Down
16 changes: 0 additions & 16 deletions tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/Chart.yaml

This file was deleted.

82 changes: 0 additions & 82 deletions tests/sdk/nodejs/examples/helm-local/step1/nginx-lego/README.md

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Loading