From 3c6d6394504aec8d623a238701d23c5dcacd0cc5 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Sat, 21 Oct 2023 14:03:56 -0700 Subject: [PATCH 01/31] python fixes (configfile, configgroup, kustomize) --- .../gen/python-templates/kustomize/kustomize.py | 7 ++++--- provider/pkg/gen/python-templates/yaml/yaml.tmpl | 14 ++++++++------ .../pulumi_kubernetes/kustomize/kustomize.py | 7 ++++--- sdk/python/pulumi_kubernetes/yaml/yaml.py | 14 ++++++++------ 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/provider/pkg/gen/python-templates/kustomize/kustomize.py b/provider/pkg/gen/python-templates/kustomize/kustomize.py index 40934e1ed9..828dde18ff 100644 --- a/provider/pkg/gen/python-templates/kustomize/kustomize.py +++ b/provider/pkg/gen/python-templates/kustomize/kustomize.py @@ -111,9 +111,10 @@ def omit_resource(obj, opts): # 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(), - provider=opts.provider if opts.provider else None) - + 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) + __ret__ = pulumi.runtime.invoke( 'kubernetes:kustomize:directory', {'directory': directory}, invoke_opts) diff --git a/provider/pkg/gen/python-templates/yaml/yaml.tmpl b/provider/pkg/gen/python-templates/yaml/yaml.tmpl index df1cf7ca8f..bf5ebccbbe 100644 --- a/provider/pkg/gen/python-templates/yaml/yaml.tmpl +++ b/provider/pkg/gen/python-templates/yaml/yaml.tmpl @@ -190,9 +190,10 @@ class ConfigGroup(pulumi.ComponentResource): for text in yaml: # 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(), - provider=opts.provider if opts.provider else None) - + 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) + __ret__ = invoke_yaml_decode(text, invoke_opts) resources = _parse_yaml_document(__ret__, opts, transformations, resource_prefix) # Add any new YAML resources to the ConfigGroup's resources @@ -341,9 +342,10 @@ class ConfigFile(pulumi.ComponentResource): transformations.append(_skip_await) # 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(), - provider=opts.provider if opts.provider else None) + # in package.json. + 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) __ret__ = invoke_yaml_decode(text, invoke_opts) diff --git a/sdk/python/pulumi_kubernetes/kustomize/kustomize.py b/sdk/python/pulumi_kubernetes/kustomize/kustomize.py index 40934e1ed9..828dde18ff 100644 --- a/sdk/python/pulumi_kubernetes/kustomize/kustomize.py +++ b/sdk/python/pulumi_kubernetes/kustomize/kustomize.py @@ -111,9 +111,10 @@ def omit_resource(obj, opts): # 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(), - provider=opts.provider if opts.provider else None) - + 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) + __ret__ = pulumi.runtime.invoke( 'kubernetes:kustomize:directory', {'directory': directory}, invoke_opts) diff --git a/sdk/python/pulumi_kubernetes/yaml/yaml.py b/sdk/python/pulumi_kubernetes/yaml/yaml.py index cdaf951f57..2f172bf781 100644 --- a/sdk/python/pulumi_kubernetes/yaml/yaml.py +++ b/sdk/python/pulumi_kubernetes/yaml/yaml.py @@ -190,9 +190,10 @@ def omit_resource(obj, opts): for text in yaml: # 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(), - provider=opts.provider if opts.provider else None) - + 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) + __ret__ = invoke_yaml_decode(text, invoke_opts) resources = _parse_yaml_document(__ret__, opts, transformations, resource_prefix) # Add any new YAML resources to the ConfigGroup's resources @@ -341,9 +342,10 @@ def omit_resource(obj, opts): transformations.append(_skip_await) # 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(), - provider=opts.provider if opts.provider else None) + # in package.json. + 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) __ret__ = invoke_yaml_decode(text, invoke_opts) From fc53386be08972229b37f0e5e7f05b9523890e65 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 23 Oct 2023 08:52:02 -0700 Subject: [PATCH 02/31] python tests --- tests/sdk/python/yaml-test/__main__.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/sdk/python/yaml-test/__main__.py b/tests/sdk/python/yaml-test/__main__.py index 5118966edc..794d3cf39b 100644 --- a/tests/sdk/python/yaml-test/__main__.py +++ b/tests/sdk/python/yaml-test/__main__.py @@ -63,6 +63,15 @@ def secret_status(obj, opts): resource_prefix="dup", opts=ResourceOptions(provider=provider), ) + +# Test provider variations +cf_provider = ConfigFile( + "yaml-test", + "manifest.yaml", + transformations=[set_namespace(ns)], + opts=ResourceOptions(providers=[provider]), +) + cg = ConfigGroup( "deployment", files=["ns*.yaml"], @@ -74,3 +83,16 @@ def secret_status(obj, opts): """], opts=ResourceOptions(provider=provider) ) + +## Test provider variations +cg = ConfigGroup( + "deployment", + files=["ns*.yaml"], + yaml=[""" +apiVersion: v1 +kind: Namespace +metadata: + name: cg3 + """], + opts=ResourceOptions(providers=[provider]) +) From e8afba30c5784ddd89a4877bf53cfb59ff65d0d6 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 23 Oct 2023 15:16:45 -0700 Subject: [PATCH 03/31] node.js option propagation --- .../pkg/gen/nodejs-templates/helm/v3/helm.ts | 12 ++------ .../nodejs-templates/kustomize/kustomize.ts | 11 ++++--- .../pkg/gen/nodejs-templates/yaml/yaml.tmpl | 30 +++++++++++++++---- sdk/nodejs/helm/v3/helm.ts | 13 ++------ sdk/nodejs/kustomize/kustomize.ts | 8 ++--- sdk/nodejs/yaml/yaml.ts | 30 +++++++++++++++---- 6 files changed, 62 insertions(+), 42 deletions(-) diff --git a/provider/pkg/gen/nodejs-templates/helm/v3/helm.ts b/provider/pkg/gen/nodejs-templates/helm/v3/helm.ts index 790e784781..25a29789b1 100644 --- a/provider/pkg/gen/nodejs-templates/helm/v3/helm.ts +++ b/provider/pkg/gen/nodejs-templates/helm/v3/helm.ts @@ -238,14 +238,8 @@ export class Chart extends yaml.CollectionComponentResource { transformations.push(yaml.skipAwait); } - // 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: opts?.version ?? getVersion(), - provider: opts?.provider, - parent: opts?.parent - }; + const childOpts = yaml.getChildOpts(this, opts); + const invokeOpts = yaml.getInvokeOpts(childOpts); const promise = pulumi.runtime.invoke("kubernetes:helm:template", {jsonOpts}, invokeOpts); return pulumi.output(promise).apply<{ [key: string]: pulumi.CustomResource }>(p => yaml.parse( @@ -254,7 +248,7 @@ export class Chart extends yaml.CollectionComponentResource { objs: p.result, transformations, }, - {parent: this} + childOpts )); } } diff --git a/provider/pkg/gen/nodejs-templates/kustomize/kustomize.ts b/provider/pkg/gen/nodejs-templates/kustomize/kustomize.ts index 107b9e66fe..4309fdd02e 100644 --- a/provider/pkg/gen/nodejs-templates/kustomize/kustomize.ts +++ b/provider/pkg/gen/nodejs-templates/kustomize/kustomize.ts @@ -94,11 +94,10 @@ export class Directory extends yaml.CollectionComponentResource { } super("kubernetes:kustomize:Directory", name, config, opts); - const directory = config.directory - - // 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(), provider: opts?.provider }; + const directory = config.directory; + + const childOpts = yaml.getChildOpts(this, opts); + const invokeOpts = yaml.getInvokeOpts(childOpts); const promise = pulumi.runtime.invoke("kubernetes:kustomize:directory", {directory}, invokeOpts); this.resources = pulumi.output(promise).apply<{[key: string]: pulumi.CustomResource}>(p => yaml.parse( @@ -107,7 +106,7 @@ export class Directory extends yaml.CollectionComponentResource { objs: p.result, transformations: config.transformations || [], }, - { parent: this, dependsOn: opts?.dependsOn } + childOpts )); } } diff --git a/provider/pkg/gen/nodejs-templates/yaml/yaml.tmpl b/provider/pkg/gen/nodejs-templates/yaml/yaml.tmpl index ec74b4a722..ffa9cb8b7e 100644 --- a/provider/pkg/gen/nodejs-templates/yaml/yaml.tmpl +++ b/provider/pkg/gen/nodejs-templates/yaml/yaml.tmpl @@ -202,7 +202,8 @@ export class ConfigGroup extends CollectionComponentResource { */ constructor(name: string, config: ConfigGroupOpts, opts?: pulumi.ComponentResourceOptions) { super("kubernetes:yaml:ConfigGroup", name, config, opts); - this.resources = parse(config, {...opts, parent: this}); + const childOpts = getChildOpts(this, opts); + this.resources = parse(config, childOpts); } } @@ -291,13 +292,14 @@ export class ConfigFile extends CollectionComponentResource { transformations.push(skipAwait); } - this.resources = pulumi.output(text.then(t => { + const childOpts = getChildOpts(this, opts); + this.resources = pulumi.output(text.then(t => { try { const parsed = parseYamlDocument({ - objs: yamlLoadAll(t, opts), + objs: yamlLoadAll(t, childOpts), transformations, resourcePrefix: config && config.resourcePrefix || undefined - }, {...opts, parent: this}); + }, childOpts); // If the provider is not fully initialized, the engine skips invoking on the provider and returns an // empty result. This may change based on how https://github.com/pulumi/pulumi/issues/10209 is addressed. parsed.apply(p => { @@ -383,9 +385,25 @@ export interface ConfigOpts { resourcePrefix?: string; } -/** @ignore */ function yamlLoadAll(text: string, opts?: pulumi.ComponentResourceOptions): Promise { - let invokeOpts: pulumi.InvokeOptions = { async: true, version: getVersion(), provider: opts?.provider }; +/** @ignore */ export function getChildOpts(parent: pulumi.Resource, opts?: pulumi.ComponentResourceOptions): pulumi.CustomResourceOptions { + return { + parent: parent, + dependsOn: opts?.dependsOn, + }; +} + +/** @ignore */ export function getInvokeOpts(opts?: pulumi.CustomResourceOptions): pulumi.InvokeOptions { + return { + parent: opts?.parent, + provider: opts?.provider, + version: opts?.version ?? getVersion(), + pluginDownloadURL: opts?.pluginDownloadURL, + async: true + }; +} +/** @ignore */ function yamlLoadAll(text: string, opts?: pulumi.CustomResourceOptions): Promise { + const invokeOpts = getInvokeOpts(opts); return pulumi.runtime.invoke("kubernetes:yaml:decode", {text}, invokeOpts) .then(p => p.result); } diff --git a/sdk/nodejs/helm/v3/helm.ts b/sdk/nodejs/helm/v3/helm.ts index 790e784781..866af4e1ed 100644 --- a/sdk/nodejs/helm/v3/helm.ts +++ b/sdk/nodejs/helm/v3/helm.ts @@ -238,15 +238,8 @@ export class Chart extends yaml.CollectionComponentResource { transformations.push(yaml.skipAwait); } - // 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: opts?.version ?? getVersion(), - provider: opts?.provider, - parent: opts?.parent - }; - + const childOpts = yaml.getChildOpts(this, opts) + const invokeOpts = yaml.getInvokeOpts(childOpts) const promise = pulumi.runtime.invoke("kubernetes:helm:template", {jsonOpts}, invokeOpts); return pulumi.output(promise).apply<{ [key: string]: pulumi.CustomResource }>(p => yaml.parse( { @@ -254,7 +247,7 @@ export class Chart extends yaml.CollectionComponentResource { objs: p.result, transformations, }, - {parent: this} + childOpts )); } } diff --git a/sdk/nodejs/kustomize/kustomize.ts b/sdk/nodejs/kustomize/kustomize.ts index 107b9e66fe..5eb9937546 100644 --- a/sdk/nodejs/kustomize/kustomize.ts +++ b/sdk/nodejs/kustomize/kustomize.ts @@ -96,10 +96,8 @@ export class Directory extends yaml.CollectionComponentResource { const directory = config.directory - // 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(), provider: opts?.provider }; - + const childOpts = yaml.getChildOpts(this, opts); + const invokeOpts = yaml.getInvokeOpts(childOpts); const promise = pulumi.runtime.invoke("kubernetes:kustomize:directory", {directory}, invokeOpts); this.resources = pulumi.output(promise).apply<{[key: string]: pulumi.CustomResource}>(p => yaml.parse( { @@ -107,7 +105,7 @@ export class Directory extends yaml.CollectionComponentResource { objs: p.result, transformations: config.transformations || [], }, - { parent: this, dependsOn: opts?.dependsOn } + childOpts )); } } diff --git a/sdk/nodejs/yaml/yaml.ts b/sdk/nodejs/yaml/yaml.ts index af8eb624cd..7978121b17 100644 --- a/sdk/nodejs/yaml/yaml.ts +++ b/sdk/nodejs/yaml/yaml.ts @@ -2949,7 +2949,8 @@ export class ConfigGroup extends CollectionComponentResource { */ constructor(name: string, config: ConfigGroupOpts, opts?: pulumi.ComponentResourceOptions) { super("kubernetes:yaml:ConfigGroup", name, config, opts); - this.resources = parse(config, {...opts, parent: this}); + const childOpts = getChildOpts(this, opts); + this.resources = parse(config, childOpts); } } @@ -3038,13 +3039,14 @@ export class ConfigFile extends CollectionComponentResource { transformations.push(skipAwait); } - this.resources = pulumi.output(text.then(t => { + const childOpts = getChildOpts(this, opts); + this.resources = pulumi.output(text.then(t => { try { const parsed = parseYamlDocument({ - objs: yamlLoadAll(t, opts), + objs: yamlLoadAll(t, childOpts), transformations, resourcePrefix: config && config.resourcePrefix || undefined - }, {...opts, parent: this}); + }, childOpts); // If the provider is not fully initialized, the engine skips invoking on the provider and returns an // empty result. This may change based on how https://github.com/pulumi/pulumi/issues/10209 is addressed. parsed.apply(p => { @@ -3130,9 +3132,25 @@ export interface ConfigOpts { resourcePrefix?: string; } -/** @ignore */ function yamlLoadAll(text: string, opts?: pulumi.ComponentResourceOptions): Promise { - let invokeOpts: pulumi.InvokeOptions = { async: true, version: getVersion(), provider: opts?.provider }; +/** @ignore */ export function getChildOpts(parent: pulumi.Resource, opts?: pulumi.ComponentResourceOptions): pulumi.CustomResourceOptions { + return { + parent: parent, + dependsOn: opts?.dependsOn, + }; +} + +/** @ignore */ export function getInvokeOpts(opts?: pulumi.CustomResourceOptions): pulumi.InvokeOptions { + return { + parent: opts?.parent, + provider: opts?.provider, + version: opts?.version ?? getVersion(), + pluginDownloadURL: opts?.pluginDownloadURL, + async: true + }; +} +/** @ignore */ function yamlLoadAll(text: string, opts?: pulumi.CustomResourceOptions): Promise { + const invokeOpts = getInvokeOpts(opts); return pulumi.runtime.invoke("kubernetes:yaml:decode", {text}, invokeOpts) .then(p => p.result); } From 91d5cba04efc02c5e9fba782bcc03d0953bbe7a9 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 23 Oct 2023 17:18:16 -0700 Subject: [PATCH 04/31] go sdk - option propagation --- .../pkg/gen/_go-templates/helm/v3/chart.go | 25 +++++------ .../gen/_go-templates/kustomize/directory.go | 15 +++---- .../pkg/gen/_go-templates/yaml/configFile.go | 5 ++- .../pkg/gen/_go-templates/yaml/configGroup.go | 5 ++- provider/pkg/gen/_go-templates/yaml/yaml.tmpl | 45 +++++++++++++++---- sdk/go/kubernetes/helm/v3/chart.go | 26 +++++------ sdk/go/kubernetes/kustomize/directory.go | 15 +++---- sdk/go/kubernetes/yaml/configFile.go | 5 ++- sdk/go/kubernetes/yaml/configGroup.go | 5 ++- sdk/go/kubernetes/yaml/yaml.go | 45 +++++++++++++++---- 10 files changed, 124 insertions(+), 67 deletions(-) diff --git a/provider/pkg/gen/_go-templates/helm/v3/chart.go b/provider/pkg/gen/_go-templates/helm/v3/chart.go index 3bf3065005..b0fd9b1128 100644 --- a/provider/pkg/gen/_go-templates/helm/v3/chart.go +++ b/provider/pkg/gen/_go-templates/helm/v3/chart.go @@ -244,12 +244,6 @@ func NewChart(ctx *pulumi.Context, }, }) - 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 { @@ -261,9 +255,12 @@ func NewChart(ctx *pulumi.Context, name = args.ResourcePrefix + "-" + name } - resourceOrInvokeOptions = append(resourceOrInvokeOptions, pulumi.Parent(chart)) + parseOpts, err := yaml.GetChildOptions(chart, opts) + if err != nil { + return nil, err + } resources := args.ToChartArgsOutput().ApplyT(func(args chartArgs) (map[string]pulumi.Resource, error) { - return parseChart(ctx, name, args, resourceOrInvokeOptions...) + return parseChart(ctx, name, args, parseOpts...) }) chart.Resources = resources @@ -287,7 +284,7 @@ func NewChart(ctx *pulumi.Context, return chart, nil } -func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi.ResourceOrInvokeOption, +func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi.ResourceOption, ) (map[string]pulumi.Resource, error) { type jsonOptsArgs struct { chartArgs @@ -304,11 +301,9 @@ func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi return nil, err } - var invokeOpts []pulumi.InvokeOption - var resourceOpts []pulumi.ResourceOption - for _, o := range opts { - invokeOpts = append(invokeOpts, o) - resourceOpts = append(resourceOpts, o) + invokeOpts, err := yaml.GetInvokeOptions(opts) + if err != nil { + return nil, err } objs, err := helmTemplate(ctx, string(b), invokeOpts...) if err != nil { @@ -320,7 +315,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, resourceOpts...) + resources, err := yaml.ParseYamlObjects(ctx, objs, transformations, args.ResourcePrefix, opts...) if err != nil { return nil, err } diff --git a/provider/pkg/gen/_go-templates/kustomize/directory.go b/provider/pkg/gen/_go-templates/kustomize/directory.go index 6e1091838f..ca797a6058 100644 --- a/provider/pkg/gen/_go-templates/kustomize/directory.go +++ b/provider/pkg/gen/_go-templates/kustomize/directory.go @@ -165,7 +165,10 @@ func NewDirectory(ctx *pulumi.Context, name = args.ResourcePrefix + "-" + name } - parseOpts := append(opts, pulumi.Parent(chart)) + parseOpts, err := yaml.GetChildOptions(chart, opts) + if err != nil { + return nil, err + } resources := args.ToDirectoryArgsOutput().ApplyT(func(args directoryArgs) (map[string]pulumi.Resource, error) { return parseDirectory(ctx, name, args, parseOpts...) }) @@ -191,14 +194,10 @@ func parseDirectory(ctx *pulumi.Context, name string, args directoryArgs, opts . Result []map[string]interface{} `pulumi:"result"` } - // Find options which are also Invoke options, and prepare them to pass to Invoke functions - var invokeOpts []pulumi.InvokeOption - for _, opt := range opts { - if invokeOpt, ok := opt.(pulumi.InvokeOption); ok { - invokeOpts = append(invokeOpts, invokeOpt) - } + invokeOpts, err := yaml.GetInvokeOptions(opts) + if err != nil { + return nil, err } - if err := ctx.Invoke("kubernetes:kustomize:directory", &invokeArgs, &ret, invokeOpts...); err != nil { return nil, errors.Wrap(err, "kustomize invoke failed") } diff --git a/provider/pkg/gen/_go-templates/yaml/configFile.go b/provider/pkg/gen/_go-templates/yaml/configFile.go index 2dbf0eb897..48e429ac90 100644 --- a/provider/pkg/gen/_go-templates/yaml/configFile.go +++ b/provider/pkg/gen/_go-templates/yaml/configFile.go @@ -162,7 +162,10 @@ func NewConfigFile(ctx *pulumi.Context, } // Parse and decode the YAML files. - parseOpts := append(opts, pulumi.Parent(configFile)) + parseOpts, err := GetChildOptions(configFile, opts) + if err != nil { + return nil, err + } rs, err := parseDecodeYamlFiles(ctx, &ConfigGroupArgs{ Files: []string{args.File}, Transformations: args.Transformations, diff --git a/provider/pkg/gen/_go-templates/yaml/configGroup.go b/provider/pkg/gen/_go-templates/yaml/configGroup.go index a8043ee1b3..251086c053 100644 --- a/provider/pkg/gen/_go-templates/yaml/configGroup.go +++ b/provider/pkg/gen/_go-templates/yaml/configGroup.go @@ -289,7 +289,10 @@ func NewConfigGroup(ctx *pulumi.Context, } // Parse and decode the YAML files. - parseOpts := append(opts, pulumi.Parent(configGroup)) + parseOpts, err := GetChildOptions(configGroup, opts) + if err != nil { + return nil, err + } rs, err := parseDecodeYamlFiles(ctx, args, true, parseOpts...) if err != nil { return nil, err diff --git a/provider/pkg/gen/_go-templates/yaml/yaml.tmpl b/provider/pkg/gen/_go-templates/yaml/yaml.tmpl index 9a185c060c..778ba28691 100644 --- a/provider/pkg/gen/_go-templates/yaml/yaml.tmpl +++ b/provider/pkg/gen/_go-templates/yaml/yaml.tmpl @@ -34,6 +34,39 @@ import ( "github.com/pulumi/pulumi/sdk/v3/go/pulumi" ) +func GetChildOptions(parent pulumi.Resource, opts []pulumi.ResourceOption) ([]pulumi.ResourceOption, error) { + snapshot, err := pulumi.NewResourceOptions(opts...) + if err != nil { + return nil, err + } + childOpts := []pulumi.ResourceOption{pulumi.Parent(parent)} + if len(snapshot.DependsOn) > 0 { + childOpts = append(childOpts, pulumi.DependsOn(snapshot.DependsOn)) + } + return childOpts, nil +} + +func GetInvokeOptions(opts []pulumi.ResourceOption) ([]pulumi.InvokeOption, error) { + snapshot, err := pulumi.NewResourceOptions(opts...) + if err != nil { + return nil, err + } + var invokeOpts []pulumi.InvokeOption + if snapshot.Parent != nil { + invokeOpts = append(invokeOpts, pulumi.Parent(snapshot.Parent)) + } + if snapshot.Provider != nil { + invokeOpts = append(invokeOpts, pulumi.Provider(snapshot.Provider)) + } + if snapshot.Version != "" { + invokeOpts = append(invokeOpts, pulumi.Version(snapshot.Version)) + } + if snapshot.PluginDownloadURL != "" { + invokeOpts = append(invokeOpts, pulumi.PluginDownloadURL(snapshot.PluginDownloadURL)) + } + return invokeOpts, nil +} + func parseDecodeYamlFiles(ctx *pulumi.Context, args *ConfigGroupArgs, glob bool, opts ...pulumi.ResourceOption, ) (map[string]pulumi.Resource, error) { @@ -80,15 +113,11 @@ func parseDecodeYamlFiles(ctx *pulumi.Context, args *ConfigGroupArgs, glob bool, } } - // Find options which are also Invoke options, and prepare them to pass to Invoke functions - var invokeOpts []pulumi.InvokeOption - for _, opt := range opts { - if invokeOpt, ok := opt.(pulumi.InvokeOption); ok { - invokeOpts = append(invokeOpts, invokeOpt) - } - } - // Next parse all YAML documents into objects. + invokeOpts, err := GetInvokeOptions(opts) + if err != nil { + return nil, err + } for _, yaml := range yamls { // Parse the resulting YAML bytes and turn them into raw Kubernetes objects. dec, err := yamlDecode(ctx, yaml, invokeOpts...) diff --git a/sdk/go/kubernetes/helm/v3/chart.go b/sdk/go/kubernetes/helm/v3/chart.go index 3bf3065005..4d74b3f441 100644 --- a/sdk/go/kubernetes/helm/v3/chart.go +++ b/sdk/go/kubernetes/helm/v3/chart.go @@ -243,13 +243,6 @@ 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 { @@ -261,9 +254,12 @@ func NewChart(ctx *pulumi.Context, name = args.ResourcePrefix + "-" + name } - resourceOrInvokeOptions = append(resourceOrInvokeOptions, pulumi.Parent(chart)) + parseOpts, err := yaml.GetChildOptions(chart, opts) + if err != nil { + return nil, err + } resources := args.ToChartArgsOutput().ApplyT(func(args chartArgs) (map[string]pulumi.Resource, error) { - return parseChart(ctx, name, args, resourceOrInvokeOptions...) + return parseChart(ctx, name, args, parseOpts...) }) chart.Resources = resources @@ -287,7 +283,7 @@ func NewChart(ctx *pulumi.Context, return chart, nil } -func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi.ResourceOrInvokeOption, +func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi.ResourceOption, ) (map[string]pulumi.Resource, error) { type jsonOptsArgs struct { chartArgs @@ -304,11 +300,9 @@ func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi return nil, err } - var invokeOpts []pulumi.InvokeOption - var resourceOpts []pulumi.ResourceOption - for _, o := range opts { - invokeOpts = append(invokeOpts, o) - resourceOpts = append(resourceOpts, o) + invokeOpts, err := yaml.GetInvokeOptions(opts) + if err != nil { + return nil, err } objs, err := helmTemplate(ctx, string(b), invokeOpts...) if err != nil { @@ -320,7 +314,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, resourceOpts...) + resources, err := yaml.ParseYamlObjects(ctx, objs, transformations, args.ResourcePrefix, opts...) if err != nil { return nil, err } diff --git a/sdk/go/kubernetes/kustomize/directory.go b/sdk/go/kubernetes/kustomize/directory.go index 6e1091838f..ca797a6058 100644 --- a/sdk/go/kubernetes/kustomize/directory.go +++ b/sdk/go/kubernetes/kustomize/directory.go @@ -165,7 +165,10 @@ func NewDirectory(ctx *pulumi.Context, name = args.ResourcePrefix + "-" + name } - parseOpts := append(opts, pulumi.Parent(chart)) + parseOpts, err := yaml.GetChildOptions(chart, opts) + if err != nil { + return nil, err + } resources := args.ToDirectoryArgsOutput().ApplyT(func(args directoryArgs) (map[string]pulumi.Resource, error) { return parseDirectory(ctx, name, args, parseOpts...) }) @@ -191,14 +194,10 @@ func parseDirectory(ctx *pulumi.Context, name string, args directoryArgs, opts . Result []map[string]interface{} `pulumi:"result"` } - // Find options which are also Invoke options, and prepare them to pass to Invoke functions - var invokeOpts []pulumi.InvokeOption - for _, opt := range opts { - if invokeOpt, ok := opt.(pulumi.InvokeOption); ok { - invokeOpts = append(invokeOpts, invokeOpt) - } + invokeOpts, err := yaml.GetInvokeOptions(opts) + if err != nil { + return nil, err } - if err := ctx.Invoke("kubernetes:kustomize:directory", &invokeArgs, &ret, invokeOpts...); err != nil { return nil, errors.Wrap(err, "kustomize invoke failed") } diff --git a/sdk/go/kubernetes/yaml/configFile.go b/sdk/go/kubernetes/yaml/configFile.go index 2dbf0eb897..48e429ac90 100644 --- a/sdk/go/kubernetes/yaml/configFile.go +++ b/sdk/go/kubernetes/yaml/configFile.go @@ -162,7 +162,10 @@ func NewConfigFile(ctx *pulumi.Context, } // Parse and decode the YAML files. - parseOpts := append(opts, pulumi.Parent(configFile)) + parseOpts, err := GetChildOptions(configFile, opts) + if err != nil { + return nil, err + } rs, err := parseDecodeYamlFiles(ctx, &ConfigGroupArgs{ Files: []string{args.File}, Transformations: args.Transformations, diff --git a/sdk/go/kubernetes/yaml/configGroup.go b/sdk/go/kubernetes/yaml/configGroup.go index a8043ee1b3..251086c053 100644 --- a/sdk/go/kubernetes/yaml/configGroup.go +++ b/sdk/go/kubernetes/yaml/configGroup.go @@ -289,7 +289,10 @@ func NewConfigGroup(ctx *pulumi.Context, } // Parse and decode the YAML files. - parseOpts := append(opts, pulumi.Parent(configGroup)) + parseOpts, err := GetChildOptions(configGroup, opts) + if err != nil { + return nil, err + } rs, err := parseDecodeYamlFiles(ctx, args, true, parseOpts...) if err != nil { return nil, err diff --git a/sdk/go/kubernetes/yaml/yaml.go b/sdk/go/kubernetes/yaml/yaml.go index 6d2504c152..8f1c9e08c5 100644 --- a/sdk/go/kubernetes/yaml/yaml.go +++ b/sdk/go/kubernetes/yaml/yaml.go @@ -85,6 +85,39 @@ import ( "github.com/pulumi/pulumi/sdk/v3/go/pulumi" ) +func GetChildOptions(parent pulumi.Resource, opts []pulumi.ResourceOption) ([]pulumi.ResourceOption, error) { + snapshot, err := pulumi.NewResourceOptions(opts...) + if err != nil { + return nil, err + } + childOpts := []pulumi.ResourceOption{pulumi.Parent(parent)} + if len(snapshot.DependsOn) > 0 { + childOpts = append(childOpts, pulumi.DependsOn(snapshot.DependsOn)) + } + return childOpts, nil +} + +func GetInvokeOptions(opts []pulumi.ResourceOption) ([]pulumi.InvokeOption, error) { + snapshot, err := pulumi.NewResourceOptions(opts...) + if err != nil { + return nil, err + } + var invokeOpts []pulumi.InvokeOption + if snapshot.Parent != nil { + invokeOpts = append(invokeOpts, pulumi.Parent(snapshot.Parent)) + } + if snapshot.Provider != nil { + invokeOpts = append(invokeOpts, pulumi.Provider(snapshot.Provider)) + } + if snapshot.Version != "" { + invokeOpts = append(invokeOpts, pulumi.Version(snapshot.Version)) + } + if snapshot.PluginDownloadURL != "" { + invokeOpts = append(invokeOpts, pulumi.PluginDownloadURL(snapshot.PluginDownloadURL)) + } + return invokeOpts, nil +} + func parseDecodeYamlFiles(ctx *pulumi.Context, args *ConfigGroupArgs, glob bool, opts ...pulumi.ResourceOption, ) (map[string]pulumi.Resource, error) { @@ -131,15 +164,11 @@ func parseDecodeYamlFiles(ctx *pulumi.Context, args *ConfigGroupArgs, glob bool, } } - // Find options which are also Invoke options, and prepare them to pass to Invoke functions - var invokeOpts []pulumi.InvokeOption - for _, opt := range opts { - if invokeOpt, ok := opt.(pulumi.InvokeOption); ok { - invokeOpts = append(invokeOpts, invokeOpt) - } - } - // Next parse all YAML documents into objects. + invokeOpts, err := GetInvokeOptions(opts) + if err != nil { + return nil, err + } for _, yaml := range yamls { // Parse the resulting YAML bytes and turn them into raw Kubernetes objects. dec, err := yamlDecode(ctx, yaml, invokeOpts...) From ff2d388dc56ae8340c2d5972e207b9cf46811538 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 23 Oct 2023 18:35:35 -0700 Subject: [PATCH 05/31] python SDK (child opts) --- .../pkg/gen/python-templates/helm/v3/helm.py | 13 +++---- .../python-templates/kustomize/kustomize.py | 15 ++++---- .../pkg/gen/python-templates/yaml/yaml.tmpl | 36 +++++++++---------- sdk/python/pulumi_kubernetes/helm/v3/helm.py | 11 +++--- .../pulumi_kubernetes/kustomize/kustomize.py | 15 ++++---- sdk/python/pulumi_kubernetes/yaml/yaml.py | 33 ++++++++--------- 6 files changed, 56 insertions(+), 67 deletions(-) diff --git a/provider/pkg/gen/python-templates/helm/v3/helm.py b/provider/pkg/gen/python-templates/helm/v3/helm.py index 57da034700..16faf50d84 100644 --- a/provider/pkg/gen/python-templates/helm/v3/helm.py +++ b/provider/pkg/gen/python-templates/helm/v3/helm.py @@ -19,7 +19,7 @@ from typing import Any, Callable, Optional, Sequence, Tuple, Union import pulumi.runtime -from pulumi_kubernetes.yaml.yaml import _parse_yaml_document, _skip_await +from pulumi_kubernetes.yaml.yaml import _get_child_options, _get_invoke_options, _parse_yaml_document, _skip_await from ... import _utilities @@ -189,7 +189,8 @@ def omit_resource(obj, opts): config.release_name = release_name - all_config = pulumi.Output.from_input((config, pulumi.ResourceOptions(parent=self))) + parseOpts = _get_child_options(self, opts) + all_config = pulumi.Output.from_input((config, parseOpts)) # Note: Unlike NodeJS, Python requires that we "pull" on our futures in order to get them scheduled for # execution. In order to do this, we leverage the engine's RegisterResourceOutputs to wait for the @@ -587,12 +588,8 @@ def _parse_chart(all_config: Tuple[Union[ChartOpts, LocalChartOpts], pulumi.Reso json_opts = config.to_json() - # 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() if not opts.version else opts.version, - parent=opts.parent if opts.parent else None, - provider=opts.provider if opts.provider else None) - + invoke_opts = _get_invoke_options(opts) + transformations = config.transformations if config.transformations is not None else [] if config.skip_await: transformations.append(_skip_await) diff --git a/provider/pkg/gen/python-templates/kustomize/kustomize.py b/provider/pkg/gen/python-templates/kustomize/kustomize.py index 828dde18ff..618668c8b2 100644 --- a/provider/pkg/gen/python-templates/kustomize/kustomize.py +++ b/provider/pkg/gen/python-templates/kustomize/kustomize.py @@ -4,7 +4,7 @@ from typing import Any, Callable, Optional, Sequence import pulumi.runtime -import pulumi_kubernetes as k8s +from pulumi_kubernetes.yaml.yaml import _get_child_options, _get_invoke_options, _parse_yaml_document from .. import _utilities, _tables @@ -98,6 +98,8 @@ def omit_resource(obj, opts): raise TypeError('Missing resource name argument (for URN creation)') if not isinstance(name, str): raise TypeError('Expected resource name to be a string') + if opts is None: + opts = pulumi.ResourceOptions() if opts and not isinstance(opts, pulumi.ResourceOptions): raise TypeError('Expected resource options to be a ResourceOptions instance') @@ -107,13 +109,8 @@ def omit_resource(obj, opts): name = f"{resource_prefix}-{name}" super(Directory, self).__init__("kubernetes:kustomize:Directory", name, __props__, opts) - opts = pulumi.ResourceOptions.merge(opts, pulumi.ResourceOptions(parent=self)) - - # 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() if not opts.version else opts.version, - parent=opts.parent if opts.parent else None, - provider=opts.provider if opts.provider else None) + child_opts = _get_child_options(self, opts) + invoke_opts = _get_invoke_options(child_opts) __ret__ = pulumi.runtime.invoke( 'kubernetes:kustomize:directory', {'directory': directory}, invoke_opts) @@ -125,7 +122,7 @@ def omit_resource(obj, opts): # Note: Unlike NodeJS, Python requires that we "pull" on our futures in order to get them scheduled for # execution. In order to do this, we leverage the engine's RegisterResourceOutputs to wait for the # resolution of all resources that this YAML document created. - self.resources = k8s.yaml.yaml._parse_yaml_document(result, opts, transformations, resource_prefix) + self.resources = k8s.yaml.yaml._parse_yaml_document(result, child_opts, transformations, resource_prefix) self.register_outputs({"resources": self.resources}) def translate_output_property(self, prop: str) -> str: diff --git a/provider/pkg/gen/python-templates/yaml/yaml.tmpl b/provider/pkg/gen/python-templates/yaml/yaml.tmpl index bf5ebccbbe..d1425dd586 100644 --- a/provider/pkg/gen/python-templates/yaml/yaml.tmpl +++ b/provider/pkg/gen/python-templates/yaml/yaml.tmpl @@ -179,21 +179,16 @@ class ConfigGroup(pulumi.ComponentResource): else: _files += [f for f in glob(file)] - opts = pulumi.ResourceOptions.merge(opts, pulumi.ResourceOptions(parent=self)) + child_opts = _get_child_options(self, opts) for file in _files: cf = ConfigFile( - file, file_id=file, transformations=transformations, resource_prefix=resource_prefix, opts=opts) + file, file_id=file, transformations=transformations, resource_prefix=resource_prefix, opts=child_opts) # Add any new ConfigFile resources to the ConfigGroup's resources self.resources = pulumi.Output.all(cf.resources, self.resources).apply(lambda x: {**x[0], **x[1]}) for text in yaml: - # 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() if not opts.version else opts.version, - parent=opts.parent if opts.parent else None, - provider=opts.provider if opts.provider else None) - + invoke_opts = _get_invoke_options(child_opts) __ret__ = invoke_yaml_decode(text, invoke_opts) resources = _parse_yaml_document(__ret__, opts, transformations, resource_prefix) # Add any new YAML resources to the ConfigGroup's resources @@ -335,24 +330,19 @@ class ConfigFile(pulumi.ComponentResource): else: text = _read_file(file) - opts = pulumi.ResourceOptions.merge(opts, pulumi.ResourceOptions(parent=self)) + child_opts = _get_child_options(self, opts) transformations = transformations if transformations is not None else [] if skip_await: transformations.append(_skip_await) - - # 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() if not opts.version else opts.version, - parent=opts.parent if opts.parent else None, - provider=opts.provider if opts.provider else None) - + + invoke_opts = _get_invoke_options(child_opts) __ret__ = invoke_yaml_decode(text, invoke_opts) # Note: Unlike NodeJS, Python requires that we "pull" on our futures in order to get them scheduled for # execution. In order to do this, we leverage the engine's RegisterResourceOutputs to wait for the # resolution of all resources that this YAML document created. - self.resources = _parse_yaml_document(__ret__, opts, transformations, resource_prefix) + self.resources = _parse_yaml_document(__ret__, child_opts, transformations, resource_prefix) self.register_outputs({"resources": self.resources}) def translate_output_property(self, prop: str) -> str: @@ -412,7 +402,17 @@ def _read_file(path: str) -> str: def _build_resources_dict(objs: Sequence[pulumi.Output]) -> Mapping[pulumi.Output, pulumi.Output]: return {key: value for key, value in objs} - +def _get_child_options(parent: pulumi.Resource, opts: pulumi.ResourceOptions): + return pulumi.ResourceOptions(parent=parent, depends_on=opts.depends_on) + +def _get_invoke_options(opts: pulumi.ResourceOptions): + return pulumi.InvokeOptions( + parent=opts.parent if opts.parent else None, + provider=opts.provider if opts.provider else None, + version=_utilities.get_version() if not opts.version else opts.version, + plugin_download_url=opts.plugin_download_url if opts.plugin_download_url else None + ) + def _parse_yaml_document( objects, opts: Optional[pulumi.ResourceOptions] = None, transformations: Optional[Sequence[Callable]] = None, diff --git a/sdk/python/pulumi_kubernetes/helm/v3/helm.py b/sdk/python/pulumi_kubernetes/helm/v3/helm.py index 57da034700..6712485cb0 100644 --- a/sdk/python/pulumi_kubernetes/helm/v3/helm.py +++ b/sdk/python/pulumi_kubernetes/helm/v3/helm.py @@ -19,7 +19,7 @@ from typing import Any, Callable, Optional, Sequence, Tuple, Union import pulumi.runtime -from pulumi_kubernetes.yaml.yaml import _parse_yaml_document, _skip_await +from pulumi_kubernetes.yaml.yaml import _get_child_options, _get_invoke_options, _parse_yaml_document, _skip_await from ... import _utilities @@ -189,7 +189,8 @@ def omit_resource(obj, opts): config.release_name = release_name - all_config = pulumi.Output.from_input((config, pulumi.ResourceOptions(parent=self))) + parseOpts = _get_child_options(self, opts) + all_config = pulumi.Output.from_input((config, parseOpts)) # Note: Unlike NodeJS, Python requires that we "pull" on our futures in order to get them scheduled for # execution. In order to do this, we leverage the engine's RegisterResourceOutputs to wait for the @@ -587,11 +588,7 @@ def _parse_chart(all_config: Tuple[Union[ChartOpts, LocalChartOpts], pulumi.Reso json_opts = config.to_json() - # 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() if not opts.version else opts.version, - parent=opts.parent if opts.parent else None, - provider=opts.provider if opts.provider else None) + invoke_opts = _get_invoke_options(opts) transformations = config.transformations if config.transformations is not None else [] if config.skip_await: diff --git a/sdk/python/pulumi_kubernetes/kustomize/kustomize.py b/sdk/python/pulumi_kubernetes/kustomize/kustomize.py index 828dde18ff..21efa5b1f9 100644 --- a/sdk/python/pulumi_kubernetes/kustomize/kustomize.py +++ b/sdk/python/pulumi_kubernetes/kustomize/kustomize.py @@ -4,7 +4,7 @@ from typing import Any, Callable, Optional, Sequence import pulumi.runtime -import pulumi_kubernetes as k8s +from pulumi_kubernetes.yaml.yaml import _get_child_options, _get_invoke_options, _parse_yaml_document from .. import _utilities, _tables @@ -98,6 +98,8 @@ def omit_resource(obj, opts): raise TypeError('Missing resource name argument (for URN creation)') if not isinstance(name, str): raise TypeError('Expected resource name to be a string') + if opts is None: + opts = pulumi.ResourceOptions() if opts and not isinstance(opts, pulumi.ResourceOptions): raise TypeError('Expected resource options to be a ResourceOptions instance') @@ -107,14 +109,9 @@ def omit_resource(obj, opts): name = f"{resource_prefix}-{name}" super(Directory, self).__init__("kubernetes:kustomize:Directory", name, __props__, opts) - opts = pulumi.ResourceOptions.merge(opts, pulumi.ResourceOptions(parent=self)) + child_opts = _get_child_options(self, opts) + invoke_opts = _get_invoke_options(child_opts) - # 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() if not opts.version else opts.version, - parent=opts.parent if opts.parent else None, - provider=opts.provider if opts.provider else None) - __ret__ = pulumi.runtime.invoke( 'kubernetes:kustomize:directory', {'directory': directory}, invoke_opts) @@ -125,7 +122,7 @@ def omit_resource(obj, opts): # Note: Unlike NodeJS, Python requires that we "pull" on our futures in order to get them scheduled for # execution. In order to do this, we leverage the engine's RegisterResourceOutputs to wait for the # resolution of all resources that this YAML document created. - self.resources = k8s.yaml.yaml._parse_yaml_document(result, opts, transformations, resource_prefix) + self.resources = _parse_yaml_document(result, child_opts, transformations, resource_prefix) self.register_outputs({"resources": self.resources}) def translate_output_property(self, prop: str) -> str: diff --git a/sdk/python/pulumi_kubernetes/yaml/yaml.py b/sdk/python/pulumi_kubernetes/yaml/yaml.py index 2f172bf781..0082efc850 100644 --- a/sdk/python/pulumi_kubernetes/yaml/yaml.py +++ b/sdk/python/pulumi_kubernetes/yaml/yaml.py @@ -179,21 +179,16 @@ def omit_resource(obj, opts): else: _files += [f for f in glob(file)] - opts = pulumi.ResourceOptions.merge(opts, pulumi.ResourceOptions(parent=self)) + child_opts = _get_child_options(self, opts) for file in _files: cf = ConfigFile( - file, file_id=file, transformations=transformations, resource_prefix=resource_prefix, opts=opts) + file, file_id=file, transformations=transformations, resource_prefix=resource_prefix, opts=child_opts) # Add any new ConfigFile resources to the ConfigGroup's resources self.resources = pulumi.Output.all(cf.resources, self.resources).apply(lambda x: {**x[0], **x[1]}) for text in yaml: - # 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() if not opts.version else opts.version, - parent=opts.parent if opts.parent else None, - provider=opts.provider if opts.provider else None) - + invoke_opts = _get_invoke_options(child_opts) __ret__ = invoke_yaml_decode(text, invoke_opts) resources = _parse_yaml_document(__ret__, opts, transformations, resource_prefix) # Add any new YAML resources to the ConfigGroup's resources @@ -335,24 +330,19 @@ def omit_resource(obj, opts): else: text = _read_file(file) - opts = pulumi.ResourceOptions.merge(opts, pulumi.ResourceOptions(parent=self)) + child_opts = _get_child_options(self, opts) transformations = transformations if transformations is not None else [] if skip_await: transformations.append(_skip_await) - # 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() if not opts.version else opts.version, - parent=opts.parent if opts.parent else None, - provider=opts.provider if opts.provider else None) - + invoke_opts = _get_invoke_options(child_opts) __ret__ = invoke_yaml_decode(text, invoke_opts) # Note: Unlike NodeJS, Python requires that we "pull" on our futures in order to get them scheduled for # execution. In order to do this, we leverage the engine's RegisterResourceOutputs to wait for the # resolution of all resources that this YAML document created. - self.resources = _parse_yaml_document(__ret__, opts, transformations, resource_prefix) + self.resources = _parse_yaml_document(__ret__, child_opts, transformations, resource_prefix) self.register_outputs({"resources": self.resources}) def translate_output_property(self, prop: str) -> str: @@ -409,6 +399,17 @@ def _read_file(path: str) -> str: return data +def _get_child_options(parent: pulumi.Resource, opts: pulumi.ResourceOptions): + return pulumi.ResourceOptions(parent=parent, depends_on=opts.depends_on) + +def _get_invoke_options(opts: pulumi.ResourceOptions): + return pulumi.InvokeOptions( + parent=opts.parent if opts.parent else None, + provider=opts.provider if opts.provider else None, + version=_utilities.get_version() if not opts.version else opts.version, + plugin_download_url=opts.plugin_download_url if opts.plugin_download_url else None + ) + def _build_resources_dict(objs: Sequence[pulumi.Output]) -> Mapping[pulumi.Output, pulumi.Output]: return {key: value for key, value in objs} From fcc4e403c4a5b7924e7667d9adf231f909acd6ae Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Wed, 1 Nov 2023 17:06:50 -0700 Subject: [PATCH 06/31] remove spurious name parameter --- sdk/go/kubernetes/kustomize/directory.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sdk/go/kubernetes/kustomize/directory.go b/sdk/go/kubernetes/kustomize/directory.go index ca797a6058..069a3aeb2b 100644 --- a/sdk/go/kubernetes/kustomize/directory.go +++ b/sdk/go/kubernetes/kustomize/directory.go @@ -160,17 +160,12 @@ func NewDirectory(ctx *pulumi.Context, return nil, err } - // Honor the resource name prefix if specified. - if args.ResourcePrefix != "" { - name = args.ResourcePrefix + "-" + name - } - parseOpts, err := yaml.GetChildOptions(chart, opts) if err != nil { return nil, err } resources := args.ToDirectoryArgsOutput().ApplyT(func(args directoryArgs) (map[string]pulumi.Resource, error) { - return parseDirectory(ctx, name, args, parseOpts...) + return parseDirectory(ctx, args, parseOpts...) }) chart.Resources = resources @@ -185,7 +180,7 @@ func NewDirectory(ctx *pulumi.Context, return chart, nil } -func parseDirectory(ctx *pulumi.Context, name string, args directoryArgs, opts ...pulumi.ResourceOption, +func parseDirectory(ctx *pulumi.Context, args directoryArgs, opts ...pulumi.ResourceOption, ) (map[string]pulumi.Resource, error) { invokeArgs := struct { Directory string `pulumi:"directory"` From cd7abece5622d90b1d8cdfc3e985a710f1f904e6 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Wed, 1 Nov 2023 17:07:30 -0700 Subject: [PATCH 07/31] Go SDK: ConfigFile shouldn't glob its parameter --- sdk/go/kubernetes/yaml/configFile.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/go/kubernetes/yaml/configFile.go b/sdk/go/kubernetes/yaml/configFile.go index 48e429ac90..576bbf9faf 100644 --- a/sdk/go/kubernetes/yaml/configFile.go +++ b/sdk/go/kubernetes/yaml/configFile.go @@ -170,7 +170,7 @@ func NewConfigFile(ctx *pulumi.Context, Files: []string{args.File}, Transformations: args.Transformations, ResourcePrefix: args.ResourcePrefix, - }, true, parseOpts...) + }, false, parseOpts...) if err != nil { return nil, err } From 421488d6f487e1261990745011260ed7e79c676b Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Wed, 29 Nov 2023 22:23:15 -0800 Subject: [PATCH 08/31] dotnet sdk - option propagation --- .../gen/dotnet-templates/helm/ChartBase.cs | 18 +-- .../pkg/gen/dotnet-templates/helm/v3/Chart.cs | 14 +-- .../dotnet-templates/kustomize/Directory.cs | 26 ++-- .../gen/dotnet-templates/yaml/ConfigFile.cs | 32 ++--- .../gen/dotnet-templates/yaml/ConfigGroup.cs | 5 +- .../pkg/gen/dotnet-templates/yaml/yaml.tmpl | 114 ++++++++++------- sdk/dotnet/Helm/ChartBase.cs | 18 +-- sdk/dotnet/Helm/V3/Chart.cs | 14 +-- sdk/dotnet/Kustomize/Directory.cs | 26 ++-- sdk/dotnet/Yaml/ConfigFile.cs | 32 ++--- sdk/dotnet/Yaml/ConfigGroup.cs | 5 +- sdk/dotnet/Yaml/Yaml.cs | 116 +++++++++++------- 12 files changed, 213 insertions(+), 207 deletions(-) diff --git a/provider/pkg/gen/dotnet-templates/helm/ChartBase.cs b/provider/pkg/gen/dotnet-templates/helm/ChartBase.cs index 769700566c..5b044f1dbb 100644 --- a/provider/pkg/gen/dotnet-templates/helm/ChartBase.cs +++ b/provider/pkg/gen/dotnet-templates/helm/ChartBase.cs @@ -139,7 +139,7 @@ protected ChartBase(string releaseName, Union args, C var yaml = ExecuteCommand("helm", flags); return ParseTemplate( - yaml, cfgBase.Transformations, cfgBase.ResourcePrefix, dependencies, cfgBase.Namespace, options?.Provider); + yaml, cfgBase.Transformations, cfgBase.ResourcePrefix, dependencies, cfgBase.Namespace, options); } catch (Exception e) { @@ -261,20 +261,20 @@ private void Fetch(string chart, ChartFetchArgsUnwrap opts) private Output> ParseTemplate(string text, List transformations, string? resourcePrefix, ImmutableHashSet dependsOn, - string? defaultNamespace, Pu.ProviderResource provider) + string? defaultNamespace, ComponentResourceOptions? options) { + var childOpts = GetChildOptions(this, dependsOn.ToArray(), options); + var invokeOpts = GetInvokeOptions(childOpts); return Yaml.Invokes - .YamlDecode(new YamlDecodeArgs { Text = text, DefaultNamespace = defaultNamespace }, new InvokeOptions { Provider = provider }) + .YamlDecode(new YamlDecodeArgs { Text = text, DefaultNamespace = defaultNamespace }, invokeOpts) .Apply(objs => { - var args = new ConfigGroupArgs + return Parser.ParseYamlObjects(new ParseArgs { - ResourcePrefix = resourcePrefix, Objs = objs, - Transformations = transformations - }; - var opts = new ComponentResourceOptions { Parent = this, DependsOn = dependsOn.ToArray(), Provider = provider }; - return Parser.Parse(args, opts); + Transformations = transformations, + ResourcePrefix = resourcePrefix + }, childOpts); }); } diff --git a/provider/pkg/gen/dotnet-templates/helm/v3/Chart.cs b/provider/pkg/gen/dotnet-templates/helm/v3/Chart.cs index e9a52eace1..d521f2ab40 100644 --- a/provider/pkg/gen/dotnet-templates/helm/v3/Chart.cs +++ b/provider/pkg/gen/dotnet-templates/helm/v3/Chart.cs @@ -359,8 +359,10 @@ private Output> ParseTemplate(Un } jsonOptsString = JsonSerializer.Serialize(jsonOpts, serializeOptions); + var childOpts = GetChildOptions(this, dependsOn.ToArray(), options); + var invokeOpts = GetInvokeOptions(childOpts); return Invokes - .HelmTemplate(new HelmTemplateArgs { JsonOpts = jsonOptsString }, new InvokeOptions { Provider = options?.Provider }) + .HelmTemplate(new HelmTemplateArgs { JsonOpts = jsonOptsString }, invokeOpts) .Apply(objs => { var transformations = cfgBase.Transformations; @@ -368,14 +370,12 @@ private Output> ParseTemplate(Un { transformations = transformations.Append(Parser.SkipAwait).ToList(); } - var args = new ConfigGroupArgs + return Parser.ParseYamlObjects(new ParseArgs { - ResourcePrefix = cfgBase.ResourcePrefix, Objs = objs, - Transformations = transformations - }; - var opts = new ComponentResourceOptions { Parent = this, DependsOn = dependsOn.ToArray(), Provider = options?.Provider }; - return Parser.Parse(args, opts); + Transformations = transformations, + ResourcePrefix = cfgBase.ResourcePrefix + }, childOpts); }); } diff --git a/provider/pkg/gen/dotnet-templates/kustomize/Directory.cs b/provider/pkg/gen/dotnet-templates/kustomize/Directory.cs index b88522e147..5944ae7c32 100644 --- a/provider/pkg/gen/dotnet-templates/kustomize/Directory.cs +++ b/provider/pkg/gen/dotnet-templates/kustomize/Directory.cs @@ -141,27 +141,19 @@ public sealed class Directory : CollectionComponentResource public Directory(string name, DirectoryArgs args, ComponentResourceOptions? options = null) : base("kubernetes:kustomize:Directory", MakeName(args, name), options) { - name = GetName(args, name); - var objs = Invokes.KustomizeDirectory(new KustomizeDirectoryArgs { Directory = args.Directory }, new InvokeOptions { Provider = options?.Provider }); - var configGroupArgs = new ConfigGroupArgs - { - ResourcePrefix = args.ResourcePrefix, - Objs = objs, - Transformations = args.Transformations - }; - var opts = ComponentResourceOptions.Merge(options, new ComponentResourceOptions { Parent = this }); - var resources = Parser.Parse(configGroupArgs, opts); + var childOpts = GetChildOptions(this, null, options); + var invokeOpts = GetInvokeOptions(childOpts); + var objs = Invokes.KustomizeDirectory(new KustomizeDirectoryArgs { Directory = args.Directory }, invokeOpts); + var resources = Parser.ParseYamlObjects(new ParseArgs + { + Objs = objs, + Transformations = args.Transformations, + ResourcePrefix = args.ResourcePrefix + }, childOpts); RegisterResources(resources); } private static string MakeName(DirectoryArgs? args, string name) => args?.ResourcePrefix != null ? $"{args.ResourcePrefix}-{name}" : name; - - private static string GetName(DirectoryArgs config, string releaseName) - { - var prefix = config.ResourcePrefix; - return string.IsNullOrEmpty(prefix) ? releaseName : $"{prefix}-{releaseName}"; - } - } /// diff --git a/provider/pkg/gen/dotnet-templates/yaml/ConfigFile.cs b/provider/pkg/gen/dotnet-templates/yaml/ConfigFile.cs index eec1e671e4..a984608bc0 100644 --- a/provider/pkg/gen/dotnet-templates/yaml/ConfigFile.cs +++ b/provider/pkg/gen/dotnet-templates/yaml/ConfigFile.cs @@ -125,39 +125,25 @@ public ConfigFile(string name, ConfigFileArgs? args = null, ComponentResourceOpt : base("kubernetes:yaml:ConfigFile", MakeName(args, name), options) { name = MakeName(args, name); - options ??= new ComponentResourceOptions(); - options.Parent ??= this; - - var transformations = args?.Transformations ?? new List(); - if (args?.SkipAwait == true) - { - transformations.Add(Parser.SkipAwait); - } + var fileOutput = args?.File.ToOutput() ?? Output.Create(name); + var childOpts = GetChildOptions(this, null, options); var resources = fileOutput.Apply(fileId => { try { - if (Parser.IsUrl(fileId)) - { - using var wc = new System.Net.WebClient(); - return wc.DownloadString(fileId); - } - - return File.ReadAllText(fileId); + return Parser.Parse(new ConfigGroupArgs{ + Files = new string[]{ fileId }, + Transformations = args?.Transformations ?? new List(), + ResourcePrefix = args?.ResourcePrefix, + SkipAwait = args?.SkipAwait + }, false, childOpts); } catch (Exception e) { throw new ResourceException($"Error fetching YAML file '{fileId}': {e.Message}", this); } - }).Apply(text => - Parser.ParseYamlDocument(new ParseArgs - { - Objs = Invokes.YamlDecode(new YamlDecodeArgs { Text = text }, new InvokeOptions { Provider = options?.Provider }), - Transformations = transformations, - ResourcePrefix = args?.ResourcePrefix - }, options)); - + }); RegisterResources(resources); } diff --git a/provider/pkg/gen/dotnet-templates/yaml/ConfigGroup.cs b/provider/pkg/gen/dotnet-templates/yaml/ConfigGroup.cs index 8d55c260fd..ac7409f809 100644 --- a/provider/pkg/gen/dotnet-templates/yaml/ConfigGroup.cs +++ b/provider/pkg/gen/dotnet-templates/yaml/ConfigGroup.cs @@ -205,9 +205,8 @@ public sealed class ConfigGroup : CollectionComponentResource public ConfigGroup(string name, ConfigGroupArgs config, ComponentResourceOptions? options = null) : base("kubernetes:yaml:ConfigGroup", name, options) { - options ??= new ComponentResourceOptions(); - options.Parent ??= this; - RegisterResources(Parser.Parse(config, options)); + var childOpts = GetChildOptions(this, null, options); + RegisterResources(Parser.Parse(config, true, childOpts)); } } diff --git a/provider/pkg/gen/dotnet-templates/yaml/yaml.tmpl b/provider/pkg/gen/dotnet-templates/yaml/yaml.tmpl index 307bac8a22..f78b4a5145 100644 --- a/provider/pkg/gen/dotnet-templates/yaml/yaml.tmpl +++ b/provider/pkg/gen/dotnet-templates/yaml/yaml.tmpl @@ -100,61 +100,95 @@ namespace Pulumi.Kubernetes.Yaml var id = namespaceName != null ? $"{namespaceName}/{name}" : name; return Resources.Apply(r => (CustomResource)r[$"{groupVersionKind}::{id}"]); } + + protected static CustomResourceOptions GetChildOptions(Pu.Resource parent, InputList? extraDependsOn, ComponentResourceOptions? options) + { + // Create resource options based on component resource options. + var dependsOn = new InputList(); + if (options?.DependsOn is not null) + dependsOn.AddRange(options.DependsOn); + if (extraDependsOn is not null) + dependsOn.AddRange(extraDependsOn); + return new CustomResourceOptions + { + Parent = parent, + DependsOn = dependsOn, + }; + } + + protected internal static InvokeOptions GetInvokeOptions(CustomResourceOptions? options) + { + return new InvokeOptions { + Parent = options?.Parent, + Provider = options?.Provider, + Version = options?.Version, + PluginDownloadURL = options?.PluginDownloadURL, + }.WithDefaults(); + } } internal static class Parser { - public static Output> Parse(ConfigGroupArgs config, ComponentResourceOptions? options) + public static Output> Parse(ConfigGroupArgs config, bool glob, CustomResourceOptions? opts) { var resources = Output.Create(ImmutableDictionary.Create()); var transformations = config.Transformations; - if (config?.SkipAwait == true) + if (config.SkipAwait == true) { transformations.Add(SkipAwait); } + var yamls = new InputList(); + if (config.Yaml != null) + yamls.AddRange(config.Yaml); + if (config.Files != null) { - var files = new List(); foreach (var file in config.Files) { + // Read the raw YAML file(s) specified in the input file parameter. It might be a URL or a file path. if (IsUrl(file)) - files.Add(file); - else - files.AddRange(Glob.Files(Directory.GetCurrentDirectory(), file)); - } - - foreach (var file in files) - { - var cf = new ConfigFile( - file, - new ConfigFileArgs + { + // If the string looks like a URL, in that it begins with a scheme, fetch it over the network. + using var wc = new System.Net.WebClient(); + var yaml = wc.DownloadString(file); + yamls.Add(yaml); + } + else + { + // Otherwise, assume this is a path to a file on disk. If globbing is enabled, we might have + // multiple files -- otherwise just read a singular file. + var files = new List(); + if (glob) + files.AddRange(Glob.Files(Directory.GetCurrentDirectory(), file)); + else + files.Add(file); + foreach (var fileId in files) { - File = file, - Transformations = transformations, - ResourcePrefix = config.ResourcePrefix - }, - options); - resources = Output.Tuple(resources, cf.Resources).Apply(vs => vs.Item1.AddRange(vs.Item2)); + var yaml = File.ReadAllText(fileId); + yamls.Add(yaml); + } + } } } - if (config.Yaml != null) + if (yamls is not null) { - var yamlResources = config.Yaml.ToOutput().Apply(texts => + var invokeOpts = CollectionComponentResource.GetInvokeOptions(opts); + var yamlResources = yamls.ToOutput().Apply(texts => { - var yamls = texts + var r = texts .Select(text => - ParseYamlDocument(new ParseArgs + ParseYamlObjects(new ParseArgs { - Objs = Invokes.YamlDecode(new YamlDecodeArgs { Text = text }, new InvokeOptions { Provider = options?.Provider }), + Objs = Invokes.YamlDecode(new YamlDecodeArgs { Text = text }, invokeOpts), Transformations = transformations, - ResourcePrefix = config.ResourcePrefix - }, options)) + ResourcePrefix = config?.ResourcePrefix + }, opts)) .Select(output => (Input>)output) .ToImmutableArray(); - return Output.All(yamls); + return Output.All(r); }); resources = Output.Tuple(resources, yamlResources).Apply(vs => @@ -169,12 +203,12 @@ namespace Pulumi.Kubernetes.Yaml if (config.Objs != null) { - var docResources = ParseYamlDocument(new ParseArgs + var docResources = ParseYamlObjects(new ParseArgs { Objs = config.Objs, Transformations = transformations, ResourcePrefix = config.ResourcePrefix - }, options); + }, opts); resources = Output.Tuple(resources, docResources).Apply(vs => vs.Item1.AddRange(vs.Item2)); } @@ -206,14 +240,14 @@ namespace Pulumi.Kubernetes.Yaml internal static bool IsUrl(string s) => s.StartsWith("http://", StringComparison.Ordinal) || s.StartsWith("https://", StringComparison.Ordinal); - internal static Output> ParseYamlDocument(ParseArgs config, - ComponentResourceOptions? options = null) + internal static Output> ParseYamlObjects(ParseArgs config, + CustomResourceOptions? opts) { return config.Objs.ToOutput().Apply(objs => { var inputs = objs - .SelectMany(obj => ParseYamlObject(obj, config.Transformations, config.ResourcePrefix, options)) + .SelectMany(obj => ParseYamlObject(obj, config.Transformations, config.ResourcePrefix, opts)) .Select(output => (Input<(string, KubernetesResource)>) output) .ToImmutableArray(); @@ -225,21 +259,13 @@ namespace Pulumi.Kubernetes.Yaml } private static Output<(string, KubernetesResource)>[] ParseYamlObject(ImmutableDictionary obj, - List? transformations, string? resourcePrefix, ComponentResourceOptions? options = null) + List? transformations, string? resourcePrefix, CustomResourceOptions? opts) { if (obj == null || obj.Count == 0) return new Output<(string, KubernetesResource)>[0]; - // Create custom resource options based on component resource options. - var opts = new CustomResourceOptions - { - Parent = options?.Parent, - DependsOn = options?.DependsOn ?? new InputList(), - IgnoreChanges = options?.IgnoreChanges ?? new List(), - Version = options?.Version, - Provider = options?.Provider, - CustomTimeouts = options?.CustomTimeouts - }; + // Create a copy of opts to pass into potentially mutating transforms that will be applied to this resource. + opts = CustomResourceOptions.Merge(null, opts); // Allow users to change API objects before any validation. if (transformations != null) @@ -281,7 +307,7 @@ namespace Pulumi.Kubernetes.Yaml if (obj["items"] is IEnumerable> items) { foreach (var item in items) - objs.AddRange(Parser.ParseYamlObject(item, transformations, resourcePrefix)); + objs.AddRange(Parser.ParseYamlObject(item, transformations, resourcePrefix, opts)); } return objs.ToArray(); } diff --git a/sdk/dotnet/Helm/ChartBase.cs b/sdk/dotnet/Helm/ChartBase.cs index 769700566c..5b044f1dbb 100644 --- a/sdk/dotnet/Helm/ChartBase.cs +++ b/sdk/dotnet/Helm/ChartBase.cs @@ -139,7 +139,7 @@ protected ChartBase(string releaseName, Union args, C var yaml = ExecuteCommand("helm", flags); return ParseTemplate( - yaml, cfgBase.Transformations, cfgBase.ResourcePrefix, dependencies, cfgBase.Namespace, options?.Provider); + yaml, cfgBase.Transformations, cfgBase.ResourcePrefix, dependencies, cfgBase.Namespace, options); } catch (Exception e) { @@ -261,20 +261,20 @@ private void Fetch(string chart, ChartFetchArgsUnwrap opts) private Output> ParseTemplate(string text, List transformations, string? resourcePrefix, ImmutableHashSet dependsOn, - string? defaultNamespace, Pu.ProviderResource provider) + string? defaultNamespace, ComponentResourceOptions? options) { + var childOpts = GetChildOptions(this, dependsOn.ToArray(), options); + var invokeOpts = GetInvokeOptions(childOpts); return Yaml.Invokes - .YamlDecode(new YamlDecodeArgs { Text = text, DefaultNamespace = defaultNamespace }, new InvokeOptions { Provider = provider }) + .YamlDecode(new YamlDecodeArgs { Text = text, DefaultNamespace = defaultNamespace }, invokeOpts) .Apply(objs => { - var args = new ConfigGroupArgs + return Parser.ParseYamlObjects(new ParseArgs { - ResourcePrefix = resourcePrefix, Objs = objs, - Transformations = transformations - }; - var opts = new ComponentResourceOptions { Parent = this, DependsOn = dependsOn.ToArray(), Provider = provider }; - return Parser.Parse(args, opts); + Transformations = transformations, + ResourcePrefix = resourcePrefix + }, childOpts); }); } diff --git a/sdk/dotnet/Helm/V3/Chart.cs b/sdk/dotnet/Helm/V3/Chart.cs index e9a52eace1..d521f2ab40 100644 --- a/sdk/dotnet/Helm/V3/Chart.cs +++ b/sdk/dotnet/Helm/V3/Chart.cs @@ -359,8 +359,10 @@ private Output> ParseTemplate(Un } jsonOptsString = JsonSerializer.Serialize(jsonOpts, serializeOptions); + var childOpts = GetChildOptions(this, dependsOn.ToArray(), options); + var invokeOpts = GetInvokeOptions(childOpts); return Invokes - .HelmTemplate(new HelmTemplateArgs { JsonOpts = jsonOptsString }, new InvokeOptions { Provider = options?.Provider }) + .HelmTemplate(new HelmTemplateArgs { JsonOpts = jsonOptsString }, invokeOpts) .Apply(objs => { var transformations = cfgBase.Transformations; @@ -368,14 +370,12 @@ private Output> ParseTemplate(Un { transformations = transformations.Append(Parser.SkipAwait).ToList(); } - var args = new ConfigGroupArgs + return Parser.ParseYamlObjects(new ParseArgs { - ResourcePrefix = cfgBase.ResourcePrefix, Objs = objs, - Transformations = transformations - }; - var opts = new ComponentResourceOptions { Parent = this, DependsOn = dependsOn.ToArray(), Provider = options?.Provider }; - return Parser.Parse(args, opts); + Transformations = transformations, + ResourcePrefix = cfgBase.ResourcePrefix + }, childOpts); }); } diff --git a/sdk/dotnet/Kustomize/Directory.cs b/sdk/dotnet/Kustomize/Directory.cs index b88522e147..5944ae7c32 100644 --- a/sdk/dotnet/Kustomize/Directory.cs +++ b/sdk/dotnet/Kustomize/Directory.cs @@ -141,27 +141,19 @@ public sealed class Directory : CollectionComponentResource public Directory(string name, DirectoryArgs args, ComponentResourceOptions? options = null) : base("kubernetes:kustomize:Directory", MakeName(args, name), options) { - name = GetName(args, name); - var objs = Invokes.KustomizeDirectory(new KustomizeDirectoryArgs { Directory = args.Directory }, new InvokeOptions { Provider = options?.Provider }); - var configGroupArgs = new ConfigGroupArgs - { - ResourcePrefix = args.ResourcePrefix, - Objs = objs, - Transformations = args.Transformations - }; - var opts = ComponentResourceOptions.Merge(options, new ComponentResourceOptions { Parent = this }); - var resources = Parser.Parse(configGroupArgs, opts); + var childOpts = GetChildOptions(this, null, options); + var invokeOpts = GetInvokeOptions(childOpts); + var objs = Invokes.KustomizeDirectory(new KustomizeDirectoryArgs { Directory = args.Directory }, invokeOpts); + var resources = Parser.ParseYamlObjects(new ParseArgs + { + Objs = objs, + Transformations = args.Transformations, + ResourcePrefix = args.ResourcePrefix + }, childOpts); RegisterResources(resources); } private static string MakeName(DirectoryArgs? args, string name) => args?.ResourcePrefix != null ? $"{args.ResourcePrefix}-{name}" : name; - - private static string GetName(DirectoryArgs config, string releaseName) - { - var prefix = config.ResourcePrefix; - return string.IsNullOrEmpty(prefix) ? releaseName : $"{prefix}-{releaseName}"; - } - } /// diff --git a/sdk/dotnet/Yaml/ConfigFile.cs b/sdk/dotnet/Yaml/ConfigFile.cs index eec1e671e4..a984608bc0 100644 --- a/sdk/dotnet/Yaml/ConfigFile.cs +++ b/sdk/dotnet/Yaml/ConfigFile.cs @@ -125,39 +125,25 @@ public ConfigFile(string name, ConfigFileArgs? args = null, ComponentResourceOpt : base("kubernetes:yaml:ConfigFile", MakeName(args, name), options) { name = MakeName(args, name); - options ??= new ComponentResourceOptions(); - options.Parent ??= this; - - var transformations = args?.Transformations ?? new List(); - if (args?.SkipAwait == true) - { - transformations.Add(Parser.SkipAwait); - } + var fileOutput = args?.File.ToOutput() ?? Output.Create(name); + var childOpts = GetChildOptions(this, null, options); var resources = fileOutput.Apply(fileId => { try { - if (Parser.IsUrl(fileId)) - { - using var wc = new System.Net.WebClient(); - return wc.DownloadString(fileId); - } - - return File.ReadAllText(fileId); + return Parser.Parse(new ConfigGroupArgs{ + Files = new string[]{ fileId }, + Transformations = args?.Transformations ?? new List(), + ResourcePrefix = args?.ResourcePrefix, + SkipAwait = args?.SkipAwait + }, false, childOpts); } catch (Exception e) { throw new ResourceException($"Error fetching YAML file '{fileId}': {e.Message}", this); } - }).Apply(text => - Parser.ParseYamlDocument(new ParseArgs - { - Objs = Invokes.YamlDecode(new YamlDecodeArgs { Text = text }, new InvokeOptions { Provider = options?.Provider }), - Transformations = transformations, - ResourcePrefix = args?.ResourcePrefix - }, options)); - + }); RegisterResources(resources); } diff --git a/sdk/dotnet/Yaml/ConfigGroup.cs b/sdk/dotnet/Yaml/ConfigGroup.cs index 8d55c260fd..ac7409f809 100644 --- a/sdk/dotnet/Yaml/ConfigGroup.cs +++ b/sdk/dotnet/Yaml/ConfigGroup.cs @@ -205,9 +205,8 @@ public sealed class ConfigGroup : CollectionComponentResource public ConfigGroup(string name, ConfigGroupArgs config, ComponentResourceOptions? options = null) : base("kubernetes:yaml:ConfigGroup", name, options) { - options ??= new ComponentResourceOptions(); - options.Parent ??= this; - RegisterResources(Parser.Parse(config, options)); + var childOpts = GetChildOptions(this, null, options); + RegisterResources(Parser.Parse(config, true, childOpts)); } } diff --git a/sdk/dotnet/Yaml/Yaml.cs b/sdk/dotnet/Yaml/Yaml.cs index 20178c613b..faeeb52f61 100755 --- a/sdk/dotnet/Yaml/Yaml.cs +++ b/sdk/dotnet/Yaml/Yaml.cs @@ -821,61 +821,95 @@ public Output GetCustomResource(string groupVersionKind, string var id = namespaceName != null ? $"{namespaceName}/{name}" : name; return Resources.Apply(r => (CustomResource)r[$"{groupVersionKind}::{id}"]); } + + protected static CustomResourceOptions GetChildOptions(Pu.Resource parent, InputList? extraDependsOn, ComponentResourceOptions? options) + { + // Create resource options based on component resource options. + var dependsOn = new InputList(); + if (options?.DependsOn is not null) + dependsOn.AddRange(options.DependsOn); + if (extraDependsOn is not null) + dependsOn.AddRange(extraDependsOn); + return new CustomResourceOptions + { + Parent = parent, + DependsOn = dependsOn, + }; + } + + protected internal static InvokeOptions GetInvokeOptions(CustomResourceOptions? options) + { + return new InvokeOptions { + Parent = options?.Parent, + Provider = options?.Provider, + Version = options?.Version, + PluginDownloadURL = options?.PluginDownloadURL, + }.WithDefaults(); + } } internal static class Parser { - public static Output> Parse(ConfigGroupArgs config, ComponentResourceOptions? options) + public static Output> Parse(ConfigGroupArgs config, bool glob, CustomResourceOptions? opts) { var resources = Output.Create(ImmutableDictionary.Create()); var transformations = config.Transformations; - if (config?.SkipAwait == true) + if (config.SkipAwait == true) { transformations.Add(SkipAwait); } + var yamls = new InputList(); + if (config.Yaml != null) + yamls.AddRange(config.Yaml); + if (config.Files != null) { - var files = new List(); foreach (var file in config.Files) { + // Read the raw YAML file(s) specified in the input file parameter. It might be a URL or a file path. if (IsUrl(file)) - files.Add(file); - else - files.AddRange(Glob.Files(Directory.GetCurrentDirectory(), file)); - } - - foreach (var file in files) - { - var cf = new ConfigFile( - file, - new ConfigFileArgs - { - File = file, - Transformations = transformations, - ResourcePrefix = config.ResourcePrefix - }, - options); - resources = Output.Tuple(resources, cf.Resources).Apply(vs => vs.Item1.AddRange(vs.Item2)); + { + // If the string looks like a URL, in that it begins with a scheme, fetch it over the network. + using var wc = new System.Net.WebClient(); + var yaml = wc.DownloadString(file); + yamls.Add(yaml); + } + else + { + // Otherwise, assume this is a path to a file on disk. If globbing is enabled, we might have + // multiple files -- otherwise just read a singular file. + var files = new List(); + if (glob) + files.AddRange(Glob.Files(Directory.GetCurrentDirectory(), file)); + else + files.Add(file); + foreach (var fileId in files) + { + var yaml = File.ReadAllText(fileId); + yamls.Add(yaml); + } + } } } - if (config.Yaml != null) + if (yamls is not null) { - var yamlResources = config.Yaml.ToOutput().Apply(texts => + var invokeOpts = CollectionComponentResource.GetInvokeOptions(opts); + var yamlResources = yamls.ToOutput().Apply(texts => { - var yamls = texts + var r = texts .Select(text => - ParseYamlDocument(new ParseArgs + ParseYamlObjects(new ParseArgs { - Objs = Invokes.YamlDecode(new YamlDecodeArgs { Text = text }, new InvokeOptions { Provider = options?.Provider }), + Objs = Invokes.YamlDecode(new YamlDecodeArgs { Text = text }, invokeOpts), Transformations = transformations, - ResourcePrefix = config.ResourcePrefix - }, options)) + ResourcePrefix = config?.ResourcePrefix + }, opts)) .Select(output => (Input>)output) .ToImmutableArray(); - return Output.All(yamls); + return Output.All(r); }); resources = Output.Tuple(resources, yamlResources).Apply(vs => @@ -890,12 +924,12 @@ public static Output> Parse(Conf if (config.Objs != null) { - var docResources = ParseYamlDocument(new ParseArgs + var docResources = ParseYamlObjects(new ParseArgs { Objs = config.Objs, Transformations = transformations, ResourcePrefix = config.ResourcePrefix - }, options); + }, opts); resources = Output.Tuple(resources, docResources).Apply(vs => vs.Item1.AddRange(vs.Item2)); } @@ -927,14 +961,14 @@ internal static ImmutableDictionary SkipAwait(ImmutableDictionar internal static bool IsUrl(string s) => s.StartsWith("http://", StringComparison.Ordinal) || s.StartsWith("https://", StringComparison.Ordinal); - internal static Output> ParseYamlDocument(ParseArgs config, - ComponentResourceOptions? options = null) + internal static Output> ParseYamlObjects(ParseArgs config, + CustomResourceOptions? opts) { return config.Objs.ToOutput().Apply(objs => { var inputs = objs - .SelectMany(obj => ParseYamlObject(obj, config.Transformations, config.ResourcePrefix, options)) + .SelectMany(obj => ParseYamlObject(obj, config.Transformations, config.ResourcePrefix, opts)) .Select(output => (Input<(string, KubernetesResource)>) output) .ToImmutableArray(); @@ -946,21 +980,13 @@ internal static Output> ParseYam } private static Output<(string, KubernetesResource)>[] ParseYamlObject(ImmutableDictionary obj, - List? transformations, string? resourcePrefix, ComponentResourceOptions? options = null) + List? transformations, string? resourcePrefix, CustomResourceOptions? opts) { if (obj == null || obj.Count == 0) return new Output<(string, KubernetesResource)>[0]; - // Create custom resource options based on component resource options. - var opts = new CustomResourceOptions - { - Parent = options?.Parent, - DependsOn = options?.DependsOn ?? new InputList(), - IgnoreChanges = options?.IgnoreChanges ?? new List(), - Version = options?.Version, - Provider = options?.Provider, - CustomTimeouts = options?.CustomTimeouts - }; + // Create a copy of opts to pass into potentially mutating transforms that will be applied to this resource. + opts = CustomResourceOptions.Merge(null, opts); // Allow users to change API objects before any validation. if (transformations != null) @@ -1119,7 +1145,7 @@ internal static Output> ParseYam if (obj["items"] is IEnumerable> items) { foreach (var item in items) - objs.AddRange(Parser.ParseYamlObject(item, transformations, resourcePrefix)); + objs.AddRange(Parser.ParseYamlObject(item, transformations, resourcePrefix, opts)); } return objs.ToArray(); } From 1493161f96d66f57da3ac4f7be6911916b0a3f87 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Wed, 29 Nov 2023 22:44:13 -0800 Subject: [PATCH 09/31] python SDK fixes --- .../pkg/gen/python-templates/kustomize/kustomize.py | 2 +- sdk/python/pulumi_kubernetes/helm/v3/helm.py | 2 +- sdk/python/pulumi_kubernetes/kustomize/kustomize.py | 2 +- sdk/python/pulumi_kubernetes/yaml/yaml.py | 11 +++++------ 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/provider/pkg/gen/python-templates/kustomize/kustomize.py b/provider/pkg/gen/python-templates/kustomize/kustomize.py index 618668c8b2..005a05758e 100644 --- a/provider/pkg/gen/python-templates/kustomize/kustomize.py +++ b/provider/pkg/gen/python-templates/kustomize/kustomize.py @@ -122,7 +122,7 @@ def omit_resource(obj, opts): # Note: Unlike NodeJS, Python requires that we "pull" on our futures in order to get them scheduled for # execution. In order to do this, we leverage the engine's RegisterResourceOutputs to wait for the # resolution of all resources that this YAML document created. - self.resources = k8s.yaml.yaml._parse_yaml_document(result, child_opts, transformations, resource_prefix) + self.resources = _parse_yaml_document(result, child_opts, transformations, resource_prefix) self.register_outputs({"resources": self.resources}) def translate_output_property(self, prop: str) -> str: diff --git a/sdk/python/pulumi_kubernetes/helm/v3/helm.py b/sdk/python/pulumi_kubernetes/helm/v3/helm.py index 6712485cb0..16faf50d84 100644 --- a/sdk/python/pulumi_kubernetes/helm/v3/helm.py +++ b/sdk/python/pulumi_kubernetes/helm/v3/helm.py @@ -589,7 +589,7 @@ def _parse_chart(all_config: Tuple[Union[ChartOpts, LocalChartOpts], pulumi.Reso json_opts = config.to_json() invoke_opts = _get_invoke_options(opts) - + transformations = config.transformations if config.transformations is not None else [] if config.skip_await: transformations.append(_skip_await) diff --git a/sdk/python/pulumi_kubernetes/kustomize/kustomize.py b/sdk/python/pulumi_kubernetes/kustomize/kustomize.py index 21efa5b1f9..005a05758e 100644 --- a/sdk/python/pulumi_kubernetes/kustomize/kustomize.py +++ b/sdk/python/pulumi_kubernetes/kustomize/kustomize.py @@ -111,7 +111,7 @@ def omit_resource(obj, opts): child_opts = _get_child_options(self, opts) invoke_opts = _get_invoke_options(child_opts) - + __ret__ = pulumi.runtime.invoke( 'kubernetes:kustomize:directory', {'directory': directory}, invoke_opts) diff --git a/sdk/python/pulumi_kubernetes/yaml/yaml.py b/sdk/python/pulumi_kubernetes/yaml/yaml.py index 0082efc850..4715b28868 100644 --- a/sdk/python/pulumi_kubernetes/yaml/yaml.py +++ b/sdk/python/pulumi_kubernetes/yaml/yaml.py @@ -335,7 +335,7 @@ def omit_resource(obj, opts): transformations = transformations if transformations is not None else [] if skip_await: transformations.append(_skip_await) - + invoke_opts = _get_invoke_options(child_opts) __ret__ = invoke_yaml_decode(text, invoke_opts) @@ -399,6 +399,9 @@ def _read_file(path: str) -> str: return data +def _build_resources_dict(objs: Sequence[pulumi.Output]) -> Mapping[pulumi.Output, pulumi.Output]: + return {key: value for key, value in objs} + def _get_child_options(parent: pulumi.Resource, opts: pulumi.ResourceOptions): return pulumi.ResourceOptions(parent=parent, depends_on=opts.depends_on) @@ -409,11 +412,7 @@ def _get_invoke_options(opts: pulumi.ResourceOptions): version=_utilities.get_version() if not opts.version else opts.version, plugin_download_url=opts.plugin_download_url if opts.plugin_download_url else None ) - -def _build_resources_dict(objs: Sequence[pulumi.Output]) -> Mapping[pulumi.Output, pulumi.Output]: - return {key: value for key, value in objs} - - + def _parse_yaml_document( objects, opts: Optional[pulumi.ResourceOptions] = None, transformations: Optional[Sequence[Callable]] = None, From 11f3ce9809315c9daac7bd22e012742e9df64bc3 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Thu, 30 Nov 2023 08:53:56 -0800 Subject: [PATCH 10/31] bugfix (python) --- provider/pkg/gen/python-templates/yaml/yaml.tmpl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/provider/pkg/gen/python-templates/yaml/yaml.tmpl b/provider/pkg/gen/python-templates/yaml/yaml.tmpl index d1425dd586..82976c2307 100644 --- a/provider/pkg/gen/python-templates/yaml/yaml.tmpl +++ b/provider/pkg/gen/python-templates/yaml/yaml.tmpl @@ -403,9 +403,13 @@ def _build_resources_dict(objs: Sequence[pulumi.Output]) -> Mapping[pulumi.Outpu return {key: value for key, value in objs} def _get_child_options(parent: pulumi.Resource, opts: pulumi.ResourceOptions): + if not opts: + opts = pulumi.ResourceOptions() return pulumi.ResourceOptions(parent=parent, depends_on=opts.depends_on) def _get_invoke_options(opts: pulumi.ResourceOptions): + if not opts: + opts = pulumi.ResourceOptions() return pulumi.InvokeOptions( parent=opts.parent if opts.parent else None, provider=opts.provider if opts.provider else None, From 4835df7c0bcf4eb3627f54c76369b2b4ba550426 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Thu, 30 Nov 2023 11:39:56 -0800 Subject: [PATCH 11/31] bugfix (python; configgroup) --- provider/pkg/gen/python-templates/yaml/yaml.tmpl | 2 +- sdk/python/pulumi_kubernetes/yaml/yaml.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/provider/pkg/gen/python-templates/yaml/yaml.tmpl b/provider/pkg/gen/python-templates/yaml/yaml.tmpl index 82976c2307..da0150d358 100644 --- a/provider/pkg/gen/python-templates/yaml/yaml.tmpl +++ b/provider/pkg/gen/python-templates/yaml/yaml.tmpl @@ -190,7 +190,7 @@ class ConfigGroup(pulumi.ComponentResource): for text in yaml: invoke_opts = _get_invoke_options(child_opts) __ret__ = invoke_yaml_decode(text, invoke_opts) - resources = _parse_yaml_document(__ret__, opts, transformations, resource_prefix) + resources = _parse_yaml_document(__ret__, child_opts, transformations, resource_prefix) # Add any new YAML resources to the ConfigGroup's resources self.resources = pulumi.Output.all(resources, self.resources).apply(lambda x: {**x[0], **x[1]}) diff --git a/sdk/python/pulumi_kubernetes/yaml/yaml.py b/sdk/python/pulumi_kubernetes/yaml/yaml.py index 4715b28868..d9acc68cea 100644 --- a/sdk/python/pulumi_kubernetes/yaml/yaml.py +++ b/sdk/python/pulumi_kubernetes/yaml/yaml.py @@ -190,7 +190,7 @@ def omit_resource(obj, opts): for text in yaml: invoke_opts = _get_invoke_options(child_opts) __ret__ = invoke_yaml_decode(text, invoke_opts) - resources = _parse_yaml_document(__ret__, opts, transformations, resource_prefix) + resources = _parse_yaml_document(__ret__, child_opts, transformations, resource_prefix) # Add any new YAML resources to the ConfigGroup's resources self.resources = pulumi.Output.all(resources, self.resources).apply(lambda x: {**x[0], **x[1]}) From c58b74e9d098625f3a15f2fd0c938fe289fc33f8 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Thu, 30 Nov 2023 11:43:27 -0800 Subject: [PATCH 12/31] bugfix (Python) --- sdk/python/pulumi_kubernetes/yaml/yaml.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sdk/python/pulumi_kubernetes/yaml/yaml.py b/sdk/python/pulumi_kubernetes/yaml/yaml.py index d9acc68cea..e104a7a55e 100644 --- a/sdk/python/pulumi_kubernetes/yaml/yaml.py +++ b/sdk/python/pulumi_kubernetes/yaml/yaml.py @@ -403,9 +403,13 @@ def _build_resources_dict(objs: Sequence[pulumi.Output]) -> Mapping[pulumi.Outpu return {key: value for key, value in objs} def _get_child_options(parent: pulumi.Resource, opts: pulumi.ResourceOptions): + if not opts: + opts = pulumi.ResourceOptions() return pulumi.ResourceOptions(parent=parent, depends_on=opts.depends_on) def _get_invoke_options(opts: pulumi.ResourceOptions): + if not opts: + opts = pulumi.ResourceOptions() return pulumi.InvokeOptions( parent=opts.parent if opts.parent else None, provider=opts.provider if opts.provider else None, From be8967f92bd596ab55bd3e2d6b36607170573ef0 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Thu, 30 Nov 2023 15:59:10 -0800 Subject: [PATCH 13/31] bugfixes (go) --- provider/pkg/gen/_go-templates/helm/v3/chart.go | 10 +++++----- provider/pkg/gen/_go-templates/kustomize/directory.go | 9 ++------- provider/pkg/gen/_go-templates/yaml/configFile.go | 7 +------ provider/pkg/gen/_go-templates/yaml/configGroup.go | 5 ----- sdk/go/kubernetes/helm/v3/chart.go | 11 ++++++----- sdk/go/kubernetes/yaml/configFile.go | 5 ----- sdk/go/kubernetes/yaml/configGroup.go | 5 ----- 7 files changed, 14 insertions(+), 38 deletions(-) diff --git a/provider/pkg/gen/_go-templates/helm/v3/chart.go b/provider/pkg/gen/_go-templates/helm/v3/chart.go index b0fd9b1128..5e3b39b9bd 100644 --- a/provider/pkg/gen/_go-templates/helm/v3/chart.go +++ b/provider/pkg/gen/_go-templates/helm/v3/chart.go @@ -250,11 +250,6 @@ func NewChart(ctx *pulumi.Context, return nil, err } - // Honor the resource name prefix if specified. - if args.ResourcePrefix != "" { - name = args.ResourcePrefix + "-" + name - } - parseOpts, err := yaml.GetChildOptions(chart, opts) if err != nil { return nil, err @@ -296,6 +291,11 @@ func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi ReleaseName: name, } + // Honor the resource name prefix if specified. + if args.ResourcePrefix != "" { + jsonOpts.ReleaseName = args.ResourcePrefix + "-" + name + } + b, err := json.Marshal(jsonOpts) if err != nil { return nil, err diff --git a/provider/pkg/gen/_go-templates/kustomize/directory.go b/provider/pkg/gen/_go-templates/kustomize/directory.go index ca797a6058..069a3aeb2b 100644 --- a/provider/pkg/gen/_go-templates/kustomize/directory.go +++ b/provider/pkg/gen/_go-templates/kustomize/directory.go @@ -160,17 +160,12 @@ func NewDirectory(ctx *pulumi.Context, return nil, err } - // Honor the resource name prefix if specified. - if args.ResourcePrefix != "" { - name = args.ResourcePrefix + "-" + name - } - parseOpts, err := yaml.GetChildOptions(chart, opts) if err != nil { return nil, err } resources := args.ToDirectoryArgsOutput().ApplyT(func(args directoryArgs) (map[string]pulumi.Resource, error) { - return parseDirectory(ctx, name, args, parseOpts...) + return parseDirectory(ctx, args, parseOpts...) }) chart.Resources = resources @@ -185,7 +180,7 @@ func NewDirectory(ctx *pulumi.Context, return chart, nil } -func parseDirectory(ctx *pulumi.Context, name string, args directoryArgs, opts ...pulumi.ResourceOption, +func parseDirectory(ctx *pulumi.Context, args directoryArgs, opts ...pulumi.ResourceOption, ) (map[string]pulumi.Resource, error) { invokeArgs := struct { Directory string `pulumi:"directory"` diff --git a/provider/pkg/gen/_go-templates/yaml/configFile.go b/provider/pkg/gen/_go-templates/yaml/configFile.go index 48e429ac90..3a580f36d3 100644 --- a/provider/pkg/gen/_go-templates/yaml/configFile.go +++ b/provider/pkg/gen/_go-templates/yaml/configFile.go @@ -151,11 +151,6 @@ func NewConfigFile(ctx *pulumi.Context, // Now provision all child resources by parsing the YAML file. if args != nil { - // Honor the resource name prefix if specified. - if args.ResourcePrefix != "" { - name = args.ResourcePrefix + "-" + name - } - transformations := args.Transformations if args.SkipAwait { transformations = AddSkipAwaitTransformation(transformations) @@ -170,7 +165,7 @@ func NewConfigFile(ctx *pulumi.Context, Files: []string{args.File}, Transformations: args.Transformations, ResourcePrefix: args.ResourcePrefix, - }, true, parseOpts...) + }, false, parseOpts...) if err != nil { return nil, err } diff --git a/provider/pkg/gen/_go-templates/yaml/configGroup.go b/provider/pkg/gen/_go-templates/yaml/configGroup.go index 251086c053..02892e9734 100644 --- a/provider/pkg/gen/_go-templates/yaml/configGroup.go +++ b/provider/pkg/gen/_go-templates/yaml/configGroup.go @@ -283,11 +283,6 @@ func NewConfigGroup(ctx *pulumi.Context, // Now provision all child resources by parsing the YAML files. if args != nil { - // Honor the resource name prefix if specified. - if args.ResourcePrefix != "" { - name = args.ResourcePrefix + "-" + name - } - // Parse and decode the YAML files. parseOpts, err := GetChildOptions(configGroup, opts) if err != nil { diff --git a/sdk/go/kubernetes/helm/v3/chart.go b/sdk/go/kubernetes/helm/v3/chart.go index 4d74b3f441..5e3b39b9bd 100644 --- a/sdk/go/kubernetes/helm/v3/chart.go +++ b/sdk/go/kubernetes/helm/v3/chart.go @@ -243,17 +243,13 @@ func NewChart(ctx *pulumi.Context, Type: pulumi.String("kubernetes:helm.sh/v2:Chart"), }, }) + opts = append(opts, aliases) err := ctx.RegisterComponentResource("kubernetes:helm.sh/v3:Chart", name, chart, opts...) if err != nil { return nil, err } - // Honor the resource name prefix if specified. - if args.ResourcePrefix != "" { - name = args.ResourcePrefix + "-" + name - } - parseOpts, err := yaml.GetChildOptions(chart, opts) if err != nil { return nil, err @@ -295,6 +291,11 @@ func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi ReleaseName: name, } + // Honor the resource name prefix if specified. + if args.ResourcePrefix != "" { + jsonOpts.ReleaseName = args.ResourcePrefix + "-" + name + } + b, err := json.Marshal(jsonOpts) if err != nil { return nil, err diff --git a/sdk/go/kubernetes/yaml/configFile.go b/sdk/go/kubernetes/yaml/configFile.go index 576bbf9faf..3a580f36d3 100644 --- a/sdk/go/kubernetes/yaml/configFile.go +++ b/sdk/go/kubernetes/yaml/configFile.go @@ -151,11 +151,6 @@ func NewConfigFile(ctx *pulumi.Context, // Now provision all child resources by parsing the YAML file. if args != nil { - // Honor the resource name prefix if specified. - if args.ResourcePrefix != "" { - name = args.ResourcePrefix + "-" + name - } - transformations := args.Transformations if args.SkipAwait { transformations = AddSkipAwaitTransformation(transformations) diff --git a/sdk/go/kubernetes/yaml/configGroup.go b/sdk/go/kubernetes/yaml/configGroup.go index 251086c053..02892e9734 100644 --- a/sdk/go/kubernetes/yaml/configGroup.go +++ b/sdk/go/kubernetes/yaml/configGroup.go @@ -283,11 +283,6 @@ func NewConfigGroup(ctx *pulumi.Context, // Now provision all child resources by parsing the YAML files. if args != nil { - // Honor the resource name prefix if specified. - if args.ResourcePrefix != "" { - name = args.ResourcePrefix + "-" + name - } - // Parse and decode the YAML files. parseOpts, err := GetChildOptions(configGroup, opts) if err != nil { From 48a14b96b2eef846752f2e055c4fd598aed45552 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Thu, 30 Nov 2023 16:23:57 -0800 Subject: [PATCH 14/31] bugfixes (go sdk) --- provider/pkg/gen/_go-templates/helm/v3/chart.go | 16 ++++++++-------- sdk/go/kubernetes/helm/v3/chart.go | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/provider/pkg/gen/_go-templates/helm/v3/chart.go b/provider/pkg/gen/_go-templates/helm/v3/chart.go index 5e3b39b9bd..860883854f 100644 --- a/provider/pkg/gen/_go-templates/helm/v3/chart.go +++ b/provider/pkg/gen/_go-templates/helm/v3/chart.go @@ -250,12 +250,17 @@ func NewChart(ctx *pulumi.Context, return nil, err } + releaseName := name + if args.ResourcePrefix != "" { + releaseName = args.ResourcePrefix + "-" + name + } + parseOpts, err := yaml.GetChildOptions(chart, opts) if err != nil { return nil, err } resources := args.ToChartArgsOutput().ApplyT(func(args chartArgs) (map[string]pulumi.Resource, error) { - return parseChart(ctx, name, args, parseOpts...) + return parseChart(ctx, releaseName, args, parseOpts...) }) chart.Resources = resources @@ -279,7 +284,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, releaseName string, args chartArgs, opts ...pulumi.ResourceOption, ) (map[string]pulumi.Resource, error) { type jsonOptsArgs struct { chartArgs @@ -288,12 +293,7 @@ func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi } jsonOpts := jsonOptsArgs{ chartArgs: args, - ReleaseName: name, - } - - // Honor the resource name prefix if specified. - if args.ResourcePrefix != "" { - jsonOpts.ReleaseName = args.ResourcePrefix + "-" + name + ReleaseName: releaseName, } b, err := json.Marshal(jsonOpts) diff --git a/sdk/go/kubernetes/helm/v3/chart.go b/sdk/go/kubernetes/helm/v3/chart.go index 5e3b39b9bd..860883854f 100644 --- a/sdk/go/kubernetes/helm/v3/chart.go +++ b/sdk/go/kubernetes/helm/v3/chart.go @@ -250,12 +250,17 @@ func NewChart(ctx *pulumi.Context, return nil, err } + releaseName := name + if args.ResourcePrefix != "" { + releaseName = args.ResourcePrefix + "-" + name + } + parseOpts, err := yaml.GetChildOptions(chart, opts) if err != nil { return nil, err } resources := args.ToChartArgsOutput().ApplyT(func(args chartArgs) (map[string]pulumi.Resource, error) { - return parseChart(ctx, name, args, parseOpts...) + return parseChart(ctx, releaseName, args, parseOpts...) }) chart.Resources = resources @@ -279,7 +284,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, releaseName string, args chartArgs, opts ...pulumi.ResourceOption, ) (map[string]pulumi.Resource, error) { type jsonOptsArgs struct { chartArgs @@ -288,12 +293,7 @@ func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi } jsonOpts := jsonOptsArgs{ chartArgs: args, - ReleaseName: name, - } - - // Honor the resource name prefix if specified. - if args.ResourcePrefix != "" { - jsonOpts.ReleaseName = args.ResourcePrefix + "-" + name + ReleaseName: releaseName, } b, err := json.Marshal(jsonOpts) From 983868087fab516821f9683f10f571c99d7511e3 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 4 Dec 2023 10:34:21 -0800 Subject: [PATCH 15/31] dependency propagation fix (python) --- provider/pkg/gen/python-templates/yaml/yaml.tmpl | 2 +- sdk/python/pulumi_kubernetes/yaml/yaml.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/provider/pkg/gen/python-templates/yaml/yaml.tmpl b/provider/pkg/gen/python-templates/yaml/yaml.tmpl index da0150d358..361ca54613 100644 --- a/provider/pkg/gen/python-templates/yaml/yaml.tmpl +++ b/provider/pkg/gen/python-templates/yaml/yaml.tmpl @@ -405,7 +405,7 @@ def _build_resources_dict(objs: Sequence[pulumi.Output]) -> Mapping[pulumi.Outpu def _get_child_options(parent: pulumi.Resource, opts: pulumi.ResourceOptions): if not opts: opts = pulumi.ResourceOptions() - return pulumi.ResourceOptions(parent=parent, depends_on=opts.depends_on) + return pulumi.ResourceOptions(parent=parent) def _get_invoke_options(opts: pulumi.ResourceOptions): if not opts: diff --git a/sdk/python/pulumi_kubernetes/yaml/yaml.py b/sdk/python/pulumi_kubernetes/yaml/yaml.py index e104a7a55e..16e01402a4 100644 --- a/sdk/python/pulumi_kubernetes/yaml/yaml.py +++ b/sdk/python/pulumi_kubernetes/yaml/yaml.py @@ -405,7 +405,7 @@ def _build_resources_dict(objs: Sequence[pulumi.Output]) -> Mapping[pulumi.Outpu def _get_child_options(parent: pulumi.Resource, opts: pulumi.ResourceOptions): if not opts: opts = pulumi.ResourceOptions() - return pulumi.ResourceOptions(parent=parent, depends_on=opts.depends_on) + return pulumi.ResourceOptions(parent=parent) def _get_invoke_options(opts: pulumi.ResourceOptions): if not opts: From b5a06f8a736b30518267899dfb38a43fe0b99570 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 4 Dec 2023 10:44:50 -0800 Subject: [PATCH 16/31] dependency propagation fix (nodejs) --- provider/pkg/gen/nodejs-templates/yaml/yaml.tmpl | 1 - sdk/nodejs/helm/v3/helm.ts | 5 +++-- sdk/nodejs/kustomize/kustomize.ts | 5 +++-- sdk/nodejs/yaml/yaml.ts | 1 - 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/provider/pkg/gen/nodejs-templates/yaml/yaml.tmpl b/provider/pkg/gen/nodejs-templates/yaml/yaml.tmpl index ffa9cb8b7e..80b4fbd48a 100644 --- a/provider/pkg/gen/nodejs-templates/yaml/yaml.tmpl +++ b/provider/pkg/gen/nodejs-templates/yaml/yaml.tmpl @@ -388,7 +388,6 @@ export interface ConfigOpts { /** @ignore */ export function getChildOpts(parent: pulumi.Resource, opts?: pulumi.ComponentResourceOptions): pulumi.CustomResourceOptions { return { parent: parent, - dependsOn: opts?.dependsOn, }; } diff --git a/sdk/nodejs/helm/v3/helm.ts b/sdk/nodejs/helm/v3/helm.ts index 866af4e1ed..25a29789b1 100644 --- a/sdk/nodejs/helm/v3/helm.ts +++ b/sdk/nodejs/helm/v3/helm.ts @@ -238,8 +238,9 @@ export class Chart extends yaml.CollectionComponentResource { transformations.push(yaml.skipAwait); } - const childOpts = yaml.getChildOpts(this, opts) - const invokeOpts = yaml.getInvokeOpts(childOpts) + const childOpts = yaml.getChildOpts(this, opts); + const invokeOpts = yaml.getInvokeOpts(childOpts); + const promise = pulumi.runtime.invoke("kubernetes:helm:template", {jsonOpts}, invokeOpts); return pulumi.output(promise).apply<{ [key: string]: pulumi.CustomResource }>(p => yaml.parse( { diff --git a/sdk/nodejs/kustomize/kustomize.ts b/sdk/nodejs/kustomize/kustomize.ts index 5eb9937546..4309fdd02e 100644 --- a/sdk/nodejs/kustomize/kustomize.ts +++ b/sdk/nodejs/kustomize/kustomize.ts @@ -94,10 +94,11 @@ export class Directory extends yaml.CollectionComponentResource { } super("kubernetes:kustomize:Directory", name, config, opts); - const directory = config.directory - + const directory = config.directory; + const childOpts = yaml.getChildOpts(this, opts); const invokeOpts = yaml.getInvokeOpts(childOpts); + const promise = pulumi.runtime.invoke("kubernetes:kustomize:directory", {directory}, invokeOpts); this.resources = pulumi.output(promise).apply<{[key: string]: pulumi.CustomResource}>(p => yaml.parse( { diff --git a/sdk/nodejs/yaml/yaml.ts b/sdk/nodejs/yaml/yaml.ts index 7978121b17..4a850695e1 100644 --- a/sdk/nodejs/yaml/yaml.ts +++ b/sdk/nodejs/yaml/yaml.ts @@ -3135,7 +3135,6 @@ export interface ConfigOpts { /** @ignore */ export function getChildOpts(parent: pulumi.Resource, opts?: pulumi.ComponentResourceOptions): pulumi.CustomResourceOptions { return { parent: parent, - dependsOn: opts?.dependsOn, }; } From 8c31328fd87f7eb49610a59e69d9adbf059973a0 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 4 Dec 2023 10:49:07 -0800 Subject: [PATCH 17/31] dependency propagation fix (dotnet) --- provider/pkg/gen/dotnet-templates/yaml/yaml.tmpl | 2 -- sdk/dotnet/Yaml/Yaml.cs | 2 -- 2 files changed, 4 deletions(-) diff --git a/provider/pkg/gen/dotnet-templates/yaml/yaml.tmpl b/provider/pkg/gen/dotnet-templates/yaml/yaml.tmpl index f78b4a5145..de1f85789d 100644 --- a/provider/pkg/gen/dotnet-templates/yaml/yaml.tmpl +++ b/provider/pkg/gen/dotnet-templates/yaml/yaml.tmpl @@ -105,8 +105,6 @@ namespace Pulumi.Kubernetes.Yaml { // Create resource options based on component resource options. var dependsOn = new InputList(); - if (options?.DependsOn is not null) - dependsOn.AddRange(options.DependsOn); if (extraDependsOn is not null) dependsOn.AddRange(extraDependsOn); return new CustomResourceOptions diff --git a/sdk/dotnet/Yaml/Yaml.cs b/sdk/dotnet/Yaml/Yaml.cs index faeeb52f61..f3ff1a5767 100755 --- a/sdk/dotnet/Yaml/Yaml.cs +++ b/sdk/dotnet/Yaml/Yaml.cs @@ -826,8 +826,6 @@ protected static CustomResourceOptions GetChildOptions(Pu.Resource parent, Input { // Create resource options based on component resource options. var dependsOn = new InputList(); - if (options?.DependsOn is not null) - dependsOn.AddRange(options.DependsOn); if (extraDependsOn is not null) dependsOn.AddRange(extraDependsOn); return new CustomResourceOptions From 6d8c10ca08394ede553257c04c0a70e1b3370517 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 4 Dec 2023 10:50:58 -0800 Subject: [PATCH 18/31] dependency propagation fix (go) --- provider/pkg/gen/_go-templates/yaml/yaml.tmpl | 7 ------- sdk/go/kubernetes/yaml/yaml.go | 7 ------- 2 files changed, 14 deletions(-) diff --git a/provider/pkg/gen/_go-templates/yaml/yaml.tmpl b/provider/pkg/gen/_go-templates/yaml/yaml.tmpl index 778ba28691..e89e1a4d0c 100644 --- a/provider/pkg/gen/_go-templates/yaml/yaml.tmpl +++ b/provider/pkg/gen/_go-templates/yaml/yaml.tmpl @@ -35,14 +35,7 @@ import ( ) func GetChildOptions(parent pulumi.Resource, opts []pulumi.ResourceOption) ([]pulumi.ResourceOption, error) { - snapshot, err := pulumi.NewResourceOptions(opts...) - if err != nil { - return nil, err - } childOpts := []pulumi.ResourceOption{pulumi.Parent(parent)} - if len(snapshot.DependsOn) > 0 { - childOpts = append(childOpts, pulumi.DependsOn(snapshot.DependsOn)) - } return childOpts, nil } diff --git a/sdk/go/kubernetes/yaml/yaml.go b/sdk/go/kubernetes/yaml/yaml.go index 8f1c9e08c5..edb4cd2efc 100644 --- a/sdk/go/kubernetes/yaml/yaml.go +++ b/sdk/go/kubernetes/yaml/yaml.go @@ -86,14 +86,7 @@ import ( ) func GetChildOptions(parent pulumi.Resource, opts []pulumi.ResourceOption) ([]pulumi.ResourceOption, error) { - snapshot, err := pulumi.NewResourceOptions(opts...) - if err != nil { - return nil, err - } childOpts := []pulumi.ResourceOption{pulumi.Parent(parent)} - if len(snapshot.DependsOn) > 0 { - childOpts = append(childOpts, pulumi.DependsOn(snapshot.DependsOn)) - } return childOpts, nil } From 45a223c59e1b0d732f5fda09b98eb1b72fb2e2d6 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Wed, 6 Dec 2023 15:55:30 -0800 Subject: [PATCH 19/31] Tests (Python SDK) --- tests/go.mod | 2 + tests/go.sum | 2 + tests/gomega/matchers.go | 39 ++ tests/pulumirpc/rpc.go | 160 +++++++ tests/sdk/python/options/Pulumi.yaml | 8 + tests/sdk/python/options/__main__.py | 218 ++++++++++ tests/sdk/python/options/requirements.txt | 4 + tests/sdk/python/python_test.go | 399 ++++++++++++++++++ tests/testdata/options/chart/Chart.yaml | 2 + .../options/chart/templates/manifest.yaml | 6 + tests/testdata/options/chart/values.yaml | 1 + tests/testdata/options/configfile/empty.yaml | 1 + .../testdata/options/configfile/manifest.yaml | 6 + tests/testdata/options/configgroup/empty.yaml | 1 + .../options/configgroup/manifest.yaml | 6 + .../options/kustomize/application.properties | 1 + .../options/kustomize/kustomization.yaml | 7 + tests/util.go | 15 + 18 files changed, 878 insertions(+) create mode 100644 tests/gomega/matchers.go create mode 100644 tests/pulumirpc/rpc.go create mode 100644 tests/sdk/python/options/Pulumi.yaml create mode 100644 tests/sdk/python/options/__main__.py create mode 100644 tests/sdk/python/options/requirements.txt create mode 100644 tests/testdata/options/chart/Chart.yaml create mode 100644 tests/testdata/options/chart/templates/manifest.yaml create mode 100644 tests/testdata/options/chart/values.yaml create mode 100644 tests/testdata/options/configfile/empty.yaml create mode 100644 tests/testdata/options/configfile/manifest.yaml create mode 100644 tests/testdata/options/configgroup/empty.yaml create mode 100644 tests/testdata/options/configgroup/manifest.yaml create mode 100644 tests/testdata/options/kustomize/application.properties create mode 100644 tests/testdata/options/kustomize/kustomization.yaml diff --git a/tests/go.mod b/tests/go.mod index 6bc611e278..6709faeee0 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -13,6 +13,7 @@ require ( github.com/pulumi/pulumi/pkg/v3 v3.81.0 github.com/pulumi/pulumi/sdk/v3 v3.81.0 github.com/stretchr/testify v1.8.4 + golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e helm.sh/helm/v3 v3.12.1 k8s.io/apimachinery v0.28.2 k8s.io/client-go v0.28.2 @@ -216,6 +217,7 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/natefinch/atomic v1.0.1 // indirect github.com/oklog/run v1.1.0 // indirect + github.com/onsi/gomega v1.27.7 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect github.com/opentracing/basictracer-go v1.1.0 // indirect diff --git a/tests/go.sum b/tests/go.sum index 289efdb809..d6648159d8 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -2047,6 +2047,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/tests/gomega/matchers.go b/tests/gomega/matchers.go new file mode 100644 index 0000000000..c5f5cf4180 --- /dev/null +++ b/tests/gomega/matchers.go @@ -0,0 +1,39 @@ +//nolint:copylocks +package gomega + +import ( + . "github.com/onsi/gomega" + gomegatypes "github.com/onsi/gomega/types" + "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" + structpb "google.golang.org/protobuf/types/known/structpb" + + pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go" +) + +// ProtobufStruct matches a protobuf struct by decoding it to a map and then applying the given matcher. +func ProtobufStruct(matcher gomegatypes.GomegaMatcher) gomegatypes.GomegaMatcher { + return WithTransform(func(actual structpb.Struct) (map[string]interface{}, error) { + m := actual.AsMap() + return m, nil + }, matcher) +} + +// Alias matches an Alias by its name. +func Alias(name tokens.QName) gomegatypes.GomegaMatcher { + return WithTransform(func(actual *pulumirpc.Alias) string { + if actual.GetSpec() == nil { + return "" + } + return actual.GetSpec().Name + }, BeEquivalentTo(name)) +} + +// AliasByType matches an Alias by its type. +func AliasByType(typ tokens.Type) gomegatypes.GomegaMatcher { + return WithTransform(func(actual *pulumirpc.Alias) string { + if actual.GetSpec() == nil { + return "" + } + return actual.GetSpec().Type + }, BeEquivalentTo(typ)) +} diff --git a/tests/pulumirpc/rpc.go b/tests/pulumirpc/rpc.go new file mode 100644 index 0000000000..6b08e2a41f --- /dev/null +++ b/tests/pulumirpc/rpc.go @@ -0,0 +1,160 @@ +//nolint:copylocks +package tests + +import ( + "bufio" + "encoding/json" + "fmt" + "os" + + "github.com/pulumi/pulumi/sdk/v3/go/common/resource" + "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" + "github.com/pulumi/pulumi/sdk/v3/go/common/util/contract" + "google.golang.org/protobuf/encoding/protojson" + + pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go" +) + +// JSON format for tracking gRPC conversations. Normal methods have +// one entry for each req-resp conversation, streaming methods have +// one entry per each request or response over the stream. +type DebugInterceptorLogEntry struct { + Method string `json:"method"` + Request json.RawMessage `json:"request,omitempty"` + Response json.RawMessage `json:"response,omitempty"` + Errors []string `json:"errors,omitempty"` + Metadata interface{} `json:"metadata,omitempty"` +} + +// DebugInterceptorLog encapsulates the gRPC debug log file produced by the PULUMI_DEBUG_GRPC environment variable. +type DebugInterceptorLog struct { + LogPath string +} + +func NewDebugInterceptorLog() (*DebugInterceptorLog, error) { + f, err := os.CreateTemp("", "pulumi-grpc-debug-") + if err != nil { + return nil, fmt.Errorf("failed to create GRPC debug log file: %v", err) + } + defer contract.IgnoreClose(f) + return &DebugInterceptorLog{LogPath: f.Name()}, nil +} + +func (d *DebugInterceptorLog) Env() string { + return fmt.Sprintf("PULUMI_DEBUG_GRPC=%s", d.LogPath) +} + +func (d *DebugInterceptorLog) Close() error { + return os.Remove(d.LogPath) +} + +func (d *DebugInterceptorLog) Reset() error { + return os.Truncate(d.LogPath, 0) +} + +func (d *DebugInterceptorLog) ReadAll() (DebugInterceptorLogEntryList, error) { + return ReadDebugInterceptorLogFile(d.LogPath) +} + +type DebugInterceptorLogEntryList []DebugInterceptorLogEntry + +// ListRegisterResource lists the RegisterResource calls in the log. +func (l DebugInterceptorLogEntryList) ListRegisterResource() RegisterResourceList { + var results []RegisterResource + for _, entry := range l { + if r, ok := ParseRegisterResource(entry); ok { + results = append(results, *r) + } + } + return results +} + +// ReadDebugInterceptorLogFile parses the gRPC log file produced by the PULUMI_DEBUG_GRPC environment variable. +func ReadDebugInterceptorLogFile(name string) ([]DebugInterceptorLogEntry, error) { + f, err := os.Open(name) + if err != nil { + return nil, fmt.Errorf("failed to open GRPC debug log file %s: %v", name, err) + } + defer f.Close() + + var entries []DebugInterceptorLogEntry + scanner := bufio.NewScanner(f) + for scanner.Scan() { + text := scanner.Text() + if text == "" { + continue + } + entry := &DebugInterceptorLogEntry{} + err := json.Unmarshal([]byte(text), &entry) + if err != nil { + return nil, fmt.Errorf("failed to parse GRPC debug log line (%s): %v", text, err) + } + entries = append(entries, *entry) + } + if scanner.Err() != nil { + return nil, fmt.Errorf("failed to read GRPC debug log file %s: %v", name, err) + } + return entries, nil +} + +func FormatDebugInterceptorLog(value interface{}) (string, bool) { + if m, ok := value.(DebugInterceptorLogEntry); ok { + json, err := json.Marshal(m) + if err != nil { + return "", false + } + return string(json), true + } + if m, ok := value.(pulumirpc.RegisterResourceRequest); ok { + return protojson.Format(&m), true + } + if m, ok := value.(pulumirpc.RegisterResourceResponse); ok { + return protojson.Format(&m), true + } + return "", false +} + +// RegisterResource is a decoded "/pulumirpc.ResourceMonitor/RegisterResource" RPC call. +type RegisterResource struct { + Request pulumirpc.RegisterResourceRequest + Response pulumirpc.RegisterResourceResponse + Errors []string `json:"errors,omitempty"` + Metadata interface{} `json:"metadata,omitempty"` +} + +type RegisterResourceList []RegisterResource + +// Named returns RegisterResource entries matching the given resource type, name, and parent. +func (l RegisterResourceList) Named(parent resource.URN, typ tokens.Type, name tokens.QName) RegisterResourceList { + var results []RegisterResource + for _, v := range l { + if resource.URN(v.Request.Parent) == parent && tokens.Type(v.Request.Type) == typ && tokens.QName(v.Request.Name) == name { + results = append(results, v) + } + } + return results +} + +// ParseRegisterResource parses a log entry as a RegisterResource call. +func ParseRegisterResource(entry DebugInterceptorLogEntry) (*RegisterResource, bool) { + if entry.Method != "/pulumirpc.ResourceMonitor/RegisterResource" { + return nil, false + } + request := &pulumirpc.RegisterResourceRequest{} + err := protojson.Unmarshal(entry.Request, request) + if err != nil { + return nil, false + } + response := &pulumirpc.RegisterResourceResponse{} + err = protojson.Unmarshal(entry.Response, response) + if err != nil { + return nil, false + } + result := RegisterResource{ + Request: *request, + Response: *response, + Errors: entry.Errors, + Metadata: entry.Metadata, + } + return &result, true +} diff --git a/tests/sdk/python/options/Pulumi.yaml b/tests/sdk/python/options/Pulumi.yaml new file mode 100644 index 0000000000..f4ba0ff2e6 --- /dev/null +++ b/tests/sdk/python/options/Pulumi.yaml @@ -0,0 +1,8 @@ +name: options-test +runtime: + name: python + options: + virtualenv: venv +description: A minimal Kubernetes Python Pulumi program +config: + pulumi:disable-default-providers: [kubernetes] diff --git a/tests/sdk/python/options/__main__.py b/tests/sdk/python/options/__main__.py new file mode 100644 index 0000000000..3251d163e5 --- /dev/null +++ b/tests/sdk/python/options/__main__.py @@ -0,0 +1,218 @@ +"""A Kubernetes Python Pulumi program""" + +import pulumi +from pulumi import ResourceOptions, ResourceTransformationResult, ResourceTransformationArgs, Alias +import pulumi_kubernetes as k8s +import pulumiverse_time as time + +import debugpy +# debugpy.listen(5678) +# debugpy.wait_for_client() + +bootstrap_provider = k8s.Provider("bootstrap") +nullopts_ns = k8s.core.v1.Namespace("nullopts", opts=pulumi.ResourceOptions(provider=bootstrap_provider)) +a_ns = k8s.core.v1.Namespace("a", opts=pulumi.ResourceOptions(provider=bootstrap_provider)) +b_ns = k8s.core.v1.Namespace("b", opts=pulumi.ResourceOptions(provider=bootstrap_provider)) +nullopts_provider = k8s.Provider("nullopts", namespace=nullopts_ns.metadata["name"]) + +# create a set of providers across namespaces, simply to facilitate the reuse of manifests in the below tests. +a_provider = k8s.Provider("a", namespace=a_ns.metadata["name"]) +b_provider = k8s.Provider("b", namespace=b_ns.metadata["name"]) + +# a sleep resource to exercise the "depends_on" component-level option +sleep = time.Sleep("sleep", create_duration="1s", opts=pulumi.ResourceOptions(depends_on=[a_provider, b_provider])) + +# apply_default_opts is a stack transformation that applies default opts to any resource whose name ends with "-nullopts". +# this is intended to be applied to component resources only. +def apply_default_opts(args): + if args.name.endswith("-nullopts"): + return ResourceTransformationResult( + props=args.props, + opts=ResourceOptions.merge(args.opts, ResourceOptions( + provider=nullopts_provider, + ))) + return None +pulumi.runtime.register_stack_transformation(apply_default_opts) + +# transform_pulumi is a Pulumi transformation that applies a unique alias to each resource. +def transform_pulumi(args: ResourceTransformationArgs): + return ResourceTransformationResult( + props=args.props, + opts=ResourceOptions.merge(args.opts, ResourceOptions( + aliases=[Alias(name=f'{args.name}-aliased')], + )), + ) + +def debugger(args: ResourceTransformationArgs): + return None + +# transform_k8s is a Kubernetes transformation that applies a unique alias and annotation to each resource. +def transform_k8s(obj, opts): + opts.aliases = [Alias(f'{obj["metadata"]["name"]}-k8s-aliased')] + (opts.aliases if opts.aliases is not None else []) + obj["metadata"]["annotations"] = {"transformed": "true"} + +### --- ConfigGroup --- +# options: providers, aliases, depends_on, ignore_changes, protect, transformations +# args: skip_await, transformations +k8s.yaml.ConfigGroup( + "cg-a", + resource_prefix="cg-a", + skip_await=True, + transformations=[transform_k8s], + files=["./testdata/options/configgroup/*.yaml"], + yaml=[''' +apiVersion: v1 +kind: ConfigMap +metadata: + name: cg-a-cm-1 + '''], + opts=ResourceOptions( + providers=[a_provider], + aliases=[Alias(name="cg-a-old")], + ignore_changes=["ignored"], + protect=True, + depends_on=[sleep], + transformations=[transform_pulumi], + ), +) +# "provider" option +k8s.yaml.ConfigGroup( + "cg-b", + resource_prefix="cg-b", + yaml=[''' +apiVersion: v1 +kind: ConfigMap +metadata: + name: yaml-cm-1 + '''], + opts=ResourceOptions( + provider=b_provider, + ), +) +# null opts +k8s.yaml.ConfigGroup( + "cg-nullopts", + resource_prefix="cg-nullopts", + yaml=[''' +apiVersion: v1 +kind: ConfigMap +metadata: + name: yaml-cm-1 + '''], +) + +### --- ConfigFile --- +# options: providers, aliases, depends_on, ignore_changes, protect, transformations +# args: skip_await, transformations +k8s.yaml.ConfigFile( + "cf-a", + file="./testdata/options/configfile/manifest.yaml", + resource_prefix="cf-a", + skip_await=True, + transformations=[transform_k8s], + opts=ResourceOptions( + providers=[a_provider], + aliases=[Alias(name="cf-a-old")], + ignore_changes=["ignored"], + protect=True, + depends_on=[sleep], + transformations=[transform_pulumi], + ), +) +# "provider" option +k8s.yaml.ConfigFile( + "cf-b", + resource_prefix="cf-b", + file="./testdata/options/configfile/manifest.yaml", + opts=ResourceOptions( + provider=b_provider, + ), +) +# null opts +k8s.yaml.ConfigFile( + "cf-nullopts", + resource_prefix="cf-nullopts", + file="./testdata/options/configfile/manifest.yaml", +) +# empty manifests +k8s.yaml.ConfigFile( + "cf-empty", + resource_prefix="cf-empty", + file="./testdata/options/configfile/empty.yaml", + opts=ResourceOptions( + providers=[a_provider], + ), +) + +### --- Directory --- +# options: providers, aliases, depends_on, ignore_changes, protect, transformations +# args: transformations +k8s.kustomize.Directory( + "kustomize-a", + directory="./testdata/options/kustomize", + resource_prefix="kustomize-a", + transformations=[transform_k8s], + opts=ResourceOptions( + providers=[a_provider], + aliases=[Alias(name="kustomize-a-old")], + ignore_changes=["ignored"], + protect=True, + depends_on=[sleep], + transformations=[transform_pulumi], + ), +) +# "provider" option +k8s.kustomize.Directory( + "kustomize-b", + directory="./testdata/options/kustomize", + resource_prefix="kustomize-b", + opts=ResourceOptions( + provider=b_provider, + ), +) +# null opts +k8s.kustomize.Directory( + "kustomize-nullopts", + directory="./testdata/options/kustomize", + resource_prefix="kustomize-nullopts", +) + +### --- Chart --- +# options: providers, aliases, depends_on, ignore_changes, protect, transformations +# args: transformations +k8s.helm.v3.Chart( + "chart-a", + k8s.helm.v3.LocalChartOpts( + path="./testdata/options/chart", + resource_prefix="chart-a", + transformations=[transform_k8s], + skip_await=True, + ), + opts=ResourceOptions( + providers=[a_provider], + aliases=[Alias(name="chart-a-old")], + ignore_changes=["ignored"], + protect=True, + depends_on=[sleep], + transformations=[transform_pulumi, debugger], + ), +) +# "provider" option +k8s.helm.v3.Chart( + "chart-b", + k8s.helm.v3.LocalChartOpts( + path="./testdata/options/chart", + resource_prefix="chart-b", + ), + opts=ResourceOptions( + provider=b_provider, + ), +) +# null opts +k8s.helm.v3.Chart( + "chart-nullopts", + k8s.helm.v3.LocalChartOpts( + path="./testdata/options/chart", + resource_prefix="chart-nullopts", + ) +) diff --git a/tests/sdk/python/options/requirements.txt b/tests/sdk/python/options/requirements.txt new file mode 100644 index 0000000000..5d395f1dfb --- /dev/null +++ b/tests/sdk/python/options/requirements.txt @@ -0,0 +1,4 @@ +pulumi>=3.0.0,<4.0.0 +pulumi-kubernetes>=4.0.0,<5.0.0 +pulumiverse_time>=v0.0.16 +debugpy>=1.4.1 diff --git a/tests/sdk/python/python_test.go b/tests/sdk/python/python_test.go index 53c130f010..16998240d9 100644 --- a/tests/sdk/python/python_test.go +++ b/tests/sdk/python/python_test.go @@ -27,12 +27,24 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "github.com/onsi/gomega/format" + + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gstruct" "github.com/pulumi/pulumi-kubernetes/provider/v4/pkg/openapi" + "github.com/pulumi/pulumi-kubernetes/tests/v4" + . "github.com/pulumi/pulumi-kubernetes/tests/v4/gomega" + pulumirpctesting "github.com/pulumi/pulumi-kubernetes/tests/v4/pulumirpc" + "github.com/pulumi/pulumi/pkg/v3/engine" "github.com/pulumi/pulumi/pkg/v3/resource/deploy/providers" "github.com/pulumi/pulumi/pkg/v3/testing/integration" + "github.com/pulumi/pulumi/sdk/v3/go/common/apitype" "github.com/pulumi/pulumi/sdk/v3/go/common/resource" "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" + "github.com/pulumi/pulumi/sdk/v3/go/common/util/contract" + "github.com/pulumi/pulumi/sdk/v3/go/common/util/fsutil" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var baseOptions = &integration.ProgramTestOptions{ @@ -40,6 +52,9 @@ var baseOptions = &integration.ProgramTestOptions{ Dependencies: []string{ filepath.Join("..", "..", "..", "sdk", "python", "bin"), }, + PostPrepareProject: func(p *engine.Projinfo) error { + return fsutil.CopyFile(filepath.Join(p.Root, "testdata"), filepath.Join("..", "..", "testdata"), nil) + }, Env: []string{ "PULUMI_K8S_CLIENT_BURST=200", "PULUMI_K8S_CLIENT_QPS=100", @@ -528,3 +543,387 @@ func TestServerSideApply(t *testing.T) { }) integration.ProgramTest(t, &options) } + +// TestOptionPropagation tests the handling of resource options by the various compoonent resources. +// Component resources are responsible for implementing option propagation logic when creating +// child resources. +func TestOptionPropagation(t *testing.T) { + g := NewWithT(t) + format.MaxLength = 0 + format.RegisterCustomFormatter(pulumirpctesting.FormatDebugInterceptorLog) + + cwd, err := os.Getwd() + if !assert.NoError(t, err) { + t.FailNow() + } + + grpcLog, err := pulumirpctesting.NewDebugInterceptorLog() + require.NoError(t, err) + + options := baseOptions.With(integration.ProgramTestOptions{ + Dir: filepath.Join(cwd, "options"), + Env: []string{grpcLog.Env()}, + Quick: true, + ExpectRefreshChanges: false, + ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { + + // lookup some resources for later use + providerA := tests.SearchResourcesByName(stackInfo, "", "pulumi:providers:kubernetes", "a") + require.NotNil(t, providerA) + providerB := tests.SearchResourcesByName(stackInfo, "", "pulumi:providers:kubernetes", "b") + require.NotNil(t, providerB) + providerNullOpts := tests.SearchResourcesByName(stackInfo, "", "pulumi:providers:kubernetes", "nullopts") + require.NotNil(t, providerNullOpts) + sleep := tests.SearchResourcesByName(stackInfo, "", "time:index/sleep:Sleep", "sleep") + require.NotNil(t, sleep) + + // some helper functions for naming purposes + providerUrn := func(prov *apitype.ResourceV3) resource.URN { + return prov.URN + resource.URNNameDelimiter + resource.URN(prov.ID) + } + urn := func(parentType, baseType tokens.Type, name tokens.QName) resource.URN { + return resource.NewURN(stackInfo.StackName, "options-test", parentType, baseType, name) + } + + // read the GRPC log file to inspect the RegisterResource calls, since they provide + // the most detailed view of the resource's options as determined by the SDK. + logEntries, err := grpcLog.ReadAll() + require.NoError(t, err) + rr := logEntries.ListRegisterResource() + + // --- ConfigGroup --- + + // ConfigGroup "cg-a" with most options + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigGroup", "cg-a-cg-a")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("cg-a") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": ConsistOf(Alias("cg-a-old"), Alias("cg-a-cg-a-aliased")), + "Protect": BeTrue(), + "Dependencies": ConsistOf(string(sleep.URN)), + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerA)), + }), + "IgnoreChanges": ConsistOf("ignored"), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigGroup", "cg-a-cg-a"), "kubernetes:core/v1:ConfigMap", "cg-a-cg-a-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": ConsistOf(Alias("cg-a-cm-1-k8s-aliased"), Alias("cg-a-cg-a-cm-1-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "annotations": And(HaveKey("pulumi.com/skipAwait"), HaveKey("transformed")), + }), + }))), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigGroup", "cg-a-cg-a"), "kubernetes:yaml:ConfigFile", "cg-a-./testdata/options/configgroup/manifest.yaml")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": ConsistOf(Alias("cg-a-./testdata/options/configgroup/manifest.yaml-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerA)), + }), + }), + }), + )) + g.Expect(rr.Named(urn("kubernetes:yaml:ConfigGroup", "kubernetes:yaml:ConfigFile", "cg-a-./testdata/options/configgroup/manifest.yaml"), "kubernetes:core/v1:ConfigMap", "cg-a-configgroup-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": ConsistOf(Alias("configgroup-cm-1-k8s-aliased"), Alias("cg-a-configgroup-cm-1-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "annotations": And(HaveKey("pulumi.com/skipAwait"), HaveKey("transformed")), + }), + }))), + }), + }), + )) + + // ConfigGroup "cg-b" with "provider" option that should propagate to children. + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigGroup", "cg-b-cg-b")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerB)), + }), + }), + }), + )) + + // ConfigGroup "cg-nullopts" with a stack transform to apply a "provider" option. + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigGroup", "cg-nullopts-cg-nullopts")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerNullOpts)), + }), + }), + }), + )) + + // --- ConfigFile --- + + // ConfigFile "cf-a" with most options + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigFile", "cf-a-cf-a")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("cf-a") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": ConsistOf(Alias("cf-a-old"), Alias("cf-a-cf-a-aliased")), + "Protect": BeTrue(), + "Dependencies": ConsistOf(string(sleep.URN)), + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerA)), + }), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-a-cf-a"), "kubernetes:core/v1:ConfigMap", "cf-a-configfile-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": ConsistOf(Alias("configfile-cm-1-k8s-aliased"), Alias("cf-a-configfile-cm-1-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "annotations": And(HaveKey("pulumi.com/skipAwait"), HaveKey("transformed")), + }), + }))), + }), + }), + )) + + // ConfigFile "cf-b" with "provider" option that should propagate to children. + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigFile", "cf-b-cf-b")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("cf-b") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerB)), + }), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-b-cf-b"), "kubernetes:core/v1:ConfigMap", "cf-b-configfile-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerB)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + }), + }), + )) + + // ConfigFile "cf-nullopts" with a stack transform to apply a "provider" option. + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigFile", "cf-nullopts-cf-nullopts")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("cf-nullopts") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerNullOpts)), + }), + }), + }), + )) + + // --- Directory --- + + // Directory "kustomize-a" with most options + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:kustomize:Directory", "kustomize-a-kustomize-a")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("kustomize-a") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": ConsistOf(Alias("kustomize-a-old"), Alias("kustomize-a-kustomize-a-aliased")), + "Protect": BeTrue(), + "Dependencies": ConsistOf(string(sleep.URN)), + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerA)), + }), + "IgnoreChanges": ConsistOf("ignored"), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-a-kustomize-a"), "kubernetes:core/v1:ConfigMap", "kustomize-a-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": ConsistOf(Alias("kustomize-cm-1-2kkk4bthmg-k8s-aliased"), Alias("kustomize-a-kustomize-cm-1-2kkk4bthmg-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "annotations": And(HaveKey("transformed")), + }), + }))), + }), + }), + )) + + // Directory "kustomize-b" with "provider" option that should propagate to children. + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:kustomize:Directory", "kustomize-b-kustomize-b")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("kustomize-b") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerB)), + }), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-b-kustomize-b"), "kubernetes:core/v1:ConfigMap", "kustomize-b-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerB)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + }), + }), + )) + + // Directory "kustomize-nullopts" with a stack transform to apply a "provider" option. + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:kustomize:Directory", "kustomize-nullopts-kustomize-nullopts")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("kustomize-nullopts") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerNullOpts)), + }), + }), + }), + )) + + // --- Chart --- + + // Chart "chart-a" + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:helm.sh/v3:Chart", "chart-a-chart-a")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("chart-a") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": ConsistOf(Alias("chart-a-old"), Alias("chart-a-chart-a-aliased"), AliasByType("kubernetes:helm.sh/v2:Chart")), + "Protect": BeTrue(), + "Dependencies": ConsistOf(string(sleep.URN)), + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerA)), + }), + "IgnoreChanges": ConsistOf("ignored"), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-a-chart-a"), "kubernetes:core/v1:ConfigMap", "chart-a-chart-a-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": ConsistOf(Alias("chart-a-chart-a-cm-1-k8s-aliased"), Alias("chart-a-chart-a-cm-1-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), + }), + }), + )) + + // Chart "chart-b" with "provider" option that should propagate to children. + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:helm.sh/v3:Chart", "chart-b-chart-b")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("chart-b") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerB)), + }), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-b-chart-b"), "kubernetes:core/v1:ConfigMap", "chart-b-chart-b-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerB)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + }), + }), + )) + + // Chart "chart-nullopts" with a stack transform to apply a "provider" option. + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:helm.sh/v3:Chart", "chart-nullopts-chart-nullopts")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("chart-a") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerNullOpts)), + }), + }), + }), + )) + }, + }) + + pt := integration.ProgramTestManualLifeCycle(t, &options) + + err = pt.TestLifeCyclePrepare() + require.NoError(t, err) + t.Cleanup(pt.TestCleanUp) + err = pt.TestLifeCycleInitialize() + require.NoError(t, err) + t.Cleanup(func() { + // to ensure cleanup, we need to unprotected all resources + err = pt.RunPulumiCommand("state", "unprotect", "--all", "-y") + contract.IgnoreError(err) + + destroyErr := pt.TestLifeCycleDestroy() + contract.IgnoreError(destroyErr) + }) + + err = pt.TestPreviewUpdateAndEdits() + require.NoError(t, err) +} diff --git a/tests/testdata/options/chart/Chart.yaml b/tests/testdata/options/chart/Chart.yaml new file mode 100644 index 0000000000..49062ffb63 --- /dev/null +++ b/tests/testdata/options/chart/Chart.yaml @@ -0,0 +1,2 @@ +name: chart +version: 1.0.0 diff --git a/tests/testdata/options/chart/templates/manifest.yaml b/tests/testdata/options/chart/templates/manifest.yaml new file mode 100644 index 0000000000..0f34094c4b --- /dev/null +++ b/tests/testdata/options/chart/templates/manifest.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{.Release.Name}}-cm-1 +data: + foo: "bar" diff --git a/tests/testdata/options/chart/values.yaml b/tests/testdata/options/chart/values.yaml new file mode 100644 index 0000000000..bad64117b1 --- /dev/null +++ b/tests/testdata/options/chart/values.yaml @@ -0,0 +1 @@ +# Default values \ No newline at end of file diff --git a/tests/testdata/options/configfile/empty.yaml b/tests/testdata/options/configfile/empty.yaml new file mode 100644 index 0000000000..c16086c5eb --- /dev/null +++ b/tests/testdata/options/configfile/empty.yaml @@ -0,0 +1 @@ +# empty manifest diff --git a/tests/testdata/options/configfile/manifest.yaml b/tests/testdata/options/configfile/manifest.yaml new file mode 100644 index 0000000000..e56a591217 --- /dev/null +++ b/tests/testdata/options/configfile/manifest.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: configfile-cm-1 +data: + foo: "bar" diff --git a/tests/testdata/options/configgroup/empty.yaml b/tests/testdata/options/configgroup/empty.yaml new file mode 100644 index 0000000000..c16086c5eb --- /dev/null +++ b/tests/testdata/options/configgroup/empty.yaml @@ -0,0 +1 @@ +# empty manifest diff --git a/tests/testdata/options/configgroup/manifest.yaml b/tests/testdata/options/configgroup/manifest.yaml new file mode 100644 index 0000000000..d47dbdc328 --- /dev/null +++ b/tests/testdata/options/configgroup/manifest.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: configgroup-cm-1 +data: + foo: "bar" diff --git a/tests/testdata/options/kustomize/application.properties b/tests/testdata/options/kustomize/application.properties new file mode 100644 index 0000000000..1566bb1d76 --- /dev/null +++ b/tests/testdata/options/kustomize/application.properties @@ -0,0 +1 @@ +FOO=bar \ No newline at end of file diff --git a/tests/testdata/options/kustomize/kustomization.yaml b/tests/testdata/options/kustomize/kustomization.yaml new file mode 100644 index 0000000000..477504b83f --- /dev/null +++ b/tests/testdata/options/kustomize/kustomization.yaml @@ -0,0 +1,7 @@ +commonLabels: + app: testapp + +configMapGenerator: +- name: kustomize-cm-1 + files: + - application.properties diff --git a/tests/util.go b/tests/util.go index e3ae7441e4..408e89616a 100644 --- a/tests/util.go +++ b/tests/util.go @@ -6,7 +6,12 @@ import ( "strings" "testing" + "golang.org/x/exp/slices" + "github.com/pulumi/pulumi/pkg/v3/testing/integration" + "github.com/pulumi/pulumi/sdk/v3/go/common/apitype" + "github.com/pulumi/pulumi/sdk/v3/go/common/resource" + "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" ) // SkipIfShort skips the test if the -short flag is passed to `go test`. @@ -22,6 +27,16 @@ func SortResourcesByURN(stackInfo integration.RuntimeValidationStackInfo) { }) } +func SearchResourcesByName(stackInfo integration.RuntimeValidationStackInfo, parent resource.URN, typ tokens.Type, name tokens.QName) *apitype.ResourceV3 { + i := slices.IndexFunc(stackInfo.Deployment.Resources, func(r apitype.ResourceV3) bool { + return r.Type == typ && r.URN.Name() == name && (parent == "" || r.Parent == parent) + }) + if i == -1 { + return nil + } + return &stackInfo.Deployment.Resources[i] +} + // Kubectl is a helper function to shell out and run kubectl commands. func Kubectl(args ...string) ([]byte, error) { var fmtArgs []string From 73c7001afbc4268e7989f73132fd8578089ab689 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Wed, 6 Dec 2023 16:32:19 -0800 Subject: [PATCH 20/31] test fix (Python SDK) --- tests/sdk/python/python_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/sdk/python/python_test.go b/tests/sdk/python/python_test.go index 16998240d9..00695c146f 100644 --- a/tests/sdk/python/python_test.go +++ b/tests/sdk/python/python_test.go @@ -865,6 +865,11 @@ func TestOptionPropagation(t *testing.T) { "Version": Not(BeEmpty()), "Providers": BeEmpty(), "IgnoreChanges": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "annotations": And(HaveKey("pulumi.com/skipAwait")), + }), + }))), }), }), )) From 7ac77017db91c4e0a167bee17c766485380d75c6 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Thu, 7 Dec 2023 14:55:36 -0800 Subject: [PATCH 21/31] cleanups (Python) --- tests/sdk/python/options/__main__.py | 29 +++++++++-------------- tests/sdk/python/options/requirements.txt | 1 - tests/sdk/python/python_test.go | 11 +++++++++ 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/tests/sdk/python/options/__main__.py b/tests/sdk/python/options/__main__.py index 3251d163e5..2aa54e602c 100644 --- a/tests/sdk/python/options/__main__.py +++ b/tests/sdk/python/options/__main__.py @@ -5,17 +5,13 @@ import pulumi_kubernetes as k8s import pulumiverse_time as time -import debugpy -# debugpy.listen(5678) -# debugpy.wait_for_client() - bootstrap_provider = k8s.Provider("bootstrap") + +# create a set of providers across namespaces, simply to facilitate the reuse of manifests in the below tests. nullopts_ns = k8s.core.v1.Namespace("nullopts", opts=pulumi.ResourceOptions(provider=bootstrap_provider)) a_ns = k8s.core.v1.Namespace("a", opts=pulumi.ResourceOptions(provider=bootstrap_provider)) b_ns = k8s.core.v1.Namespace("b", opts=pulumi.ResourceOptions(provider=bootstrap_provider)) nullopts_provider = k8s.Provider("nullopts", namespace=nullopts_ns.metadata["name"]) - -# create a set of providers across namespaces, simply to facilitate the reuse of manifests in the below tests. a_provider = k8s.Provider("a", namespace=a_ns.metadata["name"]) b_provider = k8s.Provider("b", namespace=b_ns.metadata["name"]) @@ -34,8 +30,8 @@ def apply_default_opts(args): return None pulumi.runtime.register_stack_transformation(apply_default_opts) -# transform_pulumi is a Pulumi transformation that applies a unique alias to each resource. -def transform_pulumi(args: ResourceTransformationArgs): +# apply_alias is a Pulumi transformation that applies a unique alias to each resource. +def apply_alias(args: ResourceTransformationArgs): return ResourceTransformationResult( props=args.props, opts=ResourceOptions.merge(args.opts, ResourceOptions( @@ -43,9 +39,6 @@ def transform_pulumi(args: ResourceTransformationArgs): )), ) -def debugger(args: ResourceTransformationArgs): - return None - # transform_k8s is a Kubernetes transformation that applies a unique alias and annotation to each resource. def transform_k8s(obj, opts): opts.aliases = [Alias(f'{obj["metadata"]["name"]}-k8s-aliased')] + (opts.aliases if opts.aliases is not None else []) @@ -64,7 +57,7 @@ def transform_k8s(obj, opts): apiVersion: v1 kind: ConfigMap metadata: - name: cg-a-cm-1 + name: cg-a-cm-1 '''], opts=ResourceOptions( providers=[a_provider], @@ -72,7 +65,7 @@ def transform_k8s(obj, opts): ignore_changes=["ignored"], protect=True, depends_on=[sleep], - transformations=[transform_pulumi], + transformations=[apply_alias], ), ) # "provider" option @@ -83,7 +76,7 @@ def transform_k8s(obj, opts): apiVersion: v1 kind: ConfigMap metadata: - name: yaml-cm-1 + name: cg-b-cm-1 '''], opts=ResourceOptions( provider=b_provider, @@ -97,7 +90,7 @@ def transform_k8s(obj, opts): apiVersion: v1 kind: ConfigMap metadata: - name: yaml-cm-1 + name: cg-nullopts-cm-1 '''], ) @@ -116,7 +109,7 @@ def transform_k8s(obj, opts): ignore_changes=["ignored"], protect=True, depends_on=[sleep], - transformations=[transform_pulumi], + transformations=[apply_alias], ), ) # "provider" option @@ -158,7 +151,7 @@ def transform_k8s(obj, opts): ignore_changes=["ignored"], protect=True, depends_on=[sleep], - transformations=[transform_pulumi], + transformations=[apply_alias], ), ) # "provider" option @@ -194,7 +187,7 @@ def transform_k8s(obj, opts): ignore_changes=["ignored"], protect=True, depends_on=[sleep], - transformations=[transform_pulumi, debugger], + transformations=[apply_alias], ), ) # "provider" option diff --git a/tests/sdk/python/options/requirements.txt b/tests/sdk/python/options/requirements.txt index 5d395f1dfb..6116d45b7d 100644 --- a/tests/sdk/python/options/requirements.txt +++ b/tests/sdk/python/options/requirements.txt @@ -1,4 +1,3 @@ pulumi>=3.0.0,<4.0.0 pulumi-kubernetes>=4.0.0,<5.0.0 pulumiverse_time>=v0.0.16 -debugpy>=1.4.1 diff --git a/tests/sdk/python/python_test.go b/tests/sdk/python/python_test.go index 00695c146f..808b9ed8fc 100644 --- a/tests/sdk/python/python_test.go +++ b/tests/sdk/python/python_test.go @@ -622,6 +622,7 @@ func TestOptionPropagation(t *testing.T) { "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("cg-a-cm-1"), "annotations": And(HaveKey("pulumi.com/skipAwait"), HaveKey("transformed")), }), }))), @@ -654,6 +655,7 @@ func TestOptionPropagation(t *testing.T) { "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("configgroup-cm-1"), "annotations": And(HaveKey("pulumi.com/skipAwait"), HaveKey("transformed")), }), }))), @@ -717,6 +719,7 @@ func TestOptionPropagation(t *testing.T) { "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("configfile-cm-1"), "annotations": And(HaveKey("pulumi.com/skipAwait"), HaveKey("transformed")), }), }))), @@ -743,6 +746,11 @@ func TestOptionPropagation(t *testing.T) { "Provider": BeEquivalentTo(providerUrn(providerB)), "Version": Not(BeEmpty()), "Providers": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("configfile-cm-1"), + }), + }))), }), }), )) @@ -792,6 +800,7 @@ func TestOptionPropagation(t *testing.T) { "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("kustomize-cm-1-2kkk4bthmg"), "annotations": And(HaveKey("transformed")), }), }))), @@ -856,6 +865,7 @@ func TestOptionPropagation(t *testing.T) { }), )) g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-a-chart-a"), "kubernetes:core/v1:ConfigMap", "chart-a-chart-a-cm-1")).To(HaveExactElements( + // quirk: Python SDK does NOT directly apply resource_prefix to the child resources (unlike other SDKs) MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Aliases": ConsistOf(Alias("chart-a-chart-a-cm-1-k8s-aliased"), Alias("chart-a-chart-a-cm-1-aliased")), @@ -867,6 +877,7 @@ func TestOptionPropagation(t *testing.T) { "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("chart-a-chart-a-cm-1"), // note: based on the Helm Release name "annotations": And(HaveKey("pulumi.com/skipAwait")), }), }))), From 71383fb93e47d6c6c28b83d4855ab59b500702c5 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Thu, 7 Dec 2023 15:06:08 -0800 Subject: [PATCH 22/31] renames (python) --- tests/sdk/python/options/__main__.py | 53 +++++++++------- tests/sdk/python/python_test.go | 90 ++++++++++++++-------------- 2 files changed, 76 insertions(+), 67 deletions(-) diff --git a/tests/sdk/python/options/__main__.py b/tests/sdk/python/options/__main__.py index 2aa54e602c..b4d351188a 100644 --- a/tests/sdk/python/options/__main__.py +++ b/tests/sdk/python/options/__main__.py @@ -48,8 +48,8 @@ def transform_k8s(obj, opts): # options: providers, aliases, depends_on, ignore_changes, protect, transformations # args: skip_await, transformations k8s.yaml.ConfigGroup( - "cg-a", - resource_prefix="cg-a", + "cg-options", + resource_prefix="cg-options", skip_await=True, transformations=[transform_k8s], files=["./testdata/options/configgroup/*.yaml"], @@ -57,31 +57,33 @@ def transform_k8s(obj, opts): apiVersion: v1 kind: ConfigMap metadata: - name: cg-a-cm-1 + name: cg-options-cm-1 '''], opts=ResourceOptions( providers=[a_provider], - aliases=[Alias(name="cg-a-old")], + aliases=[Alias(name="cg-options-old")], ignore_changes=["ignored"], protect=True, depends_on=[sleep], transformations=[apply_alias], ), ) + # "provider" option k8s.yaml.ConfigGroup( - "cg-b", - resource_prefix="cg-b", + "cg-provider", + resource_prefix="cg-provider", yaml=[''' apiVersion: v1 kind: ConfigMap metadata: - name: cg-b-cm-1 + name: cg-provider-cm-1 '''], opts=ResourceOptions( provider=b_provider, ), ) + # null opts k8s.yaml.ConfigGroup( "cg-nullopts", @@ -98,35 +100,38 @@ def transform_k8s(obj, opts): # options: providers, aliases, depends_on, ignore_changes, protect, transformations # args: skip_await, transformations k8s.yaml.ConfigFile( - "cf-a", + "cf-options", file="./testdata/options/configfile/manifest.yaml", - resource_prefix="cf-a", + resource_prefix="cf-options", skip_await=True, transformations=[transform_k8s], opts=ResourceOptions( providers=[a_provider], - aliases=[Alias(name="cf-a-old")], + aliases=[Alias(name="cf-options-old")], ignore_changes=["ignored"], protect=True, depends_on=[sleep], transformations=[apply_alias], ), ) + # "provider" option k8s.yaml.ConfigFile( - "cf-b", - resource_prefix="cf-b", + "cf-provider", + resource_prefix="cf-provider", file="./testdata/options/configfile/manifest.yaml", opts=ResourceOptions( provider=b_provider, ), ) + # null opts k8s.yaml.ConfigFile( "cf-nullopts", resource_prefix="cf-nullopts", file="./testdata/options/configfile/manifest.yaml", ) + # empty manifests k8s.yaml.ConfigFile( "cf-empty", @@ -141,28 +146,30 @@ def transform_k8s(obj, opts): # options: providers, aliases, depends_on, ignore_changes, protect, transformations # args: transformations k8s.kustomize.Directory( - "kustomize-a", + "kustomize-options", directory="./testdata/options/kustomize", - resource_prefix="kustomize-a", + resource_prefix="kustomize-options", transformations=[transform_k8s], opts=ResourceOptions( providers=[a_provider], - aliases=[Alias(name="kustomize-a-old")], + aliases=[Alias(name="kustomize-options-old")], ignore_changes=["ignored"], protect=True, depends_on=[sleep], transformations=[apply_alias], ), ) + # "provider" option k8s.kustomize.Directory( - "kustomize-b", + "kustomize-provider", directory="./testdata/options/kustomize", - resource_prefix="kustomize-b", + resource_prefix="kustomize-provider", opts=ResourceOptions( provider=b_provider, ), ) + # null opts k8s.kustomize.Directory( "kustomize-nullopts", @@ -174,33 +181,35 @@ def transform_k8s(obj, opts): # options: providers, aliases, depends_on, ignore_changes, protect, transformations # args: transformations k8s.helm.v3.Chart( - "chart-a", + "chart-options", k8s.helm.v3.LocalChartOpts( path="./testdata/options/chart", - resource_prefix="chart-a", + resource_prefix="chart-options", transformations=[transform_k8s], skip_await=True, ), opts=ResourceOptions( providers=[a_provider], - aliases=[Alias(name="chart-a-old")], + aliases=[Alias(name="chart-options-old")], ignore_changes=["ignored"], protect=True, depends_on=[sleep], transformations=[apply_alias], ), ) + # "provider" option k8s.helm.v3.Chart( - "chart-b", + "chart-provider", k8s.helm.v3.LocalChartOpts( path="./testdata/options/chart", - resource_prefix="chart-b", + resource_prefix="chart-provider", ), opts=ResourceOptions( provider=b_provider, ), ) + # null opts k8s.helm.v3.Chart( "chart-nullopts", diff --git a/tests/sdk/python/python_test.go b/tests/sdk/python/python_test.go index 808b9ed8fc..344108b377 100644 --- a/tests/sdk/python/python_test.go +++ b/tests/sdk/python/python_test.go @@ -593,12 +593,12 @@ func TestOptionPropagation(t *testing.T) { // --- ConfigGroup --- - // ConfigGroup "cg-a" with most options - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigGroup", "cg-a-cg-a")).To(HaveExactElements( - // quirk: Python SDK applies resource_prefix ("cg-a") to the component itself. + // ConfigGroup "cg-options" with most options + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigGroup", "cg-options-cg-options")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("cg-options") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": ConsistOf(Alias("cg-a-old"), Alias("cg-a-cg-a-aliased")), + "Aliases": ConsistOf(Alias("cg-options-old"), Alias("cg-options-cg-options-aliased")), "Protect": BeTrue(), "Dependencies": ConsistOf(string(sleep.URN)), "Provider": BeEmpty(), @@ -610,10 +610,10 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigGroup", "cg-a-cg-a"), "kubernetes:core/v1:ConfigMap", "cg-a-cg-a-cm-1")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigGroup", "cg-options-cg-options"), "kubernetes:core/v1:ConfigMap", "cg-options-cg-options-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": ConsistOf(Alias("cg-a-cm-1-k8s-aliased"), Alias("cg-a-cg-a-cm-1-aliased")), + "Aliases": ConsistOf(Alias("cg-options-cm-1-k8s-aliased"), Alias("cg-options-cg-options-cm-1-aliased")), "Protect": BeTrue(), "Dependencies": BeEmpty(), "Provider": BeEquivalentTo(providerUrn(providerA)), @@ -622,17 +622,17 @@ func TestOptionPropagation(t *testing.T) { "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ "metadata": MatchKeys(IgnoreExtras, Keys{ - "name": Equal("cg-a-cm-1"), + "name": Equal("cg-options-cm-1"), "annotations": And(HaveKey("pulumi.com/skipAwait"), HaveKey("transformed")), }), }))), }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigGroup", "cg-a-cg-a"), "kubernetes:yaml:ConfigFile", "cg-a-./testdata/options/configgroup/manifest.yaml")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigGroup", "cg-options-cg-options"), "kubernetes:yaml:ConfigFile", "cg-options-./testdata/options/configgroup/manifest.yaml")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": ConsistOf(Alias("cg-a-./testdata/options/configgroup/manifest.yaml-aliased")), + "Aliases": ConsistOf(Alias("cg-options-./testdata/options/configgroup/manifest.yaml-aliased")), "Protect": BeTrue(), "Dependencies": BeEmpty(), "Provider": BeEmpty(), @@ -643,10 +643,10 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("kubernetes:yaml:ConfigGroup", "kubernetes:yaml:ConfigFile", "cg-a-./testdata/options/configgroup/manifest.yaml"), "kubernetes:core/v1:ConfigMap", "cg-a-configgroup-cm-1")).To(HaveExactElements( + g.Expect(rr.Named(urn("kubernetes:yaml:ConfigGroup", "kubernetes:yaml:ConfigFile", "cg-options-./testdata/options/configgroup/manifest.yaml"), "kubernetes:core/v1:ConfigMap", "cg-options-configgroup-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": ConsistOf(Alias("configgroup-cm-1-k8s-aliased"), Alias("cg-a-configgroup-cm-1-aliased")), + "Aliases": ConsistOf(Alias("configgroup-cm-1-k8s-aliased"), Alias("cg-options-configgroup-cm-1-aliased")), "Protect": BeTrue(), "Dependencies": BeEmpty(), "Provider": BeEquivalentTo(providerUrn(providerA)), @@ -663,8 +663,8 @@ func TestOptionPropagation(t *testing.T) { }), )) - // ConfigGroup "cg-b" with "provider" option that should propagate to children. - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigGroup", "cg-b-cg-b")).To(HaveExactElements( + // ConfigGroup "cg-provider" with "provider" option that should propagate to children. + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigGroup", "cg-provider-cg-provider")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEmpty(), @@ -691,12 +691,12 @@ func TestOptionPropagation(t *testing.T) { // --- ConfigFile --- - // ConfigFile "cf-a" with most options - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigFile", "cf-a-cf-a")).To(HaveExactElements( - // quirk: Python SDK applies resource_prefix ("cf-a") to the component itself. + // ConfigFile "cf-options" with most options + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigFile", "cf-options-cf-options")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("cf-options") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": ConsistOf(Alias("cf-a-old"), Alias("cf-a-cf-a-aliased")), + "Aliases": ConsistOf(Alias("cf-options-old"), Alias("cf-options-cf-options-aliased")), "Protect": BeTrue(), "Dependencies": ConsistOf(string(sleep.URN)), "Provider": BeEmpty(), @@ -707,10 +707,10 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-a-cf-a"), "kubernetes:core/v1:ConfigMap", "cf-a-configfile-cm-1")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-options-cf-options"), "kubernetes:core/v1:ConfigMap", "cf-options-configfile-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": ConsistOf(Alias("configfile-cm-1-k8s-aliased"), Alias("cf-a-configfile-cm-1-aliased")), + "Aliases": ConsistOf(Alias("configfile-cm-1-k8s-aliased"), Alias("cf-options-configfile-cm-1-aliased")), "Protect": BeTrue(), "Dependencies": BeEmpty(), "Provider": BeEquivalentTo(providerUrn(providerA)), @@ -727,9 +727,9 @@ func TestOptionPropagation(t *testing.T) { }), )) - // ConfigFile "cf-b" with "provider" option that should propagate to children. - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigFile", "cf-b-cf-b")).To(HaveExactElements( - // quirk: Python SDK applies resource_prefix ("cf-b") to the component itself. + // ConfigFile "cf-provider" with "provider" option that should propagate to children. + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigFile", "cf-provider-cf-provider")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("cf-provider") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEmpty(), @@ -740,7 +740,7 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-b-cf-b"), "kubernetes:core/v1:ConfigMap", "cf-b-configfile-cm-1")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-provider-cf-provider"), "kubernetes:core/v1:ConfigMap", "cf-provider-configfile-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEquivalentTo(providerUrn(providerB)), @@ -771,12 +771,12 @@ func TestOptionPropagation(t *testing.T) { // --- Directory --- - // Directory "kustomize-a" with most options - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:kustomize:Directory", "kustomize-a-kustomize-a")).To(HaveExactElements( - // quirk: Python SDK applies resource_prefix ("kustomize-a") to the component itself. + // Directory "kustomize-options" with most options + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:kustomize:Directory", "kustomize-options-kustomize-options")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("kustomize-options") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": ConsistOf(Alias("kustomize-a-old"), Alias("kustomize-a-kustomize-a-aliased")), + "Aliases": ConsistOf(Alias("kustomize-options-old"), Alias("kustomize-options-kustomize-options-aliased")), "Protect": BeTrue(), "Dependencies": ConsistOf(string(sleep.URN)), "Provider": BeEmpty(), @@ -788,10 +788,10 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-a-kustomize-a"), "kubernetes:core/v1:ConfigMap", "kustomize-a-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-options-kustomize-options"), "kubernetes:core/v1:ConfigMap", "kustomize-options-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": ConsistOf(Alias("kustomize-cm-1-2kkk4bthmg-k8s-aliased"), Alias("kustomize-a-kustomize-cm-1-2kkk4bthmg-aliased")), + "Aliases": ConsistOf(Alias("kustomize-cm-1-2kkk4bthmg-k8s-aliased"), Alias("kustomize-options-kustomize-cm-1-2kkk4bthmg-aliased")), "Protect": BeTrue(), "Dependencies": BeEmpty(), "Provider": BeEquivalentTo(providerUrn(providerA)), @@ -808,9 +808,9 @@ func TestOptionPropagation(t *testing.T) { }), )) - // Directory "kustomize-b" with "provider" option that should propagate to children. - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:kustomize:Directory", "kustomize-b-kustomize-b")).To(HaveExactElements( - // quirk: Python SDK applies resource_prefix ("kustomize-b") to the component itself. + // Directory "kustomize-provider" with "provider" option that should propagate to children. + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:kustomize:Directory", "kustomize-provider-kustomize-provider")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("kustomize-provider") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEmpty(), @@ -821,7 +821,7 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-b-kustomize-b"), "kubernetes:core/v1:ConfigMap", "kustomize-b-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-provider-kustomize-provider"), "kubernetes:core/v1:ConfigMap", "kustomize-provider-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEquivalentTo(providerUrn(providerB)), @@ -847,12 +847,12 @@ func TestOptionPropagation(t *testing.T) { // --- Chart --- - // Chart "chart-a" - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:helm.sh/v3:Chart", "chart-a-chart-a")).To(HaveExactElements( - // quirk: Python SDK applies resource_prefix ("chart-a") to the component itself. + // Chart "chart-options" + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:helm.sh/v3:Chart", "chart-options-chart-options")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("chart-options") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": ConsistOf(Alias("chart-a-old"), Alias("chart-a-chart-a-aliased"), AliasByType("kubernetes:helm.sh/v2:Chart")), + "Aliases": ConsistOf(Alias("chart-options-old"), Alias("chart-options-chart-options-aliased"), AliasByType("kubernetes:helm.sh/v2:Chart")), "Protect": BeTrue(), "Dependencies": ConsistOf(string(sleep.URN)), "Provider": BeEmpty(), @@ -864,11 +864,11 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-a-chart-a"), "kubernetes:core/v1:ConfigMap", "chart-a-chart-a-cm-1")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-options-chart-options"), "kubernetes:core/v1:ConfigMap", "chart-options-chart-options-cm-1")).To(HaveExactElements( // quirk: Python SDK does NOT directly apply resource_prefix to the child resources (unlike other SDKs) MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": ConsistOf(Alias("chart-a-chart-a-cm-1-k8s-aliased"), Alias("chart-a-chart-a-cm-1-aliased")), + "Aliases": ConsistOf(Alias("chart-options-chart-options-cm-1-k8s-aliased"), Alias("chart-options-chart-options-cm-1-aliased")), "Protect": BeTrue(), "Dependencies": BeEmpty(), "Provider": BeEquivalentTo(providerUrn(providerA)), @@ -877,7 +877,7 @@ func TestOptionPropagation(t *testing.T) { "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ "metadata": MatchKeys(IgnoreExtras, Keys{ - "name": Equal("chart-a-chart-a-cm-1"), // note: based on the Helm Release name + "name": Equal("chart-options-chart-options-cm-1"), // note: based on the Helm Release name "annotations": And(HaveKey("pulumi.com/skipAwait")), }), }))), @@ -885,9 +885,9 @@ func TestOptionPropagation(t *testing.T) { }), )) - // Chart "chart-b" with "provider" option that should propagate to children. - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:helm.sh/v3:Chart", "chart-b-chart-b")).To(HaveExactElements( - // quirk: Python SDK applies resource_prefix ("chart-b") to the component itself. + // Chart "chart-provider" with "provider" option that should propagate to children. + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:helm.sh/v3:Chart", "chart-provider-chart-provider")).To(HaveExactElements( + // quirk: Python SDK applies resource_prefix ("chart-provider") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEmpty(), @@ -898,7 +898,7 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-b-chart-b"), "kubernetes:core/v1:ConfigMap", "chart-b-chart-b-cm-1")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-provider-chart-provider"), "kubernetes:core/v1:ConfigMap", "chart-provider-chart-provider-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEquivalentTo(providerUrn(providerB)), @@ -910,7 +910,7 @@ func TestOptionPropagation(t *testing.T) { // Chart "chart-nullopts" with a stack transform to apply a "provider" option. g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:helm.sh/v3:Chart", "chart-nullopts-chart-nullopts")).To(HaveExactElements( - // quirk: Python SDK applies resource_prefix ("chart-a") to the component itself. + // quirk: Python SDK applies resource_prefix ("chart-options") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEmpty(), From 3f6fb9e8cd01cf4c1e0b8293f56e6e733b43b923 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Thu, 7 Dec 2023 21:43:28 -0800 Subject: [PATCH 23/31] tests (NodeJS SDK) --- tests/gomega/matchers.go | 58 +++- tests/pulumirpc/rpc.go | 4 + tests/sdk/nodejs/nodejs_test.go | 434 ++++++++++++++++++++++++++ tests/sdk/nodejs/options/.gitignore | 2 + tests/sdk/nodejs/options/Pulumi.yaml | 5 + tests/sdk/nodejs/options/index.ts | 197 ++++++++++++ tests/sdk/nodejs/options/package.json | 12 + 7 files changed, 700 insertions(+), 12 deletions(-) create mode 100644 tests/sdk/nodejs/options/.gitignore create mode 100644 tests/sdk/nodejs/options/Pulumi.yaml create mode 100644 tests/sdk/nodejs/options/index.ts create mode 100644 tests/sdk/nodejs/options/package.json diff --git a/tests/gomega/matchers.go b/tests/gomega/matchers.go index c5f5cf4180..f2753fbff7 100644 --- a/tests/gomega/matchers.go +++ b/tests/gomega/matchers.go @@ -2,6 +2,8 @@ package gomega import ( + "fmt" + . "github.com/onsi/gomega" gomegatypes "github.com/onsi/gomega/types" "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" @@ -20,20 +22,52 @@ func ProtobufStruct(matcher gomegatypes.GomegaMatcher) gomegatypes.GomegaMatcher // Alias matches an Alias by its name. func Alias(name tokens.QName) gomegatypes.GomegaMatcher { - return WithTransform(func(actual *pulumirpc.Alias) string { - if actual.GetSpec() == nil { - return "" - } - return actual.GetSpec().Name - }, BeEquivalentTo(name)) + return &aliasNameMatcher{Name: name} } // AliasByType matches an Alias by its type. func AliasByType(typ tokens.Type) gomegatypes.GomegaMatcher { - return WithTransform(func(actual *pulumirpc.Alias) string { - if actual.GetSpec() == nil { - return "" - } - return actual.GetSpec().Type - }, BeEquivalentTo(typ)) + return &aliasTypeMatcher{Type: typ} +} + +type aliasNameMatcher struct { + Name tokens.QName +} + +var _ gomegatypes.GomegaMatcher = &aliasNameMatcher{} + +func (matcher *aliasNameMatcher) Match(actual interface{}) (success bool, err error) { + if alias, ok := actual.(*pulumirpc.Alias); ok { + return alias.GetSpec() != nil && alias.GetSpec().Name == string(matcher.Name), nil + } + return false, fmt.Errorf("aliasNameMatcher matcher expects a pulumirpc.Alias") +} + +func (matcher *aliasNameMatcher) FailureMessage(actual interface{}) (message string) { + return fmt.Sprintf("Expected:\n\t%#v\nto have name %q", actual, matcher.Name) +} + +func (matcher *aliasNameMatcher) NegatedFailureMessage(actual interface{}) (message string) { + return fmt.Sprintf("Expected:\n\t%#v\nnot to have name %q", actual, matcher.Name) +} + +type aliasTypeMatcher struct { + Type tokens.Type +} + +var _ gomegatypes.GomegaMatcher = &aliasTypeMatcher{} + +func (matcher *aliasTypeMatcher) Match(actual interface{}) (success bool, err error) { + if alias, ok := actual.(*pulumirpc.Alias); ok { + return alias.GetSpec() != nil && alias.GetSpec().Type == string(matcher.Type), nil + } + return false, fmt.Errorf("aliasTypeMatcher matcher expects a pulumirpc.Alias") +} + +func (matcher *aliasTypeMatcher) FailureMessage(actual interface{}) (message string) { + return fmt.Sprintf("Expected:\n\t%#v\nto have type %q", actual, matcher.Type) +} + +func (matcher *aliasTypeMatcher) NegatedFailureMessage(actual interface{}) (message string) { + return fmt.Sprintf("Expected:\n\t%#v\nnot to have type %q", actual, matcher.Type) } diff --git a/tests/pulumirpc/rpc.go b/tests/pulumirpc/rpc.go index 6b08e2a41f..7315b16368 100644 --- a/tests/pulumirpc/rpc.go +++ b/tests/pulumirpc/rpc.go @@ -11,6 +11,7 @@ import ( "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" "github.com/pulumi/pulumi/sdk/v3/go/common/util/contract" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go" ) @@ -111,6 +112,9 @@ func FormatDebugInterceptorLog(value interface{}) (string, bool) { if m, ok := value.(pulumirpc.RegisterResourceResponse); ok { return protojson.Format(&m), true } + if m, ok := value.(pulumirpc.Alias); ok { + return protojson.Format(&m), true + } return "", false } diff --git a/tests/sdk/nodejs/nodejs_test.go b/tests/sdk/nodejs/nodejs_test.go index a4609f2906..9b98cc326f 100644 --- a/tests/sdk/nodejs/nodejs_test.go +++ b/tests/sdk/nodejs/nodejs_test.go @@ -29,14 +29,23 @@ import ( "testing" "time" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/format" + . "github.com/onsi/gomega/gstruct" "github.com/pulumi/pulumi-kubernetes/provider/v4/pkg/openapi" "github.com/pulumi/pulumi-kubernetes/tests/v4" + . "github.com/pulumi/pulumi-kubernetes/tests/v4/gomega" + pulumirpctesting "github.com/pulumi/pulumi-kubernetes/tests/v4/pulumirpc" + "github.com/pulumi/pulumi/pkg/v3/engine" "github.com/pulumi/pulumi/pkg/v3/resource/deploy/providers" "github.com/pulumi/pulumi/pkg/v3/testing/integration" "github.com/pulumi/pulumi/sdk/v3/go/common/apitype" "github.com/pulumi/pulumi/sdk/v3/go/common/resource" "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" + "github.com/pulumi/pulumi/sdk/v3/go/common/util/contract" + "github.com/pulumi/pulumi/sdk/v3/go/common/util/fsutil" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/client-go/tools/clientcmd" ) @@ -46,6 +55,9 @@ var baseOptions = &integration.ProgramTestOptions{ Dependencies: []string{ "@pulumi/kubernetes", }, + PostPrepareProject: func(p *engine.Projinfo) error { + return fsutil.CopyFile(filepath.Join(p.Root, "testdata"), filepath.Join("..", "..", "testdata"), nil) + }, Env: []string{ "PULUMI_K8S_CLIENT_BURST=200", "PULUMI_K8S_CLIENT_QPS=100", @@ -2008,3 +2020,425 @@ func TestEmptyItemNormalization(t *testing.T) { integration.ProgramTest(t, &test) } + +// TestOptionPropagation tests the handling of resource options by the various compoonent resources. +// Component resources are responsible for implementing option propagation logic when creating +// child resources. +func TestOptionPropagation(t *testing.T) { + g := NewWithT(t) + format.MaxLength = 0 + format.MaxDepth = 5 + // format.UseStringerRepresentation = true + format.RegisterCustomFormatter(pulumirpctesting.FormatDebugInterceptorLog) + + cwd, err := os.Getwd() + if !assert.NoError(t, err) { + t.FailNow() + } + + grpcLog, err := pulumirpctesting.NewDebugInterceptorLog() + require.NoError(t, err) + + options := baseOptions.With(integration.ProgramTestOptions{ + Dir: filepath.Join(cwd, "options"), + Env: []string{grpcLog.Env()}, + Quick: true, + ExpectRefreshChanges: false, + ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { + + // lookup some resources for later use + providerA := tests.SearchResourcesByName(stackInfo, "", "pulumi:providers:kubernetes", "a") + require.NotNil(t, providerA) + providerB := tests.SearchResourcesByName(stackInfo, "", "pulumi:providers:kubernetes", "b") + require.NotNil(t, providerB) + providerNullOpts := tests.SearchResourcesByName(stackInfo, "", "pulumi:providers:kubernetes", "nullopts") + require.NotNil(t, providerNullOpts) + sleep := tests.SearchResourcesByName(stackInfo, "", "time:index/sleep:Sleep", "sleep") + require.NotNil(t, sleep) + + // some helper functions for naming purposes + providerUrn := func(prov *apitype.ResourceV3) resource.URN { + return prov.URN + resource.URNNameDelimiter + resource.URN(prov.ID) + } + urn := func(parentType, baseType tokens.Type, name tokens.QName) resource.URN { + return resource.NewURN(stackInfo.StackName, "options-test", parentType, baseType, name) + } + + // read the GRPC log file to inspect the RegisterResource calls, since they provide + // the most detailed view of the resource's options as determined by the SDK. + logEntries, err := grpcLog.ReadAll() + require.NoError(t, err) + rr := logEntries.ListRegisterResource() + + // --- ConfigGroup --- + + // ConfigGroup "cg-options" with most options + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:yaml:ConfigGroup", "cg-options")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("cg-options-old"), Alias("cg-options-aliased")), + "Protect": BeTrue(), + "Dependencies": HaveExactElements(string(sleep.URN)), + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerA)), + }), + "IgnoreChanges": HaveExactElements("ignored"), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigGroup", "cg-options"), + "kubernetes:core/v1:ConfigMap", "cg-options-cg-options-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("cg-options-cm-1-k8s-aliased"), Alias("cg-options-cg-options-cm-1-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("cg-options-cm-1"), + "annotations": And(HaveKey("pulumi.com/skipAwait"), HaveKey("transformed")), + }), + }))), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigGroup", "cg-options"), + "kubernetes:yaml:ConfigFile", "cg-options-./testdata/options/configgroup/manifest.yaml")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("cg-options-./testdata/options/configgroup/manifest.yaml-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEmpty(), + "Version": BeEmpty(), + // quirk: unlike Python SDK, there's no providers on the intermediate ConfigFile. + // "Providers": MatchAllKeys(Keys{ + // "kubernetes": BeEquivalentTo(providerUrn(providerA)), + // }), + }), + }), + )) + g.Expect(rr.Named(urn("kubernetes:yaml:ConfigGroup", "kubernetes:yaml:ConfigFile", "cg-options-./testdata/options/configgroup/manifest.yaml"), + "kubernetes:core/v1:ConfigMap", "cg-options-configgroup-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("configgroup-cm-1-k8s-aliased"), Alias("cg-options-configgroup-cm-1-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("configgroup-cm-1"), + "annotations": And(HaveKey("pulumi.com/skipAwait"), HaveKey("transformed")), + }), + }))), + }), + }), + )) + + // ConfigGroup "cg-provider" with "provider" option that should propagate to children. + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:yaml:ConfigGroup", "cg-provider")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerB)), + }), + }), + }), + )) + + // ConfigGroup "cg-nullopts" with a stack transform to apply a "provider" option. + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:yaml:ConfigGroup", "cg-nullopts")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerNullOpts)), + }), + }), + }), + )) + + // --- ConfigFile --- + + // ConfigFile "cf-options" with most options + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:yaml:ConfigFile", "cf-options-cf-options")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("cf-options") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("cf-options-old"), Alias("cf-options-cf-options-aliased")), + "Protect": BeTrue(), + "Dependencies": HaveExactElements(string(sleep.URN)), + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerA)), + }), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-options-cf-options"), + "kubernetes:core/v1:ConfigMap", "cf-options-configfile-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("configfile-cm-1-k8s-aliased"), Alias("cf-options-configfile-cm-1-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("configfile-cm-1"), + "annotations": And(HaveKey("pulumi.com/skipAwait"), HaveKey("transformed")), + }), + }))), + }), + }), + )) + + // ConfigFile "cf-provider" with "provider" option that should propagate to children. + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:yaml:ConfigFile", "cf-provider-cf-provider")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("cf-provider") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerB)), + }), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-provider-cf-provider"), + "kubernetes:core/v1:ConfigMap", "cf-provider-configfile-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerB)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("configfile-cm-1"), + }), + }))), + }), + }), + )) + + // ConfigFile "cf-nullopts" with a stack transform to apply a "provider" option. + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:yaml:ConfigFile", "cf-nullopts-cf-nullopts")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("cf-nullopts") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerNullOpts)), + }), + }), + }), + )) + + // --- Directory --- + + // Directory "kustomize-options" with most options + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:kustomize:Directory", "kustomize-options-kustomize-options")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("kustomize-options") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("kustomize-options-old"), Alias("kustomize-options-kustomize-options-aliased")), + "Protect": BeTrue(), + "Dependencies": HaveExactElements(string(sleep.URN)), + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerA)), + }), + "IgnoreChanges": HaveExactElements("ignored"), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-options-kustomize-options"), + "kubernetes:core/v1:ConfigMap", "kustomize-options-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("kustomize-cm-1-2kkk4bthmg-k8s-aliased"), Alias("kustomize-options-kustomize-cm-1-2kkk4bthmg-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("kustomize-cm-1-2kkk4bthmg"), + "annotations": And(HaveKey("transformed")), + }), + }))), + }), + }), + )) + + // Directory "kustomize-provider" with "provider" option that should propagate to children. + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:kustomize:Directory", "kustomize-provider-kustomize-provider")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("kustomize-provider") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerB)), + }), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-provider-kustomize-provider"), + "kubernetes:core/v1:ConfigMap", "kustomize-provider-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerB)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + }), + }), + )) + + // Directory "kustomize-nullopts" with a stack transform to apply a "provider" option. + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:kustomize:Directory", "kustomize-nullopts-kustomize-nullopts")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("kustomize-nullopts") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerNullOpts)), + }), + }), + }), + )) + + // --- Chart --- + + // Chart "chart-options" + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:helm.sh/v3:Chart", "chart-options-chart-options")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("chart-options") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(AliasByType("kubernetes:helm.sh/v2:Chart"), Alias("chart-options-old"), Alias("chart-options-chart-options-aliased")), + "Protect": BeTrue(), + "Dependencies": HaveExactElements(string(sleep.URN)), + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerA)), + }), + "IgnoreChanges": HaveExactElements("ignored"), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-options-chart-options"), + "kubernetes:core/v1:ConfigMap", "chart-options-chart-options-chart-options-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("chart-options-chart-options-cm-1-k8s-aliased"), Alias("chart-options-chart-options-chart-options-cm-1-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("chart-options-chart-options-cm-1"), // note: based on the Helm Release name + "annotations": And(HaveKey("pulumi.com/skipAwait")), + }), + }))), + }), + }), + )) + + // Chart "chart-provider" with "provider" option that should propagate to children. + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:helm.sh/v3:Chart", "chart-provider-chart-provider")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("chart-provider") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerB)), + }), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-provider-chart-provider"), + "kubernetes:core/v1:ConfigMap", "chart-provider-chart-provider-chart-provider-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerB)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + }), + }), + )) + + // Chart "chart-nullopts" with a stack transform to apply a "provider" option. + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:helm.sh/v3:Chart", "chart-nullopts-chart-nullopts")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("chart-options") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEmpty(), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerNullOpts)), + }), + }), + }), + )) + }, + }) + + pt := integration.ProgramTestManualLifeCycle(t, &options) + + err = pt.TestLifeCyclePrepare() + require.NoError(t, err) + t.Cleanup(pt.TestCleanUp) + err = pt.TestLifeCycleInitialize() + require.NoError(t, err) + t.Cleanup(func() { + // to ensure cleanup, we need to unprotected all resources + err = pt.RunPulumiCommand("state", "unprotect", "--all", "-y") + contract.IgnoreError(err) + + destroyErr := pt.TestLifeCycleDestroy() + contract.IgnoreError(destroyErr) + }) + + err = pt.TestPreviewUpdateAndEdits() + require.NoError(t, err) +} diff --git a/tests/sdk/nodejs/options/.gitignore b/tests/sdk/nodejs/options/.gitignore new file mode 100644 index 0000000000..c6958891dd --- /dev/null +++ b/tests/sdk/nodejs/options/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/node_modules/ diff --git a/tests/sdk/nodejs/options/Pulumi.yaml b/tests/sdk/nodejs/options/Pulumi.yaml new file mode 100644 index 0000000000..9d836a638a --- /dev/null +++ b/tests/sdk/nodejs/options/Pulumi.yaml @@ -0,0 +1,5 @@ +name: options-test +runtime: nodejs +description: A minimal Kubernetes TypeScript Pulumi program +config: + pulumi:disable-default-providers: [kubernetes] diff --git a/tests/sdk/nodejs/options/index.ts b/tests/sdk/nodejs/options/index.ts new file mode 100644 index 0000000000..565f1e185f --- /dev/null +++ b/tests/sdk/nodejs/options/index.ts @@ -0,0 +1,197 @@ +import * as pulumi from "@pulumi/pulumi"; +import * as k8s from "@pulumi/kubernetes"; +import * as time from "@pulumiverse/time"; + +const config = new pulumi.Config(); + +const bootstrapProvider = new k8s.Provider("bootstrap", {}); + +// create a set of providers across namespaces, simply to facilitate the reuse of manifests in the below tests. +const nulloptsNs = new k8s.core.v1.Namespace("nullopts", {}, { provider: bootstrapProvider }); +const aNs = new k8s.core.v1.Namespace("a", {}, { provider: bootstrapProvider }); +const bNs = new k8s.core.v1.Namespace("b", {}, { provider: bootstrapProvider }); +const nulloptsProvider = new k8s.Provider("nullopts", { namespace: nulloptsNs.metadata["name"] }) +const aProvider = new k8s.Provider("a", { namespace: aNs.metadata["name"] }) +const bProvider = new k8s.Provider("b", { namespace: bNs.metadata["name"] }) + +// a sleep resource to exercise the "depends_on" component-level option +const sleep = new time.Sleep("sleep", { createDuration: "1s" }, { dependsOn: [aProvider, bProvider] }); + +// apply_default_opts is a stack transformation that applies default opts to any resource whose name ends with "-nullopts". +// this is intended to be applied to component resources only. +function applyDefaultOpts(args: pulumi.ResourceTransformationArgs): pulumi.ResourceTransformationResult | undefined { + if (args.name.endsWith("-nullopts")) { + return { + props: args.props, + opts: pulumi.mergeOptions(args.opts, { + provider: nulloptsProvider, + }), + }; + } + return undefined; +} +pulumi.runtime.registerStackTransformation(applyDefaultOpts); + +// applyAlias is a Pulumi transformation that applies a unique alias to each resource. +function applyAlias(args: pulumi.ResourceTransformationArgs): pulumi.ResourceTransformationResult | undefined { + return { + props: args.props, + opts: pulumi.mergeOptions(args.opts, { + aliases: [{ name: `${args.name}-aliased` }], + // aliases: [{ name: `${args.name}-aliased` }, ...(args.opts.aliases ?? [])], + }), + }; +} + +// transform_k8s is a Kubernetes transformation that applies a unique alias and annotation to each resource. +function transformK8s(obj: any, opts: pulumi.CustomResourceOptions) { + opts.aliases = [{ name: `${obj.metadata.name}-k8s-aliased` }, ...(opts.aliases ?? [])] + obj.metadata.annotations = { "transformed": "true" } +} + +// --- ConfigGroup --- +// options: providers, aliases, depends_on, ignore_changes, protect, transformations +// args: skip_await, transformations +new k8s.yaml.ConfigGroup("cg-options", { + resourcePrefix: "cg-options", + skipAwait: true, + transformations: [transformK8s], + files: ["./testdata/options/configgroup/*.yaml"], + yaml: [` +apiVersion: v1 +kind: ConfigMap +metadata: + name: cg-options-cm-1 +`], +}, + { + providers: [aProvider], + aliases: [{ name: "cg-options-old" }], + ignoreChanges: ["ignored"], + protect: true, + dependsOn: [sleep], + transformations: [applyAlias], + }); + +// "providers" option +new k8s.yaml.ConfigGroup("cg-providers", { + resourcePrefix: "cg-providers", + yaml: [` +apiVersion: v1 +kind: ConfigMap +metadata: + name: cg-providers-cm-1 +`], +}, { providers: [bProvider] }); + +// "provider" option +new k8s.yaml.ConfigGroup("cg-provider", { + resourcePrefix: "cg-provider", + yaml: [` +apiVersion: v1 +kind: ConfigMap +metadata: + name: cg-provider-cm-1 +`], +}, { provider: bProvider }); + +// null opts +new k8s.yaml.ConfigGroup("cg-nullopts", { + resourcePrefix: "cg-nullopts", + yaml: [` +apiVersion: v1 +kind: ConfigMap +metadata: + name: cg-nullopts-cm-1 +`], +}); + +// --- ConfigFile --- +new k8s.yaml.ConfigFile("cf-options", { + resourcePrefix: "cf-options", + skipAwait: true, + transformations: [transformK8s], + file: "./testdata/options/configfile/manifest.yaml", +}, { + providers: [aProvider], + aliases: [{ name: "cf-options-old" }], + ignoreChanges: ["ignored"], + protect: true, + dependsOn: [sleep], + transformations: [applyAlias], +}); + +// "provider" option +new k8s.yaml.ConfigFile("cf-provider", { + resourcePrefix: "cf-provider", + file: "./testdata/options/configfile/manifest.yaml", +}, { provider: bProvider }); + +// null opts +new k8s.yaml.ConfigFile("cf-nullopts", { + resourcePrefix: "cf-nullopts", + file: "./testdata/options/configfile/manifest.yaml", +}); + +// empty manifest +new k8s.yaml.ConfigFile("cf-empty", { + resourcePrefix: "cf-empty", + file: "./testdata/options/configfile/empty.yaml", +}, { providers: [bProvider] }); + +// --- Directory --- +new k8s.kustomize.Directory("kustomize-options", { + directory: "./testdata/options/kustomize", + resourcePrefix: "kustomize-options", + transformations: [transformK8s], +}, { + providers: [aProvider], + aliases: [{ name: "kustomize-options-old" }], + ignoreChanges: ["ignored"], + protect: true, + dependsOn: [sleep], + transformations: [applyAlias], +}); + +// "provider" option +new k8s.kustomize.Directory("kustomize-provider", { + directory: "./testdata/options/kustomize", + resourcePrefix: "kustomize-provider", +}, { provider: bProvider }); + +// null opts +new k8s.kustomize.Directory("kustomize-nullopts", { + directory: "./testdata/options/kustomize", + resourcePrefix: "kustomize-nullopts", +}); + +// --- Chart --- +// options: providers, aliases, depends_on, ignore_changes, protect, transformations +// args: transformations +new k8s.helm.v3.Chart("chart-options", { + path: "./testdata/options/chart", + resourcePrefix: "chart-options", + transformations: [transformK8s], + skipAwait: true, +}, { + providers: [aProvider], + aliases: [{ name: "chart-options-old" }], + ignoreChanges: ["ignored"], + protect: true, + dependsOn: [sleep], + transformations: [applyAlias], +}); + +// "provider" option +new k8s.helm.v3.Chart("chart-provider", { + path: "./testdata/options/chart", + resourcePrefix: "chart-provider", +}, { provider: bProvider }); + +// null opts +new k8s.helm.v3.Chart("chart-nullopts", { + path: "./testdata/options/chart", + resourcePrefix: "chart-nullopts", +}); + + diff --git a/tests/sdk/nodejs/options/package.json b/tests/sdk/nodejs/options/package.json new file mode 100644 index 0000000000..cb56da9aaa --- /dev/null +++ b/tests/sdk/nodejs/options/package.json @@ -0,0 +1,12 @@ +{ + "name": "options-test", + "main": "index.ts", + "devDependencies": { + "@types/node": "^16" + }, + "dependencies": { + "@pulumi/pulumi": "^3.0.0", + "@pulumi/kubernetes": "^4.0.0", + "@pulumiverse/time": "^0.0.16" + } +} From 25a47e2c0ac1a57bd5fb2820e079db82975ed4d3 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Thu, 7 Dec 2023 21:43:48 -0800 Subject: [PATCH 24/31] bugfix: Chart aliases (NodeJS SDK) --- provider/pkg/gen/nodejs-templates/helm/v3/helm.ts | 2 +- sdk/nodejs/helm/v3/helm.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/provider/pkg/gen/nodejs-templates/helm/v3/helm.ts b/provider/pkg/gen/nodejs-templates/helm/v3/helm.ts index 25a29789b1..490e3dbc47 100644 --- a/provider/pkg/gen/nodejs-templates/helm/v3/helm.ts +++ b/provider/pkg/gen/nodejs-templates/helm/v3/helm.ts @@ -155,7 +155,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"}, ...(opts?.aliases ?? [])]} super(Chart.__pulumiType, releaseName, config, aliasOpts); const allConfig = pulumi.output(config); diff --git a/sdk/nodejs/helm/v3/helm.ts b/sdk/nodejs/helm/v3/helm.ts index 25a29789b1..490e3dbc47 100644 --- a/sdk/nodejs/helm/v3/helm.ts +++ b/sdk/nodejs/helm/v3/helm.ts @@ -155,7 +155,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"}, ...(opts?.aliases ?? [])]} super(Chart.__pulumiType, releaseName, config, aliasOpts); const allConfig = pulumi.output(config); From 266c7c40287a6a73e70f5cb0d4c99a1d6563c00e Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Fri, 8 Dec 2023 10:18:43 -0800 Subject: [PATCH 25/31] cleanups --- tests/gomega/matchers.go | 4 +- tests/pulumirpc/rpc.go | 1 - tests/sdk/python/python_test.go | 69 +++++++++++++++++++++------------ 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/tests/gomega/matchers.go b/tests/gomega/matchers.go index f2753fbff7..a8545ca4db 100644 --- a/tests/gomega/matchers.go +++ b/tests/gomega/matchers.go @@ -40,7 +40,7 @@ func (matcher *aliasNameMatcher) Match(actual interface{}) (success bool, err er if alias, ok := actual.(*pulumirpc.Alias); ok { return alias.GetSpec() != nil && alias.GetSpec().Name == string(matcher.Name), nil } - return false, fmt.Errorf("aliasNameMatcher matcher expects a pulumirpc.Alias") + return false, fmt.Errorf("aliasNameMatcher matcher expects a *pulumirpc.Alias") } func (matcher *aliasNameMatcher) FailureMessage(actual interface{}) (message string) { @@ -61,7 +61,7 @@ func (matcher *aliasTypeMatcher) Match(actual interface{}) (success bool, err er if alias, ok := actual.(*pulumirpc.Alias); ok { return alias.GetSpec() != nil && alias.GetSpec().Type == string(matcher.Type), nil } - return false, fmt.Errorf("aliasTypeMatcher matcher expects a pulumirpc.Alias") + return false, fmt.Errorf("aliasTypeMatcher matcher expects a *pulumirpc.Alias") } func (matcher *aliasTypeMatcher) FailureMessage(actual interface{}) (message string) { diff --git a/tests/pulumirpc/rpc.go b/tests/pulumirpc/rpc.go index 7315b16368..6d5c1452e5 100644 --- a/tests/pulumirpc/rpc.go +++ b/tests/pulumirpc/rpc.go @@ -11,7 +11,6 @@ import ( "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" "github.com/pulumi/pulumi/sdk/v3/go/common/util/contract" "google.golang.org/protobuf/encoding/protojson" - "google.golang.org/protobuf/proto" pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go" ) diff --git a/tests/sdk/python/python_test.go b/tests/sdk/python/python_test.go index 344108b377..97e9282b57 100644 --- a/tests/sdk/python/python_test.go +++ b/tests/sdk/python/python_test.go @@ -25,11 +25,8 @@ import ( "strings" "testing" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - - "github.com/onsi/gomega/format" - . "github.com/onsi/gomega" + "github.com/onsi/gomega/format" . "github.com/onsi/gomega/gstruct" "github.com/pulumi/pulumi-kubernetes/provider/v4/pkg/openapi" "github.com/pulumi/pulumi-kubernetes/tests/v4" @@ -45,6 +42,7 @@ import ( "github.com/pulumi/pulumi/sdk/v3/go/common/util/fsutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) var baseOptions = &integration.ProgramTestOptions{ @@ -594,7 +592,8 @@ func TestOptionPropagation(t *testing.T) { // --- ConfigGroup --- // ConfigGroup "cg-options" with most options - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigGroup", "cg-options-cg-options")).To(HaveExactElements( + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:yaml:ConfigGroup", "cg-options-cg-options")).To(HaveExactElements( // quirk: Python SDK applies resource_prefix ("cg-options") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ @@ -610,7 +609,8 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigGroup", "cg-options-cg-options"), "kubernetes:core/v1:ConfigMap", "cg-options-cg-options-cm-1")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigGroup", "cg-options-cg-options"), + "kubernetes:core/v1:ConfigMap", "cg-options-cg-options-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Aliases": ConsistOf(Alias("cg-options-cm-1-k8s-aliased"), Alias("cg-options-cg-options-cm-1-aliased")), @@ -629,7 +629,8 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigGroup", "cg-options-cg-options"), "kubernetes:yaml:ConfigFile", "cg-options-./testdata/options/configgroup/manifest.yaml")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigGroup", "cg-options-cg-options"), + "kubernetes:yaml:ConfigFile", "cg-options-./testdata/options/configgroup/manifest.yaml")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Aliases": ConsistOf(Alias("cg-options-./testdata/options/configgroup/manifest.yaml-aliased")), @@ -643,7 +644,8 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("kubernetes:yaml:ConfigGroup", "kubernetes:yaml:ConfigFile", "cg-options-./testdata/options/configgroup/manifest.yaml"), "kubernetes:core/v1:ConfigMap", "cg-options-configgroup-cm-1")).To(HaveExactElements( + g.Expect(rr.Named(urn("kubernetes:yaml:ConfigGroup", "kubernetes:yaml:ConfigFile", "cg-options-./testdata/options/configgroup/manifest.yaml"), + "kubernetes:core/v1:ConfigMap", "cg-options-configgroup-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Aliases": ConsistOf(Alias("configgroup-cm-1-k8s-aliased"), Alias("cg-options-configgroup-cm-1-aliased")), @@ -664,7 +666,8 @@ func TestOptionPropagation(t *testing.T) { )) // ConfigGroup "cg-provider" with "provider" option that should propagate to children. - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigGroup", "cg-provider-cg-provider")).To(HaveExactElements( + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:yaml:ConfigGroup", "cg-provider-cg-provider")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEmpty(), @@ -677,7 +680,8 @@ func TestOptionPropagation(t *testing.T) { )) // ConfigGroup "cg-nullopts" with a stack transform to apply a "provider" option. - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigGroup", "cg-nullopts-cg-nullopts")).To(HaveExactElements( + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:yaml:ConfigGroup", "cg-nullopts-cg-nullopts")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEmpty(), @@ -692,7 +696,8 @@ func TestOptionPropagation(t *testing.T) { // --- ConfigFile --- // ConfigFile "cf-options" with most options - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigFile", "cf-options-cf-options")).To(HaveExactElements( + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:yaml:ConfigFile", "cf-options-cf-options")).To(HaveExactElements( // quirk: Python SDK applies resource_prefix ("cf-options") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ @@ -707,7 +712,8 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-options-cf-options"), "kubernetes:core/v1:ConfigMap", "cf-options-configfile-cm-1")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-options-cf-options"), + "kubernetes:core/v1:ConfigMap", "cf-options-configfile-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Aliases": ConsistOf(Alias("configfile-cm-1-k8s-aliased"), Alias("cf-options-configfile-cm-1-aliased")), @@ -728,7 +734,8 @@ func TestOptionPropagation(t *testing.T) { )) // ConfigFile "cf-provider" with "provider" option that should propagate to children. - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigFile", "cf-provider-cf-provider")).To(HaveExactElements( + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:yaml:ConfigFile", "cf-provider-cf-provider")).To(HaveExactElements( // quirk: Python SDK applies resource_prefix ("cf-provider") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ @@ -740,7 +747,8 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-provider-cf-provider"), "kubernetes:core/v1:ConfigMap", "cf-provider-configfile-cm-1")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-provider-cf-provider"), + "kubernetes:core/v1:ConfigMap", "cf-provider-configfile-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEquivalentTo(providerUrn(providerB)), @@ -756,7 +764,8 @@ func TestOptionPropagation(t *testing.T) { )) // ConfigFile "cf-nullopts" with a stack transform to apply a "provider" option. - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigFile", "cf-nullopts-cf-nullopts")).To(HaveExactElements( + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:yaml:ConfigFile", "cf-nullopts-cf-nullopts")).To(HaveExactElements( // quirk: Python SDK applies resource_prefix ("cf-nullopts") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ @@ -772,7 +781,8 @@ func TestOptionPropagation(t *testing.T) { // --- Directory --- // Directory "kustomize-options" with most options - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:kustomize:Directory", "kustomize-options-kustomize-options")).To(HaveExactElements( + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:kustomize:Directory", "kustomize-options-kustomize-options")).To(HaveExactElements( // quirk: Python SDK applies resource_prefix ("kustomize-options") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ @@ -788,7 +798,8 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-options-kustomize-options"), "kubernetes:core/v1:ConfigMap", "kustomize-options-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-options-kustomize-options"), + "kubernetes:core/v1:ConfigMap", "kustomize-options-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Aliases": ConsistOf(Alias("kustomize-cm-1-2kkk4bthmg-k8s-aliased"), Alias("kustomize-options-kustomize-cm-1-2kkk4bthmg-aliased")), @@ -809,7 +820,8 @@ func TestOptionPropagation(t *testing.T) { )) // Directory "kustomize-provider" with "provider" option that should propagate to children. - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:kustomize:Directory", "kustomize-provider-kustomize-provider")).To(HaveExactElements( + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:kustomize:Directory", "kustomize-provider-kustomize-provider")).To(HaveExactElements( // quirk: Python SDK applies resource_prefix ("kustomize-provider") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ @@ -821,7 +833,8 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-provider-kustomize-provider"), "kubernetes:core/v1:ConfigMap", "kustomize-provider-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-provider-kustomize-provider"), + "kubernetes:core/v1:ConfigMap", "kustomize-provider-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEquivalentTo(providerUrn(providerB)), @@ -832,7 +845,8 @@ func TestOptionPropagation(t *testing.T) { )) // Directory "kustomize-nullopts" with a stack transform to apply a "provider" option. - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:kustomize:Directory", "kustomize-nullopts-kustomize-nullopts")).To(HaveExactElements( + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:kustomize:Directory", "kustomize-nullopts-kustomize-nullopts")).To(HaveExactElements( // quirk: Python SDK applies resource_prefix ("kustomize-nullopts") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ @@ -848,7 +862,8 @@ func TestOptionPropagation(t *testing.T) { // --- Chart --- // Chart "chart-options" - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:helm.sh/v3:Chart", "chart-options-chart-options")).To(HaveExactElements( + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:helm.sh/v3:Chart", "chart-options-chart-options")).To(HaveExactElements( // quirk: Python SDK applies resource_prefix ("chart-options") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ @@ -864,7 +879,8 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-options-chart-options"), "kubernetes:core/v1:ConfigMap", "chart-options-chart-options-cm-1")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-options-chart-options"), + "kubernetes:core/v1:ConfigMap", "chart-options-chart-options-cm-1")).To(HaveExactElements( // quirk: Python SDK does NOT directly apply resource_prefix to the child resources (unlike other SDKs) MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ @@ -886,7 +902,8 @@ func TestOptionPropagation(t *testing.T) { )) // Chart "chart-provider" with "provider" option that should propagate to children. - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:helm.sh/v3:Chart", "chart-provider-chart-provider")).To(HaveExactElements( + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:helm.sh/v3:Chart", "chart-provider-chart-provider")).To(HaveExactElements( // quirk: Python SDK applies resource_prefix ("chart-provider") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ @@ -898,7 +915,8 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-provider-chart-provider"), "kubernetes:core/v1:ConfigMap", "chart-provider-chart-provider-cm-1")).To(HaveExactElements( + g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-provider-chart-provider"), + "kubernetes:core/v1:ConfigMap", "chart-provider-chart-provider-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEquivalentTo(providerUrn(providerB)), @@ -909,7 +927,8 @@ func TestOptionPropagation(t *testing.T) { )) // Chart "chart-nullopts" with a stack transform to apply a "provider" option. - g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:helm.sh/v3:Chart", "chart-nullopts-chart-nullopts")).To(HaveExactElements( + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:helm.sh/v3:Chart", "chart-nullopts-chart-nullopts")).To(HaveExactElements( // quirk: Python SDK applies resource_prefix ("chart-options") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ From b4fd7b6149f83974135908ae4671721b3979474f Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 11 Dec 2023 09:37:53 -0800 Subject: [PATCH 26/31] p/p 3.96 --- provider/pkg/metadata/naming.go | 4 +- provider/pkg/provider/helm_release.go | 2 +- tests/go.mod | 79 +++++------ tests/go.sum | 182 ++++++++++++-------------- 4 files changed, 116 insertions(+), 151 deletions(-) diff --git a/provider/pkg/metadata/naming.go b/provider/pkg/metadata/naming.go index ed5de80dc7..2cd866c631 100644 --- a/provider/pkg/metadata/naming.go +++ b/provider/pkg/metadata/naming.go @@ -23,7 +23,7 @@ import ( // AssignNameIfAutonamable generates a name for an object. Uses DNS-1123-compliant characters. // All auto-named resources get the annotation `pulumi.com/autonamed` for tooling purposes. func AssignNameIfAutonamable(randomSeed []byte, obj *unstructured.Unstructured, propMap resource.PropertyMap, urn resource.URN) { - contract.Assertf(urn.Name().String() != "", "expected non-empty name in URN: %s", urn) + contract.Assertf(urn.Name() != "", "expected non-empty name in URN: %s", urn) // Check if the .metadata.name is set and is a computed value. If so, do not auto-name. if md, ok := propMap["metadata"].V.(resource.PropertyMap); ok { if name, ok := md["name"]; ok && name.IsComputed() { @@ -32,7 +32,7 @@ func AssignNameIfAutonamable(randomSeed []byte, obj *unstructured.Unstructured, } if obj.GetName() == "" { - prefix := urn.Name().String() + "-" + prefix := urn.Name() + "-" autoname, err := resource.NewUniqueName(randomSeed, prefix, 0, 0, nil) contract.AssertNoErrorf(err, "unexpected error while creating NewUniqueName") obj.SetName(autoname) diff --git a/provider/pkg/provider/helm_release.go b/provider/pkg/provider/helm_release.go index f3bbbfc53e..0f0359a01c 100644 --- a/provider/pkg/provider/helm_release.go +++ b/provider/pkg/provider/helm_release.go @@ -651,7 +651,7 @@ func adoptOldNameIfUnnamed(new, old resource.PropertyMap) { func assignNameIfAutonameable(pm resource.PropertyMap, urn resource.URN) { name, ok := pm["name"] if !ok || (name.IsString() && name.StringValue() == "") { - prefix := urn.Name().String() + "-" + prefix := urn.Name() + "-" autoname, err := resource.NewUniqueHex(prefix, 0, 0) contract.AssertNoErrorf(err, "unexpected error while executing NewUniqueHex") pm["name"] = resource.NewStringProperty(autoname) diff --git a/tests/go.mod b/tests/go.mod index 6709faeee0..07eca5c362 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -8,12 +8,15 @@ replace ( ) require ( + github.com/onsi/gomega v1.27.10 github.com/pulumi/pulumi-kubernetes/provider/v4 v4.0.0 github.com/pulumi/pulumi-kubernetes/sdk/v4 v4.0.0 - github.com/pulumi/pulumi/pkg/v3 v3.81.0 - github.com/pulumi/pulumi/sdk/v3 v3.81.0 + github.com/pulumi/pulumi/pkg/v3 v3.96.2 + github.com/pulumi/pulumi/sdk/v3 v3.96.2 + github.com/pulumiverse/pulumi-time/sdk v0.0.0-20231010123146-089d7304da13 github.com/stretchr/testify v1.8.4 - golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa + google.golang.org/protobuf v1.31.0 helm.sh/helm/v3 v3.12.1 k8s.io/apimachinery v0.28.2 k8s.io/client-go v0.28.2 @@ -28,13 +31,9 @@ require ( cloud.google.com/go/logging v1.8.1 // indirect cloud.google.com/go/longrunning v0.5.1 // indirect cloud.google.com/go/storage v1.30.1 // indirect + dario.cat/mergo v1.0.0 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // indirect - github.com/AlecAivazis/survey/v2 v2.0.5 // indirect github.com/Azure/azure-sdk-for-go v66.0.0+incompatible // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.28 // indirect @@ -46,16 +45,15 @@ require ( github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0 // indirect github.com/BurntSushi/toml v1.2.1 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Masterminds/squirrel v1.5.4 // indirect - github.com/Microsoft/go-winio v0.6.0 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 // indirect - github.com/acomagu/bufpipe v1.0.3 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect + github.com/acomagu/bufpipe v1.0.4 // indirect github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/ahmetb/go-linq v3.0.0+incompatible // indirect @@ -66,21 +64,14 @@ require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/aws/aws-sdk-go v1.44.298 // indirect github.com/aws/aws-sdk-go-v2 v1.17.3 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3 // indirect github.com/aws/aws-sdk-go-v2/config v1.15.15 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.12.10 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.9 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.21 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.16 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.6 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.10 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.9 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.9 // indirect github.com/aws/aws-sdk-go-v2/service/kms v1.18.1 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.27.2 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.11.13 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.16.10 // indirect github.com/aws/smithy-go v1.13.5 // indirect @@ -99,6 +90,7 @@ require ( github.com/containerd/containerd v1.7.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/deckarep/golang-set/v2 v2.5.0 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect github.com/djherbis/times v1.5.0 // indirect github.com/docker/cli v20.10.21+incompatible // indirect @@ -108,7 +100,6 @@ require ( github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect @@ -118,9 +109,9 @@ require ( github.com/fatih/color v1.13.0 // indirect github.com/fluxcd/pkg/ssa v0.28.1 // indirect github.com/go-errors/errors v1.4.2 // indirect - github.com/go-git/gcfg v1.5.0 // indirect - github.com/go-git/go-billy/v5 v5.4.0 // indirect - github.com/go-git/go-git/v5 v5.6.0 // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.5.0 // indirect + github.com/go-git/go-git/v5 v5.9.0 // indirect github.com/go-gorp/gorp/v3 v3.0.5 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -130,7 +121,6 @@ require ( github.com/gobwas/glob v0.2.3 // indirect github.com/gofrs/uuid v4.2.0+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt v3.2.1+incompatible // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/glog v1.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -167,12 +157,11 @@ require ( github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hashicorp/hcl/v2 v2.16.2 // indirect + github.com/hashicorp/hcl/v2 v2.17.0 // indirect github.com/hashicorp/vault/api v1.8.2 // indirect github.com/hashicorp/vault/sdk v0.6.1 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/huandu/xstrings v1.4.0 // indirect - github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect @@ -180,10 +169,8 @@ require ( github.com/jmoiron/sqlx v1.3.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/compress v1.16.0 // indirect - github.com/kylelemons/godebug v1.1.0 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lib/pq v1.10.9 // indirect @@ -191,11 +178,10 @@ require ( github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.18 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-localereader v0.0.1 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect @@ -210,23 +196,22 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/morikuni/aec v1.0.0 // indirect - github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/reflow v0.3.0 // indirect - github.com/muesli/termenv v0.15.1 // indirect + github.com/muesli/termenv v0.15.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/natefinch/atomic v1.0.1 // indirect github.com/oklog/run v1.1.0 // indirect - github.com/onsi/gomega v1.27.7 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect github.com/opentracing/basictracer-go v1.1.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pgavlin/fx v0.1.6 // indirect github.com/pgavlin/goldmark v1.1.33-0.20200616210433-b5eb04559386 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect - github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pkg/term v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -234,9 +219,11 @@ require ( github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect + github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231 // indirect github.com/pulumi/cloud-ready-checks v1.0.1-0.20230201174945-00fe9c1b68fd // indirect + github.com/pulumi/esc v0.6.1-0.20231111193429-44b746a5b3b5 // indirect github.com/rivo/uniseg v0.4.4 // indirect - github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rubenv/sql-migrate v1.3.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect @@ -247,7 +234,7 @@ require ( github.com/sergi/go-diff v1.3.1 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.0 // indirect - github.com/skeema/knownhosts v1.1.0 // indirect + github.com/skeema/knownhosts v1.2.0 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect @@ -269,16 +256,16 @@ require ( go.uber.org/atomic v1.11.0 // indirect gocloud.dev v0.27.0 // indirect gocloud.dev/secrets/hashivault v0.27.0 // indirect - golang.org/x/crypto v0.13.0 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.15.0 // indirect + golang.org/x/crypto v0.15.0 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.18.0 // indirect golang.org/x/oauth2 v0.12.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.12.0 // indirect - golang.org/x/term v0.12.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/term v0.14.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.13.0 // indirect + golang.org/x/tools v0.15.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.128.0 // indirect google.golang.org/appengine v1.6.8 // indirect @@ -286,7 +273,6 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect google.golang.org/grpc v1.58.2 // indirect - google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect @@ -310,5 +296,4 @@ require ( sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect sigs.k8s.io/yaml v1.3.0 // indirect - sourcegraph.com/sourcegraph/appdash v0.0.0-20211028080628-e2786a622600 // indirect ) diff --git a/tests/go.sum b/tests/go.sum index d6648159d8..649ff24670 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -91,12 +91,12 @@ code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c/go.mod h1:QD9Lzhd contrib.go.opencensus.io/exporter/aws v0.0.0-20200617204711-c478e41e60e9/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= contrib.go.opencensus.io/exporter/stackdriver v0.13.13/go.mod h1:5pSSGY0Bhuk7waTHuDf4aQ8D2DrhgETRo9fy6k3Xlzc= contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0= -github.com/AlecAivazis/survey/v2 v2.0.5 h1:xpZp+Q55wi5C7Iaze+40onHnEkex1jSc34CltJjOoPM= -github.com/AlecAivazis/survey/v2 v2.0.5/go.mod h1:WYBhg6f0y/fNYUuesWQc0PKbJcEliGcYHB9sNT3Bg74= github.com/Azure/azure-amqp-common-go/v3 v3.2.3/go.mod h1:7rPmbSfszeovxGfc5fSAXE4ehlXQZHpMja2OtxC2Tas= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v63.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= @@ -105,16 +105,12 @@ github.com/Azure/azure-sdk-for-go v66.0.0+incompatible h1:bmmC38SlE8/E81nNADlgmV github.com/Azure/azure-sdk-for-go v66.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1 h1:tz19qLF65vuu2ibfTqGVJxG/zZAI27NEIIbvAOQwYbw= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0 h1:Yoicul8bnVdQrhDMTHxdEckRGX01XvwXDHUT9zYZ3k0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM= github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.0.2/go.mod h1:LH9XQnMr2ZYxQdVdCrzLO9mxeDyrDFa6wbSI3x5zCZk= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1 h1:QSdcrd/UFJv6Bp/CfoVf2SrENpFn9P6Yh8yb+xNhYMM= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1/go.mod h1:eZ4g6GUvXiGulfIbbhh1Xr4XwUYaYaWMqzGD/284wCA= github.com/Azure/go-amqp v0.17.0/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg= github.com/Azure/go-amqp v0.17.5/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg= @@ -159,7 +155,6 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0 h1:WVsrXCnHlDDX8ls+tootqRE87/hL9S/g4ewig9RsD/c= github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= @@ -195,8 +190,8 @@ github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JP github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= -github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= @@ -214,12 +209,9 @@ github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5 github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= -github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= -github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 h1:ra2OtmuW0AE5csawV4YXMNGNQQXvLRps3z2Z59OPO+I= -github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= @@ -230,8 +222,8 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/a8m/expect v1.0.0/go.mod h1:4IwSCMumY49ScypDnjNbYEjgVeqy1/U2cEs3Lat96eA= -github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= -github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= +github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= @@ -363,7 +355,7 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembj github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= -github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= @@ -410,7 +402,6 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -570,6 +561,8 @@ github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjI github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set/v2 v2.5.0 h1:hn6cEZtQ0h3J8kFrHR/NrzyOoTnjgW1+FmNJzQ7y/sA= +github.com/deckarep/golang-set/v2 v2.5.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denisenkom/go-mssqldb v0.12.2/go.mod h1:lnIw1mZukFRZDJYQ0Pb833QS2IaC3l5HkEfra2LJ+sk= github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= @@ -589,7 +582,6 @@ github.com/djherbis/times v1.5.0 h1:79myA211VwPhFTqUk8xehWrsEO+zcIZj0zT8mXPVARU= github.com/djherbis/times v1.5.0/go.mod h1:5q7FDLvbNg1L/KaBmPcWlVR9NmoKo3+ucqUA3ijQhA0= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= -github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v20.10.21+incompatible h1:qVkgyYUnOLQ98LtXBrwd/duVqPT2X4SHndOuGsfwyhU= @@ -625,8 +617,6 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= @@ -634,6 +624,8 @@ github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaB github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= @@ -709,15 +701,14 @@ github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4x github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= -github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= -github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.4.0 h1:Vaw7LaSTRJOUric7pe4vnzBSgyuf2KrLsu2Y4ZpQBDE= -github.com/go-git/go-billy/v5 v5.4.0/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg= -github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ= -github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= -github.com/go-git/go-git/v5 v5.6.0 h1:JvBdYfcttd+0kdpuWO7KTu0FYgCf5W0t5VwkWGobaa4= -github.com/go-git/go-git/v5 v5.6.0/go.mod h1:6nmJ0tJ3N4noMV1Omv7rC5FG3/o8Cm51TB4CJp7mRmE= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= +github.com/go-git/go-git/v5 v5.9.0 h1:cD9SFA7sHVRdJ7AYck1ZaAa/yeuBvGPxwXDL8cxrObY= +github.com/go-git/go-git/v5 v5.9.0/go.mod h1:RKIqga24sWdMGZF+1Ekv9kylsDz6LzdTSI2s/OsZWE0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -861,7 +852,6 @@ github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= @@ -1120,8 +1110,8 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/hcl/v2 v2.16.2 h1:mpkHZh/Tv+xet3sy3F9Ld4FyI2tUpWe9x3XtPx9f1a0= -github.com/hashicorp/hcl/v2 v2.16.2/go.mod h1:JRmR89jycNkrrqnMmvPDMd56n1rQJ2Q6KocSLCMCXng= +github.com/hashicorp/hcl/v2 v2.17.0 h1:z1XvSUyXd1HP10U4lrLg5e0JMVz6CPaJvAgxM0KNZVY= +github.com/hashicorp/hcl/v2 v2.17.0/go.mod h1:gJyW2PTShkJqQBKpAmPO3yxMxIuoXkOF2TpqXzrQyx4= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= @@ -1143,9 +1133,6 @@ github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hetznercloud/hcloud-go v1.33.1/go.mod h1:XX/TQub3ge0yWR2yHWmnDVIrB+MQbda1pHxkUmDlUME= github.com/hetznercloud/hcloud-go v1.35.0/go.mod h1:mepQwR6va27S3UQthaEPGS86jtzSY9xWL1e9dyxXpgA= -github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= -github.com/hinshun/vt10x v0.0.0-20220301184237-5011da428d02 h1:AgcIVYPa6XJnU3phs104wLj8l5GEththEw6+F79YsIY= -github.com/hinshun/vt10x v0.0.0-20220301184237-5011da428d02/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= @@ -1158,8 +1145,6 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= -github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd h1:anPrsicrIi2ColgWTVPk+TrN42hJIWlfPHSBP9S0ZkM= -github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwPgrt2be44XgSqndprz1G18rSk8KD84= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= @@ -1253,8 +1238,6 @@ github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaR github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= @@ -1282,14 +1265,12 @@ github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NB github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= @@ -1337,7 +1318,6 @@ github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -1356,8 +1336,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= @@ -1365,8 +1345,8 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= @@ -1378,8 +1358,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microsoft/ApplicationInsights-Go v0.4.4/go.mod h1:fKRUseBqkw6bDiXTs3ESTiU/4YTIHsQS4W3fP2ieF4U= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= @@ -1420,7 +1398,6 @@ github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQ github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= @@ -1453,14 +1430,14 @@ github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= -github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs= -github.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= @@ -1503,8 +1480,8 @@ github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1ls github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= -github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= +github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= +github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -1515,8 +1492,8 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= -github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= -github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -1572,6 +1549,8 @@ github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pgavlin/fx v0.1.6 h1:r9jEg69DhNoCd3Xh0+5mIbdbS3PqWrVWujkY76MFRTU= +github.com/pgavlin/fx v0.1.6/go.mod h1:KWZJ6fqBBSh8GxHYqwYCf3rYE7Gp2p0N8tJp8xv9u9M= github.com/pgavlin/goldmark v1.1.33-0.20200616210433-b5eb04559386 h1:LoCV5cscNVWyK5ChN/uCoIFJz8jZD63VQiGJIRgr6uo= github.com/pgavlin/goldmark v1.1.33-0.20200616210433-b5eb04559386/go.mod h1:MRxHTJrf9FhdfNQ8Hdeh9gmHevC9RJE/fu8M3JIGjoE= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= @@ -1584,7 +1563,6 @@ github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= -github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1668,12 +1646,18 @@ github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3c github.com/prometheus/prometheus v0.35.0/go.mod h1:7HaLx5kEPKJ0GDgbODG0fZgXbQ8K/XjZNJXQmbmgQlY= github.com/prometheus/prometheus v0.37.0/go.mod h1:egARUgz+K93zwqsVIAneFlLZefyGOON44WyAp4Xqbbk= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231 h1:vkHw5I/plNdTr435cARxCW6q9gc0S/Yxz7Mkd38pOb0= +github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231/go.mod h1:murToZ2N9hNJzewjHBgfFdXhZKjY3z5cYC1VXk+lbFE= github.com/pulumi/cloud-ready-checks v1.0.1-0.20230201174945-00fe9c1b68fd h1:shFTLvh3MZbBzVDr3xwYjUr5H1y3N5n4pczWtVaUZxo= github.com/pulumi/cloud-ready-checks v1.0.1-0.20230201174945-00fe9c1b68fd/go.mod h1:C6HmNtth9oPAWKyRJveZSU4rK/tvzhSGuoOV5y+S17g= -github.com/pulumi/pulumi/pkg/v3 v3.81.0 h1:6rf2farQLszi8inHCu9YdJtDvK0fqNguix51b3FEDRQ= -github.com/pulumi/pulumi/pkg/v3 v3.81.0/go.mod h1:URXozJB/abhxb2yOwa5ywHjT2dqt9SmAX2iLkdcOOl0= -github.com/pulumi/pulumi/sdk/v3 v3.81.0 h1:d711GUpjZK1beNpIKFReC1LBmHXYE684sYWntJWQ4Q0= -github.com/pulumi/pulumi/sdk/v3 v3.81.0/go.mod h1:RMilNNVMlmK1h4Nl/qylb9vzbgh4F3mufZoUOnPy98o= +github.com/pulumi/esc v0.6.1-0.20231111193429-44b746a5b3b5 h1:1DJMji9F7XPea46bSuhy4/85n8J4/Mfz8PWLZtjKKiI= +github.com/pulumi/esc v0.6.1-0.20231111193429-44b746a5b3b5/go.mod h1:Y6W21yUukvxS2NnS5ae1beMSPhMvj0xNAYcDqDHVj/g= +github.com/pulumi/pulumi/pkg/v3 v3.96.2 h1:d+zDsh4K1j90q/upDRkhgxHkspP20Xxd3g6OaMbw574= +github.com/pulumi/pulumi/pkg/v3 v3.96.2/go.mod h1:lR+q06XrnEqRzJXZ6IeHb4nu+U5fswFcc51Q0MRBTio= +github.com/pulumi/pulumi/sdk/v3 v3.96.2 h1:q5ZKdf+e9JR+a6Eiueg0Ohy6jCQGk9pO2V7xI/qGP3I= +github.com/pulumi/pulumi/sdk/v3 v3.96.2/go.mod h1:yvD23IIRiqIXuo4kaZNe5zK/uT0nhO99wr6BVEqoi7A= +github.com/pulumiverse/pulumi-time/sdk v0.0.0-20231010123146-089d7304da13 h1:4U7DFIlSggj/4iLbis2Bckayed+OhaYKE7bncZwQCYI= +github.com/pulumiverse/pulumi-time/sdk v0.0.0-20231010123146-089d7304da13/go.mod h1:NUa1zA74DF002WrM6iF111A6UjX9knPpXufVRvBwNyg= github.com/rakyll/embedmd v0.0.0-20171029212350-c8060a0752a2/go.mod h1:7jOTMgqac46PZcF54q6l2hkLEG8op93fZu61KmxWDV4= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -1688,8 +1672,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= @@ -1721,7 +1705,6 @@ github.com/segmentio/asm v1.1.3 h1:WM03sfUOENvvKexOLp+pCqgb/WDjsi7EK8gIsICtzhc= github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg= github.com/segmentio/encoding v0.3.5 h1:UZEiaZ55nlXGDL92scoVuw00RmiRCazIEmvPSbSvt8Y= github.com/segmentio/encoding v0.3.5/go.mod h1:n0JeuIqEQrQoPDGsjo8UNd1iA0U8d8+oHAA4E3G3OxM= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -1742,8 +1725,8 @@ github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0= -github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag= +github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM= +github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -1791,7 +1774,6 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -1991,7 +1973,6 @@ gocloud.dev v0.27.0 h1:j0WTUsnKTxCsWO7y8T+YCiBZUmLl9w/WIowqAY3yo0g= gocloud.dev v0.27.0/go.mod h1:YlYKhYsY5/1JdHGWQDkAuqkezVKowu7qbe9aIeUF6p0= gocloud.dev/secrets/hashivault v0.27.0 h1:AAeGJXr0tiHHJgg5tL8atOGktB4eK9EJAqkZbPKAcOo= gocloud.dev/secrets/hashivault v0.27.0/go.mod h1:offqsI5oj0B0bVHZdfk/88uIb3NnN93ia8py0yvRlHY= -golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -2001,7 +1982,6 @@ golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -2028,15 +2008,14 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -2047,8 +2026,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -2078,9 +2057,9 @@ golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2161,12 +2140,13 @@ golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2209,8 +2189,9 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -2230,7 +2211,6 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2355,27 +2335,28 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= -golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2388,8 +2369,10 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2489,9 +2472,9 @@ golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2888,7 +2871,6 @@ oras.land/oras-go v1.2.2/go.mod h1:Apa81sKoZPpP7CDciE006tSZ0x3Q3+dOoBcMZ/aNxvw= pgregory.net/rapid v0.6.1 h1:4eyrDxyht86tT4Ztm+kvlyNBLIk071gR+ZQdhphc9dQ= pgregory.net/rapid v0.6.1/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= @@ -2918,5 +2900,3 @@ sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= -sourcegraph.com/sourcegraph/appdash v0.0.0-20211028080628-e2786a622600 h1:hfyJ5ku9yFtLVOiSxa3IN+dx5eBQT9mPmKFypAmg8XM= -sourcegraph.com/sourcegraph/appdash v0.0.0-20211028080628-e2786a622600/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= From 60776a67cccd79d4bdcd02e4963d16e68ccd613b Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 11 Dec 2023 09:39:38 -0800 Subject: [PATCH 27/31] fixups for nodejs --- tests/sdk/nodejs/nodejs_test.go | 2 +- tests/sdk/nodejs/options/Pulumi.yaml | 2 +- tests/sdk/nodejs/options/index.ts | 1 - tests/sdk/python/options/Pulumi.yaml | 2 +- tests/util.go | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/sdk/nodejs/nodejs_test.go b/tests/sdk/nodejs/nodejs_test.go index 9b98cc326f..6e1b929290 100644 --- a/tests/sdk/nodejs/nodejs_test.go +++ b/tests/sdk/nodejs/nodejs_test.go @@ -2060,7 +2060,7 @@ func TestOptionPropagation(t *testing.T) { providerUrn := func(prov *apitype.ResourceV3) resource.URN { return prov.URN + resource.URNNameDelimiter + resource.URN(prov.ID) } - urn := func(parentType, baseType tokens.Type, name tokens.QName) resource.URN { + urn := func(parentType, baseType tokens.Type, name string) resource.URN { return resource.NewURN(stackInfo.StackName, "options-test", parentType, baseType, name) } diff --git a/tests/sdk/nodejs/options/Pulumi.yaml b/tests/sdk/nodejs/options/Pulumi.yaml index 9d836a638a..bb025fb3e3 100644 --- a/tests/sdk/nodejs/options/Pulumi.yaml +++ b/tests/sdk/nodejs/options/Pulumi.yaml @@ -1,5 +1,5 @@ name: options-test runtime: nodejs -description: A minimal Kubernetes TypeScript Pulumi program +description: Test options propagation with component resources. config: pulumi:disable-default-providers: [kubernetes] diff --git a/tests/sdk/nodejs/options/index.ts b/tests/sdk/nodejs/options/index.ts index 565f1e185f..057db3c8a6 100644 --- a/tests/sdk/nodejs/options/index.ts +++ b/tests/sdk/nodejs/options/index.ts @@ -38,7 +38,6 @@ function applyAlias(args: pulumi.ResourceTransformationArgs): pulumi.ResourceTra props: args.props, opts: pulumi.mergeOptions(args.opts, { aliases: [{ name: `${args.name}-aliased` }], - // aliases: [{ name: `${args.name}-aliased` }, ...(args.opts.aliases ?? [])], }), }; } diff --git a/tests/sdk/python/options/Pulumi.yaml b/tests/sdk/python/options/Pulumi.yaml index f4ba0ff2e6..58f038215b 100644 --- a/tests/sdk/python/options/Pulumi.yaml +++ b/tests/sdk/python/options/Pulumi.yaml @@ -3,6 +3,6 @@ runtime: name: python options: virtualenv: venv -description: A minimal Kubernetes Python Pulumi program +description: Test options propagation with component resources. config: pulumi:disable-default-providers: [kubernetes] diff --git a/tests/util.go b/tests/util.go index 408e89616a..88eef3c5e4 100644 --- a/tests/util.go +++ b/tests/util.go @@ -27,7 +27,7 @@ func SortResourcesByURN(stackInfo integration.RuntimeValidationStackInfo) { }) } -func SearchResourcesByName(stackInfo integration.RuntimeValidationStackInfo, parent resource.URN, typ tokens.Type, name tokens.QName) *apitype.ResourceV3 { +func SearchResourcesByName(stackInfo integration.RuntimeValidationStackInfo, parent resource.URN, typ tokens.Type, name string) *apitype.ResourceV3 { i := slices.IndexFunc(stackInfo.Deployment.Resources, func(r apitype.ResourceV3) bool { return r.Type == typ && r.URN.Name() == name && (parent == "" || r.Parent == parent) }) From 842dd1f28afb023a2aac8ab0ea7e656b829c14d9 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 11 Dec 2023 11:01:28 -0800 Subject: [PATCH 28/31] go tests --- tests/sdk/go/go_test.go | 436 +++++++++++++++++++++++++++++++ tests/sdk/go/options/Pulumi.yaml | 5 + tests/sdk/go/options/main.go | 280 ++++++++++++++++++++ 3 files changed, 721 insertions(+) create mode 100644 tests/sdk/go/options/Pulumi.yaml create mode 100644 tests/sdk/go/options/main.go diff --git a/tests/sdk/go/go_test.go b/tests/sdk/go/go_test.go index 955ae3e936..4418452abe 100644 --- a/tests/sdk/go/go_test.go +++ b/tests/sdk/go/go_test.go @@ -25,9 +25,20 @@ import ( "strings" "testing" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/format" + . "github.com/onsi/gomega/gstruct" "github.com/pulumi/pulumi-kubernetes/provider/v4/pkg/openapi" + "github.com/pulumi/pulumi-kubernetes/tests/v4" + . "github.com/pulumi/pulumi-kubernetes/tests/v4/gomega" + pulumirpctesting "github.com/pulumi/pulumi-kubernetes/tests/v4/pulumirpc" + "github.com/pulumi/pulumi/pkg/v3/engine" "github.com/pulumi/pulumi/pkg/v3/testing/integration" + "github.com/pulumi/pulumi/sdk/v3/go/common/apitype" + "github.com/pulumi/pulumi/sdk/v3/go/common/resource" + "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" "github.com/pulumi/pulumi/sdk/v3/go/common/util/contract" + "github.com/pulumi/pulumi/sdk/v3/go/common/util/fsutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -38,6 +49,9 @@ var baseOptions = &integration.ProgramTestOptions{ Dependencies: []string{ "github.com/pulumi/pulumi-kubernetes/sdk/v4", }, + PostPrepareProject: func(p *engine.Projinfo) error { + return fsutil.CopyFile(filepath.Join(p.Root, "testdata"), filepath.Join("..", "..", "testdata"), nil) + }, Env: []string{ "PULUMI_K8S_CLIENT_BURST=200", "PULUMI_K8S_CLIENT_QPS=100", @@ -426,3 +440,425 @@ func TestGo(t *testing.T) { integration.ProgramTest(t, &test) }) } + +// TestOptionPropagation tests the handling of resource options by the various compoonent resources. +// Component resources are responsible for implementing option propagation logic when creating +// child resources. +func TestOptionPropagation(t *testing.T) { + g := NewWithT(t) + format.MaxLength = 0 + // format.MaxDepth = 6 + // format.UseStringerRepresentation = true + format.RegisterCustomFormatter(pulumirpctesting.FormatDebugInterceptorLog) + + cwd, err := os.Getwd() + if !assert.NoError(t, err) { + t.FailNow() + } + + grpcLog, err := pulumirpctesting.NewDebugInterceptorLog() + require.NoError(t, err) + + options := baseOptions.With(integration.ProgramTestOptions{ + Dir: filepath.Join(cwd, "options"), + Env: []string{grpcLog.Env()}, + Quick: true, + ExpectRefreshChanges: false, + ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { + + // lookup some resources for later use + providerA := tests.SearchResourcesByName(stackInfo, "", "pulumi:providers:kubernetes", "a") + require.NotNil(t, providerA) + providerB := tests.SearchResourcesByName(stackInfo, "", "pulumi:providers:kubernetes", "b") + require.NotNil(t, providerB) + providerNullOpts := tests.SearchResourcesByName(stackInfo, "", "pulumi:providers:kubernetes", "nullopts") + require.NotNil(t, providerNullOpts) + sleep := tests.SearchResourcesByName(stackInfo, "", "time:index/sleep:Sleep", "sleep") + require.NotNil(t, sleep) + + // some helper functions for naming purposes + providerUrn := func(prov *apitype.ResourceV3) resource.URN { + return prov.URN + resource.URNNameDelimiter + resource.URN(prov.ID) + } + urn := func(parentType, baseType tokens.Type, name tokens.QName) resource.URN { + return resource.NewURN(stackInfo.StackName, "options-test", parentType, baseType, string(name)) + } + + // read the GRPC log file to inspect the RegisterResource calls, since they provide + // the most detailed view of the resource's options as determined by the SDK. + logEntries, err := grpcLog.ReadAll() + require.NoError(t, err) + rr := logEntries.ListRegisterResource() + + // --- ConfigGroup --- + + // ConfigGroup "cg-options" with most options + g.Expect(rr.Named("", + "kubernetes:yaml:ConfigGroup", "cg-options")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("cg-options-old"), Alias("cg-options-aliased")), + "Protect": BeTrue(), + "Dependencies": HaveExactElements(string(sleep.URN)), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerA)), + }), + "IgnoreChanges": HaveExactElements("ignored"), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigGroup", "cg-options"), + "kubernetes:core/v1:ConfigMap", "cg-options-cg-options-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("cg-options-cm-1-k8s-aliased"), Alias("cg-options-cg-options-cm-1-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("cg-options-cm-1"), + "annotations": And(HaveKey("pulumi.com/skipAwait"), HaveKey("transformed")), + }), + }))), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigGroup", "cg-options"), + "kubernetes:yaml:ConfigFile", "cg-options-./testdata/options/configgroup/manifest.yaml")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("cg-options-./testdata/options/configgroup/manifest.yaml-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": BeEmpty(), + // quirk: unlike Python SDK, there's no providers on the intermediate ConfigFile. + // "Providers": MatchAllKeys(Keys{ + // "kubernetes": BeEquivalentTo(providerUrn(providerA)), + // }), + }), + }), + )) + g.Expect(rr.Named(urn("kubernetes:yaml:ConfigGroup", "kubernetes:yaml:ConfigFile", "cg-options-./testdata/options/configgroup/manifest.yaml"), + "kubernetes:core/v1:ConfigMap", "cg-options-configgroup-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("configgroup-cm-1-k8s-aliased"), Alias("cg-options-configgroup-cm-1-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("configgroup-cm-1"), + "annotations": And(HaveKey("pulumi.com/skipAwait"), HaveKey("transformed")), + }), + }))), + }), + }), + )) + + // ConfigGroup "cg-provider" with "provider" option that should propagate to children. + g.Expect(rr.Named("", + "kubernetes:yaml:ConfigGroup", "cg-provider")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerB)), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerB)), + }), + }), + }), + )) + + // ConfigGroup "cg-nullopts" with a stack transform to apply a "provider" option. + g.Expect(rr.Named("", + "kubernetes:yaml:ConfigGroup", "cg-nullopts")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerNullOpts)), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerNullOpts)), + }), + }), + }), + )) + + // --- ConfigFile --- + + // ConfigFile "cf-options" with most options + g.Expect(rr.Named("", + "kubernetes:yaml:ConfigFile", "cf-options-cf-options")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("cf-options") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("cf-options-old"), Alias("cf-options-cf-options-aliased")), + "Protect": BeTrue(), + "Dependencies": HaveExactElements(string(sleep.URN)), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerA)), + }), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-options-cf-options"), + "kubernetes:core/v1:ConfigMap", "cf-options-configfile-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("configfile-cm-1-k8s-aliased"), Alias("cf-options-configfile-cm-1-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("configfile-cm-1"), + "annotations": And(HaveKey("pulumi.com/skipAwait"), HaveKey("transformed")), + }), + }))), + }), + }), + )) + + // ConfigFile "cf-provider" with "provider" option that should propagate to children. + g.Expect(rr.Named("", + "kubernetes:yaml:ConfigFile", "cf-provider-cf-provider")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("cf-provider") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerB)), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerB)), + }), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-provider-cf-provider"), + "kubernetes:core/v1:ConfigMap", "cf-provider-configfile-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerB)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("configfile-cm-1"), + }), + }))), + }), + }), + )) + + // ConfigFile "cf-nullopts" with a stack transform to apply a "provider" option. + g.Expect(rr.Named("", + "kubernetes:yaml:ConfigFile", "cf-nullopts-cf-nullopts")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("cf-nullopts") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerNullOpts)), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerNullOpts)), + }), + }), + }), + )) + + // --- Directory --- + + // Directory "kustomize-options" with most options + g.Expect(rr.Named("", + "kubernetes:kustomize:Directory", "kustomize-options-kustomize-options")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("kustomize-options") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("kustomize-options-old"), Alias("kustomize-options-kustomize-options-aliased")), + "Protect": BeTrue(), + "Dependencies": HaveExactElements(string(sleep.URN)), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerA)), + }), + "IgnoreChanges": HaveExactElements("ignored"), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-options-kustomize-options"), + "kubernetes:core/v1:ConfigMap", "kustomize-options-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("kustomize-cm-1-2kkk4bthmg-k8s-aliased"), Alias("kustomize-options-kustomize-cm-1-2kkk4bthmg-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("kustomize-cm-1-2kkk4bthmg"), + "annotations": And(HaveKey("transformed")), + }), + }))), + }), + }), + )) + + // Directory "kustomize-provider" with "provider" option that should propagate to children. + g.Expect(rr.Named("", + "kubernetes:kustomize:Directory", "kustomize-provider-kustomize-provider")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("kustomize-provider") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerB)), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerB)), + }), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-provider-kustomize-provider"), + "kubernetes:core/v1:ConfigMap", "kustomize-provider-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerB)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + }), + }), + )) + + // Directory "kustomize-nullopts" with a stack transform to apply a "provider" option. + g.Expect(rr.Named("", + "kubernetes:kustomize:Directory", "kustomize-nullopts-kustomize-nullopts")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("kustomize-nullopts") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerNullOpts)), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerNullOpts)), + }), + }), + }), + )) + + // --- Chart --- + + // Chart "chart-options" + g.Expect(rr.Named("", + "kubernetes:helm.sh/v3:Chart", "chart-options-chart-options")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("chart-options") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(AliasByType("kubernetes:helm.sh/v2:Chart"), Alias("chart-options-old"), Alias("chart-options-chart-options-aliased")), + "Protect": BeTrue(), + "Dependencies": HaveExactElements(string(sleep.URN)), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerA)), + }), + "IgnoreChanges": HaveExactElements("ignored"), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-options-chart-options"), + "kubernetes:core/v1:ConfigMap", "chart-options-chart-options-chart-options-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Aliases": HaveExactElements(Alias("chart-options-chart-options-cm-1-k8s-aliased"), Alias("chart-options-chart-options-chart-options-cm-1-aliased")), + "Protect": BeTrue(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), + "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "name": Equal("chart-options-chart-options-cm-1"), // note: based on the Helm Release name + "annotations": And(HaveKey("pulumi.com/skipAwait")), + }), + }))), + }), + }), + )) + + // Chart "chart-provider" with "provider" option that should propagate to children. + g.Expect(rr.Named("", + "kubernetes:helm.sh/v3:Chart", "chart-provider-chart-provider")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("chart-provider") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerB)), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerB)), + }), + }), + }), + )) + g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-provider-chart-provider"), + "kubernetes:core/v1:ConfigMap", "chart-provider-chart-provider-chart-provider-cm-1")).To(HaveExactElements( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerB)), + "Version": Not(BeEmpty()), + "Providers": BeEmpty(), + }), + }), + )) + + // Chart "chart-nullopts" with a stack transform to apply a "provider" option. + g.Expect(rr.Named("", + "kubernetes:helm.sh/v3:Chart", "chart-nullopts-chart-nullopts")).To(HaveExactElements( + // quirk: NodeJS SDK applies resource_prefix ("chart-options") to the component itself. + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Provider": BeEquivalentTo(providerUrn(providerNullOpts)), + "Version": BeEmpty(), + "Providers": MatchAllKeys(Keys{ + "kubernetes": BeEquivalentTo(providerUrn(providerNullOpts)), + }), + }), + }), + )) + }, + }) + + pt := integration.ProgramTestManualLifeCycle(t, &options) + + err = pt.TestLifeCyclePrepare() + require.NoError(t, err) + t.Cleanup(pt.TestCleanUp) + err = pt.TestLifeCycleInitialize() + require.NoError(t, err) + t.Cleanup(func() { + // to ensure cleanup, we need to unprotected all resources + err = pt.RunPulumiCommand("state", "unprotect", "--all", "-y") + contract.IgnoreError(err) + + destroyErr := pt.TestLifeCycleDestroy() + contract.IgnoreError(destroyErr) + }) + + err = pt.TestPreviewUpdateAndEdits() + require.NoError(t, err) +} diff --git a/tests/sdk/go/options/Pulumi.yaml b/tests/sdk/go/options/Pulumi.yaml new file mode 100644 index 0000000000..fee061b3c1 --- /dev/null +++ b/tests/sdk/go/options/Pulumi.yaml @@ -0,0 +1,5 @@ +name: options-test +description: Test options propagation with component resources. +runtime: go +# config: +# pulumi:disable-default-providers: [kubernetes] diff --git a/tests/sdk/go/options/main.go b/tests/sdk/go/options/main.go new file mode 100644 index 0000000000..cb1bbc495a --- /dev/null +++ b/tests/sdk/go/options/main.go @@ -0,0 +1,280 @@ +package main + +import ( + "strings" + + "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes" + corev1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/core/v1" + "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/helm/v3" + "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/kustomize" + "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/yaml" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" + "github.com/pulumiverse/pulumi-time/sdk/go/time" +) + +func main() { + pulumi.Run(func(ctx *pulumi.Context) error { + + _, err := corev1.NewNamespace(ctx, "version", &corev1.NamespaceArgs{}, + pulumi.Version("1.2.3"), pulumi.PluginDownloadURL("https://example.com")) + if err != nil { + return err + } + + bootstrapProvider, err := kubernetes.NewProvider(ctx, "bootstrap", &kubernetes.ProviderArgs{}) + if err != nil { + return err + } + nulloptsNs, err := corev1.NewNamespace(ctx, "nullopts", &corev1.NamespaceArgs{}, pulumi.Provider(bootstrapProvider)) + if err != nil { + return err + } + aNs, err := corev1.NewNamespace(ctx, "a", &corev1.NamespaceArgs{}, pulumi.Provider(bootstrapProvider)) + if err != nil { + return err + } + bNs, err := corev1.NewNamespace(ctx, "b", &corev1.NamespaceArgs{}, pulumi.Provider(bootstrapProvider)) + if err != nil { + return err + } + nulloptsProvider, err := kubernetes.NewProvider(ctx, "nullopts", &kubernetes.ProviderArgs{Namespace: nulloptsNs.Metadata.Name()}) + if err != nil { + return err + } + aProvider, err := kubernetes.NewProvider(ctx, "a", &kubernetes.ProviderArgs{Namespace: aNs.Metadata.Name()}) + if err != nil { + return err + } + bProvider, err := kubernetes.NewProvider(ctx, "b", &kubernetes.ProviderArgs{Namespace: bNs.Metadata.Name()}) + if err != nil { + return err + } + + // a sleep resource to exercise the "depends_on" component-level option + sleep, err := time.NewSleep(ctx, "sleep", &time.SleepArgs{CreateDuration: pulumi.String("1s")}) + if err != nil { + return err + } + + // apply_default_opts is a stack transformation that applies default opts to any resource whose name ends with "-nullopts". + // this is intended to be applied to component resources only. + applyDefaultOpts := func(args *pulumi.ResourceTransformationArgs) *pulumi.ResourceTransformationResult { + if strings.HasSuffix(args.Name, "-nullopts") { + return &pulumi.ResourceTransformationResult{ + Props: args.Props, + Opts: append(args.Opts, pulumi.Provider(nulloptsProvider)), + } + } + return nil + } + ctx.RegisterStackTransformation(applyDefaultOpts) + + // applyAlias is a Pulumi transformation that applies a unique alias to each resource. + applyAlias := func(args *pulumi.ResourceTransformationArgs) *pulumi.ResourceTransformationResult { + return &pulumi.ResourceTransformationResult{ + Props: args.Props, + Opts: append(args.Opts, pulumi.Aliases([]pulumi.Alias{{Name: pulumi.String(args.Name + "-aliased")}})), + } + } + + // transform_k8s is a Kubernetes transformation that applies a unique alias and annotation to each resource. + transformK8s := func(state map[string]interface{}, opts ...pulumi.ResourceOption) { + if state["kind"] == "Service" { + metadata := state["metadata"].(map[string]interface{}) + metadata["annotations"] = map[string]interface{}{"transformed": "true"} + + // note: pulumi-kubernetes Go SDK doesn't provide a way to mutate the options (e.g. to add a "-k8s-aliased" alias) + // https://github.com/pulumi/pulumi-kubernetes/issues/2666 + } + } + + // --- ConfigGroup --- + + _, err = yaml.NewConfigGroup(ctx, "cg-options", &yaml.ConfigGroupArgs{ + ResourcePrefix: "cg-options", + SkipAwait: true, + Transformations: []yaml.Transformation{transformK8s}, + Files: []string{"./testdata/options/configgroup/*.yaml"}, + YAML: []string{` +apiVersion: v1 +kind: ConfigMap +metadata: + name: cg-options-cm-1 +`}, + }, + pulumi.Providers(aProvider), + pulumi.Aliases([]pulumi.Alias{{Name: pulumi.String("cg-options-old")}}), + pulumi.IgnoreChanges([]string{"ignored"}), + pulumi.Protect(true), + pulumi.DependsOn([]pulumi.Resource{sleep}), + pulumi.Transformations([]pulumi.ResourceTransformation{applyAlias}), + ) + if err != nil { + return err + } + + if true { + return nil + } + + // "provider" option + _, err = yaml.NewConfigGroup(ctx, "cg-provider", &yaml.ConfigGroupArgs{ + ResourcePrefix: "cg-provider", + YAML: []string{` +apiVersion: v1 +kind: ConfigMap +metadata: + name: cg-provider-cm-1 +`}, + }, pulumi.Provider(bProvider)) + if err != nil { + return err + } + + // null opts + _, err = yaml.NewConfigGroup(ctx, "cg-nullopts", &yaml.ConfigGroupArgs{ + ResourcePrefix: "cg-nullopts", + YAML: []string{` +apiVersion: v1 +kind: ConfigMap +metadata: + name: cg-nullopts-cm-1 +`}, + }) + if err != nil { + return err + } + + // version + _, err = yaml.NewConfigGroup(ctx, "cg-version", &yaml.ConfigGroupArgs{ + ResourcePrefix: "cg-version", + YAML: []string{` +apiVersion: v1 +kind: ConfigMap +metadata: + name: cg-version-cm-1 +`}, + }, pulumi.Provider(nulloptsProvider), pulumi.Version("1.2.3"), pulumi.PluginDownloadURL("https://example.com")) + if err != nil { + return err + } + + // --- ConfigFile --- + _, err = yaml.NewConfigFile(ctx, "cf-options", &yaml.ConfigFileArgs{ + ResourcePrefix: "cf-options", + SkipAwait: true, + Transformations: []yaml.Transformation{transformK8s}, + File: "./testdata/options/configfile/manifest.yaml", + }, + pulumi.Providers(aProvider), + pulumi.Aliases([]pulumi.Alias{{Name: pulumi.String("cf-options-old")}}), + pulumi.IgnoreChanges([]string{"ignored"}), + pulumi.Protect(true), + pulumi.DependsOn([]pulumi.Resource{sleep}), + pulumi.Transformations([]pulumi.ResourceTransformation{applyAlias}), + ) + if err != nil { + return err + } + + // "provider" option + _, err = yaml.NewConfigFile(ctx, "cf-provider", &yaml.ConfigFileArgs{ + ResourcePrefix: "cf-provider", + File: "./testdata/options/configfile/manifest.yaml", + }, pulumi.Providers(bProvider)) + if err != nil { + return err + } + + // null opts + _, err = yaml.NewConfigFile(ctx, "cf-nullopts", &yaml.ConfigFileArgs{ + ResourcePrefix: "cf-nullopts", + File: "./testdata/options/configfile/manifest.yaml", + }) + if err != nil { + return err + } + + // empty manifest + _, err = yaml.NewConfigFile(ctx, "cf-empty", &yaml.ConfigFileArgs{ + ResourcePrefix: "cf-empty", + File: "./testdata/options/configfile/empty.yaml", + }, pulumi.Providers(bProvider)) + if err != nil { + return err + } + + // --- Directory --- + _, err = kustomize.NewDirectory(ctx, "kustomize-options", kustomize.DirectoryArgs{ + Directory: pulumi.String("./testdata/options/kustomize"), + ResourcePrefix: "kustomize-options", + Transformations: []yaml.Transformation{transformK8s}, + }, + pulumi.Providers(aProvider), + pulumi.Aliases([]pulumi.Alias{{Name: pulumi.String("kustomize-options-old")}}), + pulumi.IgnoreChanges([]string{"ignored"}), + pulumi.Protect(true), + pulumi.DependsOn([]pulumi.Resource{sleep}), + pulumi.Transformations([]pulumi.ResourceTransformation{applyAlias}), + ) + if err != nil { + return err + } + + // "provider" option + _, err = kustomize.NewDirectory(ctx, "kustomize-provider", kustomize.DirectoryArgs{ + Directory: pulumi.String("./testdata/options/kustomize"), + ResourcePrefix: "kustomize-provider", + }, pulumi.Provider(bProvider)) + if err != nil { + return err + } + + // null opts + _, err = kustomize.NewDirectory(ctx, "kustomize-nullopts", kustomize.DirectoryArgs{ + Directory: pulumi.String("./testdata/options/kustomize"), + ResourcePrefix: "kustomize-nullopts", + }) + if err != nil { + return err + } + + // --- Chart --- + _, err = helm.NewChart(ctx, "chart-options", helm.ChartArgs{ + Path: pulumi.String("./testdata/options/chart"), + ResourcePrefix: "chart-options", + Transformations: []yaml.Transformation{transformK8s}, + SkipAwait: pulumi.Bool(true), + }, + pulumi.Providers(aProvider), + pulumi.Aliases([]pulumi.Alias{{Name: pulumi.String("chart-options-old")}}), + pulumi.IgnoreChanges([]string{"ignored"}), + pulumi.Protect(true), + pulumi.DependsOn([]pulumi.Resource{sleep}), + pulumi.Transformations([]pulumi.ResourceTransformation{applyAlias}), + ) + if err != nil { + return err + } + + // "provider" option + _, err = helm.NewChart(ctx, "chart-provider", helm.ChartArgs{ + Path: pulumi.String("./testdata/options/chart"), + ResourcePrefix: "chart-provider", + }, pulumi.Provider(bProvider)) + if err != nil { + return err + } + + // null opts + _, err = helm.NewChart(ctx, "chart-nullopts", helm.ChartArgs{ + Path: pulumi.String("./testdata/options/chart"), + ResourcePrefix: "chart-nullopts", + }) + if err != nil { + return err + } + + return nil + }) +} From 9f5429c7d7d53342f2b5b9c5f12034c7e6bc2d2f Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 11 Dec 2023 12:29:15 -0800 Subject: [PATCH 29/31] fix: ConfigFile (skipAwait) --- provider/pkg/gen/_go-templates/yaml/configFile.go | 2 +- sdk/go/kubernetes/yaml/configFile.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/provider/pkg/gen/_go-templates/yaml/configFile.go b/provider/pkg/gen/_go-templates/yaml/configFile.go index 3a580f36d3..0d0479b31e 100644 --- a/provider/pkg/gen/_go-templates/yaml/configFile.go +++ b/provider/pkg/gen/_go-templates/yaml/configFile.go @@ -163,7 +163,7 @@ func NewConfigFile(ctx *pulumi.Context, } rs, err := parseDecodeYamlFiles(ctx, &ConfigGroupArgs{ Files: []string{args.File}, - Transformations: args.Transformations, + Transformations: transformations, ResourcePrefix: args.ResourcePrefix, }, false, parseOpts...) if err != nil { diff --git a/sdk/go/kubernetes/yaml/configFile.go b/sdk/go/kubernetes/yaml/configFile.go index 3a580f36d3..0d0479b31e 100644 --- a/sdk/go/kubernetes/yaml/configFile.go +++ b/sdk/go/kubernetes/yaml/configFile.go @@ -163,7 +163,7 @@ func NewConfigFile(ctx *pulumi.Context, } rs, err := parseDecodeYamlFiles(ctx, &ConfigGroupArgs{ Files: []string{args.File}, - Transformations: args.Transformations, + Transformations: transformations, ResourcePrefix: args.ResourcePrefix, }, false, parseOpts...) if err != nil { From 998264e9c5b96911d187885e506b4db4038d1f26 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 11 Dec 2023 13:56:22 -0800 Subject: [PATCH 30/31] go tests --- tests/pulumirpc/rpc.go | 11 +++- tests/sdk/go/go_test.go | 102 +++++++++++++------------------- tests/sdk/go/options/main.go | 14 ++--- tests/sdk/nodejs/nodejs_test.go | 2 +- tests/sdk/python/python_test.go | 2 +- 5 files changed, 58 insertions(+), 73 deletions(-) diff --git a/tests/pulumirpc/rpc.go b/tests/pulumirpc/rpc.go index 6d5c1452e5..97da9f5121 100644 --- a/tests/pulumirpc/rpc.go +++ b/tests/pulumirpc/rpc.go @@ -6,6 +6,8 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" + "testing" "github.com/pulumi/pulumi/sdk/v3/go/common/resource" "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" @@ -31,12 +33,19 @@ type DebugInterceptorLog struct { LogPath string } -func NewDebugInterceptorLog() (*DebugInterceptorLog, error) { +func NewDebugInterceptorLog(t *testing.T) (*DebugInterceptorLog, error) { f, err := os.CreateTemp("", "pulumi-grpc-debug-") if err != nil { return nil, fmt.Errorf("failed to create GRPC debug log file: %v", err) } defer contract.IgnoreClose(f) + path, _ := filepath.Abs(f.Name()) + t.Logf("GRPC debug log file: %s", path) + t.Cleanup(func() { + if !t.Failed() { + os.Remove(path) + } + }) return &DebugInterceptorLog{LogPath: f.Name()}, nil } diff --git a/tests/sdk/go/go_test.go b/tests/sdk/go/go_test.go index 4418452abe..63b1e6b7d0 100644 --- a/tests/sdk/go/go_test.go +++ b/tests/sdk/go/go_test.go @@ -456,7 +456,7 @@ func TestOptionPropagation(t *testing.T) { t.FailNow() } - grpcLog, err := pulumirpctesting.NewDebugInterceptorLog() + grpcLog, err := pulumirpctesting.NewDebugInterceptorLog(t) require.NoError(t, err) options := baseOptions.With(integration.ProgramTestOptions{ @@ -513,11 +513,11 @@ func TestOptionPropagation(t *testing.T) { "kubernetes:core/v1:ConfigMap", "cg-options-cg-options-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("cg-options-cm-1-k8s-aliased"), Alias("cg-options-cg-options-cm-1-aliased")), - "Protect": BeTrue(), + "Aliases": HaveExactElements(Alias("cg-options-cg-options-cm-1-aliased")), + "Protect": BeFalse(), "Dependencies": BeEmpty(), "Provider": BeEquivalentTo(providerUrn(providerA)), - "Version": Not(BeEmpty()), + "Version": BeEmpty(), "Providers": BeEmpty(), "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ @@ -529,31 +529,16 @@ func TestOptionPropagation(t *testing.T) { }), }), )) + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigGroup", "cg-options"), - "kubernetes:yaml:ConfigFile", "cg-options-./testdata/options/configgroup/manifest.yaml")).To(HaveExactElements( - MatchFields(IgnoreExtras, Fields{ - "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("cg-options-./testdata/options/configgroup/manifest.yaml-aliased")), - "Protect": BeTrue(), - "Dependencies": BeEmpty(), - "Provider": BeEquivalentTo(providerUrn(providerA)), - "Version": BeEmpty(), - // quirk: unlike Python SDK, there's no providers on the intermediate ConfigFile. - // "Providers": MatchAllKeys(Keys{ - // "kubernetes": BeEquivalentTo(providerUrn(providerA)), - // }), - }), - }), - )) - g.Expect(rr.Named(urn("kubernetes:yaml:ConfigGroup", "kubernetes:yaml:ConfigFile", "cg-options-./testdata/options/configgroup/manifest.yaml"), "kubernetes:core/v1:ConfigMap", "cg-options-configgroup-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("configgroup-cm-1-k8s-aliased"), Alias("cg-options-configgroup-cm-1-aliased")), - "Protect": BeTrue(), + "Aliases": HaveExactElements(Alias("cg-options-configgroup-cm-1-aliased")), + "Protect": BeFalse(), "Dependencies": BeEmpty(), "Provider": BeEquivalentTo(providerUrn(providerA)), - "Version": Not(BeEmpty()), + "Version": BeEmpty(), "Providers": BeEmpty(), "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ @@ -567,7 +552,7 @@ func TestOptionPropagation(t *testing.T) { )) // ConfigGroup "cg-provider" with "provider" option that should propagate to children. - g.Expect(rr.Named("", + g.Expect(rr.Named(stackInfo.RootResource.URN, "kubernetes:yaml:ConfigGroup", "cg-provider")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ @@ -598,11 +583,10 @@ func TestOptionPropagation(t *testing.T) { // ConfigFile "cf-options" with most options g.Expect(rr.Named("", - "kubernetes:yaml:ConfigFile", "cf-options-cf-options")).To(HaveExactElements( - // quirk: NodeJS SDK applies resource_prefix ("cf-options") to the component itself. + "kubernetes:yaml:ConfigFile", "cf-options")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("cf-options-old"), Alias("cf-options-cf-options-aliased")), + "Aliases": HaveExactElements(Alias("cf-options-old"), Alias("cf-options-aliased")), "Protect": BeTrue(), "Dependencies": HaveExactElements(string(sleep.URN)), "Provider": BeEquivalentTo(providerUrn(providerA)), @@ -613,15 +597,15 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-options-cf-options"), + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-options"), "kubernetes:core/v1:ConfigMap", "cf-options-configfile-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("configfile-cm-1-k8s-aliased"), Alias("cf-options-configfile-cm-1-aliased")), - "Protect": BeTrue(), + "Aliases": HaveExactElements(Alias("cf-options-configfile-cm-1-aliased")), + "Protect": BeFalse(), "Dependencies": BeEmpty(), "Provider": BeEquivalentTo(providerUrn(providerA)), - "Version": Not(BeEmpty()), + "Version": BeEmpty(), "Providers": BeEmpty(), "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ @@ -635,9 +619,8 @@ func TestOptionPropagation(t *testing.T) { )) // ConfigFile "cf-provider" with "provider" option that should propagate to children. - g.Expect(rr.Named("", - "kubernetes:yaml:ConfigFile", "cf-provider-cf-provider")).To(HaveExactElements( - // quirk: NodeJS SDK applies resource_prefix ("cf-provider") to the component itself. + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:yaml:ConfigFile", "cf-provider")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEquivalentTo(providerUrn(providerB)), @@ -648,12 +631,12 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-provider-cf-provider"), + g.Expect(rr.Named(urn("", "kubernetes:yaml:ConfigFile", "cf-provider"), "kubernetes:core/v1:ConfigMap", "cf-provider-configfile-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEquivalentTo(providerUrn(providerB)), - "Version": Not(BeEmpty()), + "Version": BeEmpty(), "Providers": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ "metadata": MatchKeys(IgnoreExtras, Keys{ @@ -666,8 +649,7 @@ func TestOptionPropagation(t *testing.T) { // ConfigFile "cf-nullopts" with a stack transform to apply a "provider" option. g.Expect(rr.Named("", - "kubernetes:yaml:ConfigFile", "cf-nullopts-cf-nullopts")).To(HaveExactElements( - // quirk: NodeJS SDK applies resource_prefix ("cf-nullopts") to the component itself. + "kubernetes:yaml:ConfigFile", "cf-nullopts")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEquivalentTo(providerUrn(providerNullOpts)), @@ -683,11 +665,11 @@ func TestOptionPropagation(t *testing.T) { // Directory "kustomize-options" with most options g.Expect(rr.Named("", - "kubernetes:kustomize:Directory", "kustomize-options-kustomize-options")).To(HaveExactElements( + "kubernetes:kustomize:Directory", "kustomize-options")).To(HaveExactElements( // quirk: NodeJS SDK applies resource_prefix ("kustomize-options") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("kustomize-options-old"), Alias("kustomize-options-kustomize-options-aliased")), + "Aliases": HaveExactElements(Alias("kustomize-options-old"), Alias("kustomize-options-aliased")), "Protect": BeTrue(), "Dependencies": HaveExactElements(string(sleep.URN)), "Provider": BeEquivalentTo(providerUrn(providerA)), @@ -699,15 +681,15 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-options-kustomize-options"), + g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-options"), "kubernetes:core/v1:ConfigMap", "kustomize-options-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("kustomize-cm-1-2kkk4bthmg-k8s-aliased"), Alias("kustomize-options-kustomize-cm-1-2kkk4bthmg-aliased")), - "Protect": BeTrue(), + "Aliases": HaveExactElements(Alias("kustomize-options-kustomize-cm-1-2kkk4bthmg-aliased")), + "Protect": BeFalse(), "Dependencies": BeEmpty(), "Provider": BeEquivalentTo(providerUrn(providerA)), - "Version": Not(BeEmpty()), + "Version": BeEmpty(), "Providers": BeEmpty(), "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ @@ -721,8 +703,8 @@ func TestOptionPropagation(t *testing.T) { )) // Directory "kustomize-provider" with "provider" option that should propagate to children. - g.Expect(rr.Named("", - "kubernetes:kustomize:Directory", "kustomize-provider-kustomize-provider")).To(HaveExactElements( + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:kustomize:Directory", "kustomize-provider")).To(HaveExactElements( // quirk: NodeJS SDK applies resource_prefix ("kustomize-provider") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ @@ -734,12 +716,12 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-provider-kustomize-provider"), + g.Expect(rr.Named(urn("", "kubernetes:kustomize:Directory", "kustomize-provider"), "kubernetes:core/v1:ConfigMap", "kustomize-provider-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEquivalentTo(providerUrn(providerB)), - "Version": Not(BeEmpty()), + "Version": BeEmpty(), "Providers": BeEmpty(), }), }), @@ -747,7 +729,7 @@ func TestOptionPropagation(t *testing.T) { // Directory "kustomize-nullopts" with a stack transform to apply a "provider" option. g.Expect(rr.Named("", - "kubernetes:kustomize:Directory", "kustomize-nullopts-kustomize-nullopts")).To(HaveExactElements( + "kubernetes:kustomize:Directory", "kustomize-nullopts")).To(HaveExactElements( // quirk: NodeJS SDK applies resource_prefix ("kustomize-nullopts") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ @@ -764,11 +746,11 @@ func TestOptionPropagation(t *testing.T) { // Chart "chart-options" g.Expect(rr.Named("", - "kubernetes:helm.sh/v3:Chart", "chart-options-chart-options")).To(HaveExactElements( + "kubernetes:helm.sh/v3:Chart", "chart-options")).To(HaveExactElements( // quirk: NodeJS SDK applies resource_prefix ("chart-options") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(AliasByType("kubernetes:helm.sh/v2:Chart"), Alias("chart-options-old"), Alias("chart-options-chart-options-aliased")), + "Aliases": HaveExactElements(Alias("chart-options-old"), AliasByType("kubernetes:helm.sh/v2:Chart"), Alias("chart-options-aliased")), "Protect": BeTrue(), "Dependencies": HaveExactElements(string(sleep.URN)), "Provider": BeEquivalentTo(providerUrn(providerA)), @@ -780,15 +762,15 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-options-chart-options"), + g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-options"), "kubernetes:core/v1:ConfigMap", "chart-options-chart-options-chart-options-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("chart-options-chart-options-cm-1-k8s-aliased"), Alias("chart-options-chart-options-chart-options-cm-1-aliased")), - "Protect": BeTrue(), + "Aliases": HaveExactElements(Alias("chart-options-chart-options-chart-options-cm-1-aliased")), + "Protect": BeFalse(), "Dependencies": BeEmpty(), "Provider": BeEquivalentTo(providerUrn(providerA)), - "Version": Not(BeEmpty()), + "Version": BeEmpty(), "Providers": BeEmpty(), "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ @@ -802,8 +784,8 @@ func TestOptionPropagation(t *testing.T) { )) // Chart "chart-provider" with "provider" option that should propagate to children. - g.Expect(rr.Named("", - "kubernetes:helm.sh/v3:Chart", "chart-provider-chart-provider")).To(HaveExactElements( + g.Expect(rr.Named(stackInfo.RootResource.URN, + "kubernetes:helm.sh/v3:Chart", "chart-provider")).To(HaveExactElements( // quirk: NodeJS SDK applies resource_prefix ("chart-provider") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ @@ -815,12 +797,12 @@ func TestOptionPropagation(t *testing.T) { }), }), )) - g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-provider-chart-provider"), + g.Expect(rr.Named(urn("", "kubernetes:helm.sh/v3:Chart", "chart-provider"), "kubernetes:core/v1:ConfigMap", "chart-provider-chart-provider-chart-provider-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ "Provider": BeEquivalentTo(providerUrn(providerB)), - "Version": Not(BeEmpty()), + "Version": BeEmpty(), "Providers": BeEmpty(), }), }), @@ -828,7 +810,7 @@ func TestOptionPropagation(t *testing.T) { // Chart "chart-nullopts" with a stack transform to apply a "provider" option. g.Expect(rr.Named("", - "kubernetes:helm.sh/v3:Chart", "chart-nullopts-chart-nullopts")).To(HaveExactElements( + "kubernetes:helm.sh/v3:Chart", "chart-nullopts")).To(HaveExactElements( // quirk: NodeJS SDK applies resource_prefix ("chart-options") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ diff --git a/tests/sdk/go/options/main.go b/tests/sdk/go/options/main.go index cb1bbc495a..c28dc0c111 100644 --- a/tests/sdk/go/options/main.go +++ b/tests/sdk/go/options/main.go @@ -79,13 +79,11 @@ func main() { // transform_k8s is a Kubernetes transformation that applies a unique alias and annotation to each resource. transformK8s := func(state map[string]interface{}, opts ...pulumi.ResourceOption) { - if state["kind"] == "Service" { - metadata := state["metadata"].(map[string]interface{}) - metadata["annotations"] = map[string]interface{}{"transformed": "true"} + metadata := state["metadata"].(map[string]interface{}) + metadata["annotations"] = map[string]interface{}{"transformed": "true"} - // note: pulumi-kubernetes Go SDK doesn't provide a way to mutate the options (e.g. to add a "-k8s-aliased" alias) - // https://github.com/pulumi/pulumi-kubernetes/issues/2666 - } + // note: pulumi-kubernetes Go SDK doesn't provide a way to mutate the options (e.g. to add a "-k8s-aliased" alias) + // https://github.com/pulumi/pulumi-kubernetes/issues/2666 } // --- ConfigGroup --- @@ -113,10 +111,6 @@ metadata: return err } - if true { - return nil - } - // "provider" option _, err = yaml.NewConfigGroup(ctx, "cg-provider", &yaml.ConfigGroupArgs{ ResourcePrefix: "cg-provider", diff --git a/tests/sdk/nodejs/nodejs_test.go b/tests/sdk/nodejs/nodejs_test.go index 6e1b929290..8783cfa8e6 100644 --- a/tests/sdk/nodejs/nodejs_test.go +++ b/tests/sdk/nodejs/nodejs_test.go @@ -2036,7 +2036,7 @@ func TestOptionPropagation(t *testing.T) { t.FailNow() } - grpcLog, err := pulumirpctesting.NewDebugInterceptorLog() + grpcLog, err := pulumirpctesting.NewDebugInterceptorLog(t) require.NoError(t, err) options := baseOptions.With(integration.ProgramTestOptions{ diff --git a/tests/sdk/python/python_test.go b/tests/sdk/python/python_test.go index 97e9282b57..268d722b77 100644 --- a/tests/sdk/python/python_test.go +++ b/tests/sdk/python/python_test.go @@ -555,7 +555,7 @@ func TestOptionPropagation(t *testing.T) { t.FailNow() } - grpcLog, err := pulumirpctesting.NewDebugInterceptorLog() + grpcLog, err := pulumirpctesting.NewDebugInterceptorLog(t) require.NoError(t, err) options := baseOptions.With(integration.ProgramTestOptions{ From c15bd22680a0493df5eb5b5f7b2bcfa0c37ace34 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Tue, 12 Dec 2023 11:10:47 -0800 Subject: [PATCH 31/31] version propagation (go sdk) --- provider/pkg/gen/_go-templates/yaml/yaml.tmpl | 10 ++ sdk/go/kubernetes/yaml/yaml.go | 10 ++ tests/pulumirpc/{rpc.go => log.go} | 95 ++++++++++-- tests/sdk/go/go_test.go | 135 ++++++++++-------- tests/sdk/go/options/main.go | 28 ++-- 5 files changed, 191 insertions(+), 87 deletions(-) rename tests/pulumirpc/{rpc.go => log.go} (72%) diff --git a/provider/pkg/gen/_go-templates/yaml/yaml.tmpl b/provider/pkg/gen/_go-templates/yaml/yaml.tmpl index e89e1a4d0c..28cec842f8 100644 --- a/provider/pkg/gen/_go-templates/yaml/yaml.tmpl +++ b/provider/pkg/gen/_go-templates/yaml/yaml.tmpl @@ -35,7 +35,17 @@ import ( ) func GetChildOptions(parent pulumi.Resource, opts []pulumi.ResourceOption) ([]pulumi.ResourceOption, error) { + snapshot, err := pulumi.NewResourceOptions(opts...) + if err != nil { + return nil, err + } childOpts := []pulumi.ResourceOption{pulumi.Parent(parent)} + if snapshot.Version != "" { + childOpts = append(childOpts, pulumi.Version(snapshot.Version)) + } + if snapshot.PluginDownloadURL != "" { + childOpts = append(childOpts, pulumi.PluginDownloadURL(snapshot.PluginDownloadURL)) + } return childOpts, nil } diff --git a/sdk/go/kubernetes/yaml/yaml.go b/sdk/go/kubernetes/yaml/yaml.go index edb4cd2efc..ebbcd3e24b 100644 --- a/sdk/go/kubernetes/yaml/yaml.go +++ b/sdk/go/kubernetes/yaml/yaml.go @@ -86,7 +86,17 @@ import ( ) func GetChildOptions(parent pulumi.Resource, opts []pulumi.ResourceOption) ([]pulumi.ResourceOption, error) { + snapshot, err := pulumi.NewResourceOptions(opts...) + if err != nil { + return nil, err + } childOpts := []pulumi.ResourceOption{pulumi.Parent(parent)} + if snapshot.Version != "" { + childOpts = append(childOpts, pulumi.Version(snapshot.Version)) + } + if snapshot.PluginDownloadURL != "" { + childOpts = append(childOpts, pulumi.PluginDownloadURL(snapshot.PluginDownloadURL)) + } return childOpts, nil } diff --git a/tests/pulumirpc/rpc.go b/tests/pulumirpc/log.go similarity index 72% rename from tests/pulumirpc/rpc.go rename to tests/pulumirpc/log.go index 97da9f5121..1461cef3ab 100644 --- a/tests/pulumirpc/rpc.go +++ b/tests/pulumirpc/log.go @@ -67,17 +67,6 @@ func (d *DebugInterceptorLog) ReadAll() (DebugInterceptorLogEntryList, error) { type DebugInterceptorLogEntryList []DebugInterceptorLogEntry -// ListRegisterResource lists the RegisterResource calls in the log. -func (l DebugInterceptorLogEntryList) ListRegisterResource() RegisterResourceList { - var results []RegisterResource - for _, entry := range l { - if r, ok := ParseRegisterResource(entry); ok { - results = append(results, *r) - } - } - return results -} - // ReadDebugInterceptorLogFile parses the gRPC log file produced by the PULUMI_DEBUG_GRPC environment variable. func ReadDebugInterceptorLogFile(name string) ([]DebugInterceptorLogEntry, error) { f, err := os.Open(name) @@ -123,9 +112,26 @@ func FormatDebugInterceptorLog(value interface{}) (string, bool) { if m, ok := value.(pulumirpc.Alias); ok { return protojson.Format(&m), true } + if m, ok := value.(pulumirpc.ResourceInvokeRequest); ok { + return protojson.Format(&m), true + } + if m, ok := value.(pulumirpc.InvokeResponse); ok { + return protojson.Format(&m), true + } return "", false } +// ListRegisterResource lists the RegisterResource calls in the log. +func (l DebugInterceptorLogEntryList) ListRegisterResource() RegisterResourceList { + var results []RegisterResource + for _, entry := range l { + if r, ok := ParseRegisterResource(entry); ok { + results = append(results, *r) + } + } + return results +} + // RegisterResource is a decoded "/pulumirpc.ResourceMonitor/RegisterResource" RPC call. type RegisterResource struct { Request pulumirpc.RegisterResourceRequest @@ -170,3 +176,70 @@ func ParseRegisterResource(entry DebugInterceptorLogEntry) (*RegisterResource, b } return &result, true } + +// Invokes lists the Invoke calls in the log. +func (l DebugInterceptorLogEntryList) Invokes() InvokeList { + var results []Invoke + for _, entry := range l { + if r, ok := ParseInvoke(entry); ok { + results = append(results, *r) + } + } + return results +} + +// Invoke is a decoded "/pulumirpc.ResourceMonitor/Invoke" RPC call. +type Invoke struct { + Request pulumirpc.ResourceInvokeRequest + Response pulumirpc.InvokeResponse + Errors []string `json:"errors,omitempty"` + Metadata interface{} `json:"metadata,omitempty"` +} + +type InvokeList []Invoke + +// Lookup returns Invoke entries matching the given token (operation). +func (l InvokeList) Tok(tok string) InvokeList { + var results []Invoke + for _, v := range l { + if v.Request.Tok == tok { + results = append(results, v) + } + } + return results +} + +// Lookup returns Invoke entries matching the given provider and token (operation). +func (l InvokeList) ByProvider(providerUrn resource.URN) InvokeList { + var results []Invoke + for _, v := range l { + if resource.URN(v.Request.Provider) == providerUrn { + results = append(results, v) + } + } + return results +} + +// ParseInvoke parses a log entry as a Invoke call. +func ParseInvoke(entry DebugInterceptorLogEntry) (*Invoke, bool) { + if entry.Method != "/pulumirpc.ResourceMonitor/Invoke" { + return nil, false + } + request := &pulumirpc.ResourceInvokeRequest{} + err := protojson.Unmarshal(entry.Request, request) + if err != nil { + return nil, false + } + response := &pulumirpc.InvokeResponse{} + err = protojson.Unmarshal(entry.Response, response) + if err != nil { + return nil, false + } + result := Invoke{ + Request: *request, + Response: *response, + Errors: entry.Errors, + Metadata: entry.Metadata, + } + return &result, true +} diff --git a/tests/sdk/go/go_test.go b/tests/sdk/go/go_test.go index 63b1e6b7d0..e191a1788f 100644 --- a/tests/sdk/go/go_test.go +++ b/tests/sdk/go/go_test.go @@ -489,19 +489,34 @@ func TestOptionPropagation(t *testing.T) { logEntries, err := grpcLog.ReadAll() require.NoError(t, err) rr := logEntries.ListRegisterResource() + invokes := logEntries.Invokes() + + // Verify that the invokes for provider A contain version info across-the-board. + // The Version and PluginDownloadURL options normally serve as hints when selecting + // a default provider, and should be propagated. For testing purposes, we set the provider explicitly to avoid + // any attempt to use the fake version/url. + g.Expect(invokes.ByProvider(providerUrn(providerA))).To(HaveEach( + MatchFields(IgnoreExtras, Fields{ + "Request": MatchFields(IgnoreExtras, Fields{ + "Version": Equal("1.2.3"), + "PluginDownloadURL": Equal("https://a.pulumi.test"), + }), + }), + )) // --- ConfigGroup --- - // ConfigGroup "cg-options" with most options + // ConfigGroup "cg-options" with most options. g.Expect(rr.Named("", "kubernetes:yaml:ConfigGroup", "cg-options")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("cg-options-old"), Alias("cg-options-aliased")), - "Protect": BeTrue(), - "Dependencies": HaveExactElements(string(sleep.URN)), - "Provider": BeEquivalentTo(providerUrn(providerA)), - "Version": BeEmpty(), + "Aliases": HaveExactElements(Alias("cg-options-old"), Alias("cg-options-aliased")), + "Protect": BeTrue(), + "Dependencies": HaveExactElements(string(sleep.URN)), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Equal("1.2.3"), + "PluginDownloadURL": Equal("https://a.pulumi.test"), "Providers": MatchAllKeys(Keys{ "kubernetes": BeEquivalentTo(providerUrn(providerA)), }), @@ -513,13 +528,14 @@ func TestOptionPropagation(t *testing.T) { "kubernetes:core/v1:ConfigMap", "cg-options-cg-options-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("cg-options-cg-options-cm-1-aliased")), - "Protect": BeFalse(), - "Dependencies": BeEmpty(), - "Provider": BeEquivalentTo(providerUrn(providerA)), - "Version": BeEmpty(), - "Providers": BeEmpty(), - "IgnoreChanges": BeEmpty(), + "Aliases": HaveExactElements(Alias("cg-options-cg-options-cm-1-aliased")), + "Protect": BeFalse(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Equal("1.2.3"), + "PluginDownloadURL": Equal("https://a.pulumi.test"), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ "metadata": MatchKeys(IgnoreExtras, Keys{ "name": Equal("cg-options-cm-1"), @@ -534,13 +550,14 @@ func TestOptionPropagation(t *testing.T) { "kubernetes:core/v1:ConfigMap", "cg-options-configgroup-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("cg-options-configgroup-cm-1-aliased")), - "Protect": BeFalse(), - "Dependencies": BeEmpty(), - "Provider": BeEquivalentTo(providerUrn(providerA)), - "Version": BeEmpty(), - "Providers": BeEmpty(), - "IgnoreChanges": BeEmpty(), + "Aliases": HaveExactElements(Alias("cg-options-configgroup-cm-1-aliased")), + "Protect": BeFalse(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Equal("1.2.3"), + "PluginDownloadURL": Equal("https://a.pulumi.test"), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ "metadata": MatchKeys(IgnoreExtras, Keys{ "name": Equal("configgroup-cm-1"), @@ -586,11 +603,12 @@ func TestOptionPropagation(t *testing.T) { "kubernetes:yaml:ConfigFile", "cf-options")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("cf-options-old"), Alias("cf-options-aliased")), - "Protect": BeTrue(), - "Dependencies": HaveExactElements(string(sleep.URN)), - "Provider": BeEquivalentTo(providerUrn(providerA)), - "Version": BeEmpty(), + "Aliases": HaveExactElements(Alias("cf-options-old"), Alias("cf-options-aliased")), + "Protect": BeTrue(), + "Dependencies": HaveExactElements(string(sleep.URN)), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Equal("1.2.3"), + "PluginDownloadURL": Equal("https://a.pulumi.test"), "Providers": MatchAllKeys(Keys{ "kubernetes": BeEquivalentTo(providerUrn(providerA)), }), @@ -601,13 +619,14 @@ func TestOptionPropagation(t *testing.T) { "kubernetes:core/v1:ConfigMap", "cf-options-configfile-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("cf-options-configfile-cm-1-aliased")), - "Protect": BeFalse(), - "Dependencies": BeEmpty(), - "Provider": BeEquivalentTo(providerUrn(providerA)), - "Version": BeEmpty(), - "Providers": BeEmpty(), - "IgnoreChanges": BeEmpty(), + "Aliases": HaveExactElements(Alias("cf-options-configfile-cm-1-aliased")), + "Protect": BeFalse(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Equal("1.2.3"), + "PluginDownloadURL": Equal("https://a.pulumi.test"), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ "metadata": MatchKeys(IgnoreExtras, Keys{ "name": Equal("configfile-cm-1"), @@ -669,11 +688,12 @@ func TestOptionPropagation(t *testing.T) { // quirk: NodeJS SDK applies resource_prefix ("kustomize-options") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("kustomize-options-old"), Alias("kustomize-options-aliased")), - "Protect": BeTrue(), - "Dependencies": HaveExactElements(string(sleep.URN)), - "Provider": BeEquivalentTo(providerUrn(providerA)), - "Version": BeEmpty(), + "Aliases": HaveExactElements(Alias("kustomize-options-old"), Alias("kustomize-options-aliased")), + "Protect": BeTrue(), + "Dependencies": HaveExactElements(string(sleep.URN)), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Equal("1.2.3"), + "PluginDownloadURL": Equal("https://a.pulumi.test"), "Providers": MatchAllKeys(Keys{ "kubernetes": BeEquivalentTo(providerUrn(providerA)), }), @@ -685,13 +705,14 @@ func TestOptionPropagation(t *testing.T) { "kubernetes:core/v1:ConfigMap", "kustomize-options-kustomize-cm-1-2kkk4bthmg")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("kustomize-options-kustomize-cm-1-2kkk4bthmg-aliased")), - "Protect": BeFalse(), - "Dependencies": BeEmpty(), - "Provider": BeEquivalentTo(providerUrn(providerA)), - "Version": BeEmpty(), - "Providers": BeEmpty(), - "IgnoreChanges": BeEmpty(), + "Aliases": HaveExactElements(Alias("kustomize-options-kustomize-cm-1-2kkk4bthmg-aliased")), + "Protect": BeFalse(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Equal("1.2.3"), + "PluginDownloadURL": Equal("https://a.pulumi.test"), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ "metadata": MatchKeys(IgnoreExtras, Keys{ "name": Equal("kustomize-cm-1-2kkk4bthmg"), @@ -750,11 +771,12 @@ func TestOptionPropagation(t *testing.T) { // quirk: NodeJS SDK applies resource_prefix ("chart-options") to the component itself. MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("chart-options-old"), AliasByType("kubernetes:helm.sh/v2:Chart"), Alias("chart-options-aliased")), - "Protect": BeTrue(), - "Dependencies": HaveExactElements(string(sleep.URN)), - "Provider": BeEquivalentTo(providerUrn(providerA)), - "Version": BeEmpty(), + "Aliases": HaveExactElements(Alias("chart-options-old"), AliasByType("kubernetes:helm.sh/v2:Chart"), Alias("chart-options-aliased")), + "Protect": BeTrue(), + "Dependencies": HaveExactElements(string(sleep.URN)), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Equal("1.2.3"), + "PluginDownloadURL": Equal("https://a.pulumi.test"), "Providers": MatchAllKeys(Keys{ "kubernetes": BeEquivalentTo(providerUrn(providerA)), }), @@ -766,13 +788,14 @@ func TestOptionPropagation(t *testing.T) { "kubernetes:core/v1:ConfigMap", "chart-options-chart-options-chart-options-cm-1")).To(HaveExactElements( MatchFields(IgnoreExtras, Fields{ "Request": MatchFields(IgnoreExtras, Fields{ - "Aliases": HaveExactElements(Alias("chart-options-chart-options-chart-options-cm-1-aliased")), - "Protect": BeFalse(), - "Dependencies": BeEmpty(), - "Provider": BeEquivalentTo(providerUrn(providerA)), - "Version": BeEmpty(), - "Providers": BeEmpty(), - "IgnoreChanges": BeEmpty(), + "Aliases": HaveExactElements(Alias("chart-options-chart-options-chart-options-cm-1-aliased")), + "Protect": BeFalse(), + "Dependencies": BeEmpty(), + "Provider": BeEquivalentTo(providerUrn(providerA)), + "Version": Equal("1.2.3"), + "PluginDownloadURL": Equal("https://a.pulumi.test"), + "Providers": BeEmpty(), + "IgnoreChanges": BeEmpty(), "Object": PointTo(ProtobufStruct(MatchKeys(IgnoreExtras, Keys{ "metadata": MatchKeys(IgnoreExtras, Keys{ "name": Equal("chart-options-chart-options-cm-1"), // note: based on the Helm Release name diff --git a/tests/sdk/go/options/main.go b/tests/sdk/go/options/main.go index c28dc0c111..7a98335b45 100644 --- a/tests/sdk/go/options/main.go +++ b/tests/sdk/go/options/main.go @@ -15,12 +15,6 @@ import ( func main() { pulumi.Run(func(ctx *pulumi.Context) error { - _, err := corev1.NewNamespace(ctx, "version", &corev1.NamespaceArgs{}, - pulumi.Version("1.2.3"), pulumi.PluginDownloadURL("https://example.com")) - if err != nil { - return err - } - bootstrapProvider, err := kubernetes.NewProvider(ctx, "bootstrap", &kubernetes.ProviderArgs{}) if err != nil { return err @@ -106,6 +100,8 @@ metadata: pulumi.Protect(true), pulumi.DependsOn([]pulumi.Resource{sleep}), pulumi.Transformations([]pulumi.ResourceTransformation{applyAlias}), + pulumi.Version("1.2.3"), + pulumi.PluginDownloadURL("https://a.pulumi.test"), ) if err != nil { return err @@ -139,20 +135,6 @@ metadata: return err } - // version - _, err = yaml.NewConfigGroup(ctx, "cg-version", &yaml.ConfigGroupArgs{ - ResourcePrefix: "cg-version", - YAML: []string{` -apiVersion: v1 -kind: ConfigMap -metadata: - name: cg-version-cm-1 -`}, - }, pulumi.Provider(nulloptsProvider), pulumi.Version("1.2.3"), pulumi.PluginDownloadURL("https://example.com")) - if err != nil { - return err - } - // --- ConfigFile --- _, err = yaml.NewConfigFile(ctx, "cf-options", &yaml.ConfigFileArgs{ ResourcePrefix: "cf-options", @@ -166,6 +148,8 @@ metadata: pulumi.Protect(true), pulumi.DependsOn([]pulumi.Resource{sleep}), pulumi.Transformations([]pulumi.ResourceTransformation{applyAlias}), + pulumi.Version("1.2.3"), + pulumi.PluginDownloadURL("https://a.pulumi.test"), ) if err != nil { return err @@ -210,6 +194,8 @@ metadata: pulumi.Protect(true), pulumi.DependsOn([]pulumi.Resource{sleep}), pulumi.Transformations([]pulumi.ResourceTransformation{applyAlias}), + pulumi.Version("1.2.3"), + pulumi.PluginDownloadURL("https://a.pulumi.test"), ) if err != nil { return err @@ -246,6 +232,8 @@ metadata: pulumi.Protect(true), pulumi.DependsOn([]pulumi.Resource{sleep}), pulumi.Transformations([]pulumi.ResourceTransformation{applyAlias}), + pulumi.Version("1.2.3"), + pulumi.PluginDownloadURL("https://a.pulumi.test"), ) if err != nil { return err