Revert 'Simplify API for passing providers to a ComponentResource (#2602)' (#2606)

This commit is contained in:
CyrusNajmabadi 2019-03-28 18:31:03 -07:00 committed by GitHub
parent 49a8e73aa7
commit 1f51ec00fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 72 additions and 610 deletions

View file

@ -1,10 +1,8 @@
## 0.17.5 (Unreleased)
### Improvements
- Correctly handle the case where we would fail to detect an archive type if the filename included a dot in it. (fixes [pulumi/pulumi#2589](https://github.com/pulumi/pulumi/issues/2589))
- The API for passing along a custom provider to a ComponentResource has been simplified. You can
now just say `new SomeComponentResource(name, props, { provider: awsProvider })` instead of
`new SomeComponentResource(name, props, { provider: { "aws" : awsProvider } })`
## 0.17.4 (Released March 26, 2019)

View file

@ -1,5 +1,5 @@
PROJECT_NAME := Pulumi SDK
SUB_PROJECTS := sdk/python sdk/nodejs sdk/go
SUB_PROJECTS := sdk/nodejs sdk/python sdk/go
include build/common.mk
PROJECT := github.com/pulumi/pulumi

View file

@ -133,10 +133,6 @@ export abstract class Resource {
throw new ResourceError("Missing resource name argument (for URN creation)", opts.parent);
}
if (opts.provider && (<ComponentResourceOptions>opts).providers) {
throw new ResourceError("Do not supply both 'provider' and 'providers' options to a ComponentResource.", opts.parent);
}
// Check the parent type if one exists and fill in any default options.
this.__providers = {};
if (opts.parent) {
@ -165,19 +161,12 @@ export abstract class Resource {
}
}
}
if (!custom) {
// Note: we checked above that at most one of opts.provider or opts.providers is set.
// If opts.provider is set, treat that as if we were given a array of provider with that
// single value in it. Otherwise, take the array or map of providers, convert it to a
// map and combine with any providers we've already set from our parent.
const providers = opts.provider
? convertToProvidersMap([opts.provider])
: convertToProvidersMap((<ComponentResourceOptions>opts).providers);
this.__providers = { ...this.__providers, ...providers };
const providers = (<ComponentResourceOptions>opts).providers;
if (providers) {
this.__providers = { ...this.__providers, ...providers };
}
}
this.__protect = !!opts.protect;
if (opts.id) {
@ -197,23 +186,6 @@ export abstract class Resource {
}
}
function convertToProvidersMap(providers: Record<string, ProviderResource> | ProviderResource[] | undefined) {
if (!providers) {
return {};
}
if (!Array.isArray(providers)) {
return providers;
}
const result: Record<string, ProviderResource> = {};
for (const provider of providers) {
result[provider.getPackage()] = provider;
}
return result;
}
(<any>Resource).doNotCapture = true;
/**
@ -236,21 +208,19 @@ export interface ResourceOptions {
* When set to true, protect ensures this resource cannot be deleted.
*/
protect?: boolean;
/**
* An optional provider to use for this resource's CRUD operations. If no provider is supplied,
* the default provider for the resource's package will be used. The default provider is pulled
* from the parent's provider bag (see also ComponentResourceOptions.providers).
*
* If this is a [ComponentResourceOptions] do not provide both [provider] and [providers]
*/
provider?: ProviderResource;
}
/**
* CustomResourceOptions is a bag of optional settings that control a custom resource's behavior.
*/
export interface CustomResourceOptions extends ResourceOptions {
/**
* An optional provider to use for this resource's CRUD operations. If no provider is supplied, the default
* provider for the resource's package will be used. The default provider is pulled from the parent's
* provider bag (see also ComponentResourceOptions.providers).
*/
provider?: ProviderResource;
/**
* When set to true, deleteBeforeReplace indicates that this resource should be deleted before its replacement
* is created when replacement is necessary.
@ -263,15 +233,9 @@ export interface CustomResourceOptions extends ResourceOptions {
*/
export interface ComponentResourceOptions extends ResourceOptions {
/**
* An optional set of providers to use for child resources. Either keyed by package name (e.g.
* "aws"), or just provided as an array. In the latter case, the package name will be retrieved
* from the provider itself.
*
* In the case of a single provider, the options can be simplified to just pass along `provider: theProvider`
*
* Note: do not provide both [provider] and [providers];
* An optional set of providers to use for child resources. Keyed by package name (e.g. "aws")
*/
providers?: Record<string, ProviderResource> | ProviderResource[];
providers?: Record<string, ProviderResource>;
}
/**
@ -339,13 +303,9 @@ export abstract class ProviderResource extends CustomResource {
* @param props The configuration to use for this provider.
* @param opts A bag of options that control this provider's behavior.
*/
constructor(private readonly pkg: string, name: string, props?: Inputs, opts: ResourceOptions = {}) {
constructor(pkg: string, name: string, props?: Inputs, opts: ResourceOptions = {}) {
super(`pulumi:providers:${pkg}`, name, props, opts);
}
public getPackage() {
return this.pkg;
}
}
/**
@ -382,6 +342,10 @@ export class ComponentResource extends Resource {
* @param opts A bag of options that control this resource's behavior.
*/
constructor(type: string, name: string, unused?: Inputs, opts: ComponentResourceOptions = {}) {
if ((<CustomResourceOptions>opts).provider) {
throw new ResourceError("Do not supply 'provider' option to a ComponentResource. Did you mean 'providers' instead?", opts.parent);
}
// Explicitly ignore the props passed in. We allow them for back compat reasons. However,
// we explicitly do not want to pass them along to the engine. The ComponentResource acts
// only as a container for other resources. Another way to think about this is that a normal

View file

@ -1,79 +0,0 @@
// This tests the creation of ten resources that contains "simple" input and output propeprties.
// In particular, there aren't any fancy dataflow linked properties.
let assert = require("assert");
let pulumi = require("../../../../../");
class Provider extends pulumi.ProviderResource {
constructor(name, opts) {
super("test", name, {}, opts);
}
}
class Resource extends pulumi.CustomResource {
constructor(name, createChildren, opts) {
super("test:index:Resource", name, {}, opts)
if (createChildren) {
createChildren(name, this);
}
}
}
class Component extends pulumi.ComponentResource {
constructor(name, createChildren, opts) {
super("test:index:Component", name, {}, opts);
createChildren(name, this);
}
}
function createResources(name, createChildren, parent) {
// Use all parent defaults
new Resource(`${name}/r0`, createChildren, { parent: parent });
// Override protect
new Resource(`${name}/r1`, createChildren, { parent: parent, protect: false });
new Resource(`${name}/r2`, createChildren, { parent: parent, protect: true });
// Override provider
new Resource(`${name}/r3`, createChildren, { parent: parent, provider: new Provider(`${name}-p`, { parent: parent }) });
}
function createComponents(name, createChildren, parent) {
// Use all parent defaults
new Component(`${name}/c0`, createChildren, { parent: parent });
// Override protect.
new Component(`${name}/c1`, createChildren, { parent: parent, protect: false });
new Component(`${name}/c2`, createChildren, { parent: parent, protect: true });
// Override providers.
new Component(`${name}/c3`, createChildren, {
parent: parent,
provider: new Provider(`${name}-p`, { parent: parent }),
});
}
// Create default (unparented) resources
createResources("unparented");
// Create singly-nested resources
createComponents("single-nest", (name, parent) => {
createResources(name, undefined, parent);
});
// Create doubly-nested resources
createComponents("double-nest", (name, parent) => {
createComponents(name, (name, parent) => {
createResources(name, undefined, parent);
}, parent);
});
// Create doubly-nested resources parented to other resources
createComponents("double-nest-2", (name, parent) => {
createResources(name, (name, parent) => {
createResources(name, undefined, parent);
}, parent);
});

View file

@ -1,79 +0,0 @@
// This tests the creation of ten resources that contains "simple" input and output propeprties.
// In particular, there aren't any fancy dataflow linked properties.
let assert = require("assert");
let pulumi = require("../../../../../");
class Provider extends pulumi.ProviderResource {
constructor(name, opts) {
super("test", name, {}, opts);
}
}
class Resource extends pulumi.CustomResource {
constructor(name, createChildren, opts) {
super("test:index:Resource", name, {}, opts)
if (createChildren) {
createChildren(name, this);
}
}
}
class Component extends pulumi.ComponentResource {
constructor(name, createChildren, opts) {
super("test:index:Component", name, {}, opts);
createChildren(name, this);
}
}
function createResources(name, createChildren, parent) {
// Use all parent defaults
new Resource(`${name}/r0`, createChildren, { parent: parent });
// Override protect
new Resource(`${name}/r1`, createChildren, { parent: parent, protect: false });
new Resource(`${name}/r2`, createChildren, { parent: parent, protect: true });
// Override provider
new Resource(`${name}/r3`, createChildren, { parent: parent, provider: new Provider(`${name}-p`, { parent: parent }) });
}
function createComponents(name, createChildren, parent) {
// Use all parent defaults
new Component(`${name}/c0`, createChildren, { parent: parent });
// Override protect.
new Component(`${name}/c1`, createChildren, { parent: parent, protect: false });
new Component(`${name}/c2`, createChildren, { parent: parent, protect: true });
// Override providers.
new Component(`${name}/c3`, createChildren, {
parent: parent,
providers: [new Provider(`${name}-p`, { parent: parent })],
});
}
// Create default (unparented) resources
createResources("unparented");
// Create singly-nested resources
createComponents("single-nest", (name, parent) => {
createResources(name, undefined, parent);
});
// Create doubly-nested resources
createComponents("double-nest", (name, parent) => {
createComponents(name, (name, parent) => {
createResources(name, undefined, parent);
}, parent);
});
// Create doubly-nested resources parented to other resources
createComponents("double-nest-2", (name, parent) => {
createResources(name, (name, parent) => {
createResources(name, undefined, parent);
}, parent);
});

View file

@ -431,7 +431,53 @@ describe("rpc", () => {
"parent_defaults": {
program: path.join(base, "017.parent_defaults"),
expectResourceCount: 240,
registerResource: parentDefaultsRegisterResource,
registerResource: (ctx: any, dryrun: boolean, t: string, name: string, res: any, dependencies?: string[],
custom?: boolean, protect?: boolean, parent?: string, provider?: string) => {
if (custom && !t.startsWith("pulumi:providers:")) {
let expectProtect = false;
let expectProviderName = "";
const rpath = name.split("/");
for (let i = 1; i < rpath.length; i++) {
switch (rpath[i]) {
case "c0":
case "r0":
// Pass through parent values
break;
case "c1":
case "r1":
// Force protect to false
expectProtect = false;
break;
case "c2":
case "r2":
// Force protect to true
expectProtect = true;
break;
case "c3":
case "r3":
// Force provider
expectProviderName = `${rpath.slice(0, i).join("/")}-p`;
break;
default:
assert.fail(`unexpected path element in name: ${rpath[i]}`);
}
}
// r3 explicitly overrides its provider.
if (rpath[rpath.length-1] === "r3") {
expectProviderName = `${rpath.slice(0, rpath.length-1).join("/")}-p`;
}
const providerName = provider!.split("::").reduce((_, v) => v);
assert.strictEqual(`${name}.protect: ${protect!}`, `${name}.protect: ${expectProtect}`);
assert.strictEqual(`${name}.provider: ${providerName}`, `${name}.provider: ${expectProviderName}`);
}
return { urn: makeUrn(t, name), id: name, props: {} };
},
},
"logging": {
program: path.join(base, "018.logging"),
@ -717,16 +763,6 @@ describe("rpc", () => {
// host should bail.
expectBail: true,
},
"component_opt_single_provider": {
program: path.join(base, "041.component_opt_single_provider"),
expectResourceCount: 240,
registerResource: parentDefaultsRegisterResource,
},
"component_opt_providers_array": {
program: path.join(base, "042.component_opt_providers_array"),
expectResourceCount: 240,
registerResource: parentDefaultsRegisterResource,
},
"depends_on_non_resource": {
program: path.join(base, "043.depends_on_non_resource"),
expectResourceCount: 0,
@ -949,55 +985,6 @@ describe("rpc", () => {
}
});
function parentDefaultsRegisterResource(
ctx: any, dryrun: boolean, t: string, name: string, res: any, dependencies?: string[],
custom?: boolean, protect?: boolean, parent?: string, provider?: string) {
if (custom && !t.startsWith("pulumi:providers:")) {
let expectProtect = false;
let expectProviderName = "";
const rpath = name.split("/");
for (let i = 1; i < rpath.length; i++) {
switch (rpath[i]) {
case "c0":
case "r0":
// Pass through parent values
break;
case "c1":
case "r1":
// Force protect to false
expectProtect = false;
break;
case "c2":
case "r2":
// Force protect to true
expectProtect = true;
break;
case "c3":
case "r3":
// Force provider
expectProviderName = `${rpath.slice(0, i).join("/")}-p`;
break;
default:
assert.fail(`unexpected path element in name: ${rpath[i]}`);
}
}
// r3 explicitly overrides its provider.
if (rpath[rpath.length-1] === "r3") {
expectProviderName = `${rpath.slice(0, rpath.length-1).join("/")}-p`;
}
const providerName = provider!.split("::").reduce((_, v) => v);
assert.strictEqual(`${name}.protect: ${protect!}`, `${name}.protect: ${expectProtect}`);
assert.strictEqual(`${name}.provider: ${providerName}`, `${name}.provider: ${expectProviderName}`);
}
return { urn: makeUrn(t, name), id: name, props: {} };
}
function mockRun(langHostClient: any, monitor: string, opts: RunCase, dryrun: boolean): Promise<[string | undefined, boolean]> {
return new Promise<[string | undefined, boolean]>(
(resolve, reject) => {

View file

@ -52,8 +52,6 @@ test_fast::
pipenv run pip install ./env/src
pipenv run python -m unittest discover -s lib/test -v
test_all:: test_fast
dist::
go install -ldflags "-X github.com/pulumi/pulumi/sdk/python/pkg/version.Version=${VERSION}" ${LANGHOST_PKG}
cp ./cmd/pulumi-language-python-exec "$$(go env GOPATH)"/bin/

View file

@ -13,7 +13,7 @@
# limitations under the License.
"""The Resource module, containing all resource-related definitions."""
from typing import Optional, List, Any, Mapping, Union, TYPE_CHECKING
from typing import Optional, List, Any, Mapping, TYPE_CHECKING
from .runtime import known_types
from .runtime.resource import register_resource, register_resource_outputs
@ -55,7 +55,7 @@ class ResourceOptions:
provider bag (see also ResourceOptions.providers).
"""
providers: Union[Mapping[str, 'ProviderResource'], List['ProviderResource']]
providers: Mapping[str, 'ProviderResource']
"""
An optional set of providers to use for child resources. Keyed by package name (e.g. "aws")
"""
@ -165,28 +165,13 @@ class Resource:
self._providers = {**self._providers, pkg: provider}
if not custom:
providers = self._convert_providers(opts.provider, opts.providers)
self._providers = {**self._providers, **providers}
providers = opts.providers
if providers is not None:
self._providers = {**self._providers, **providers}
self._protect = bool(opts.protect)
register_resource(self, t, name, custom, props, opts)
def _convert_providers(self, provider: Optional['ProviderResource'], providers: Union[Mapping[str, 'ProviderResource'], List['ProviderResource']]) -> Mapping[str, 'ProviderResource']:
if provider is not None:
return self._convert_providers(None, [provider])
if providers is None:
return {}
if not isinstance(providers, list):
return providers
result = {}
for p in providers:
result[p.package] = p
return result
def translate_output_property(self, prop: str) -> str:
"""
Provides subclasses of Resource an opportunity to translate names of output properties
@ -296,13 +281,6 @@ class ProviderResource(CustomResource):
ProviderResource is a resource that implements CRUD operations for other custom resources. These resources are
managed similarly to other resources, including the usual diffing and update semantics.
"""
package: str
"""
package is the name of the package this is provider for. Common examples are "aws" and "azure".
"""
def __init__(self,
pkg: str,
name: str,
@ -320,7 +298,6 @@ class ProviderResource(CustomResource):
raise TypeError("Explicit providers may not be used with provider resources")
# Provider resources are given a well-known type, prefixed with "pulumi:providers".
CustomResource.__init__(self, f"pulumi:providers:{pkg}", name, props, opts)
self.package = pkg
def export(name: str, value: Any):

View file

@ -1,13 +0,0 @@
# Copyright 2016-2018, Pulumi Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

View file

@ -1,71 +0,0 @@
# Copyright 2016-2018, Pulumi Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from pulumi import ProviderResource, CustomResource, ComponentResource, ResourceOptions
class Provider(ProviderResource):
def __init__(self, name, opts=None):
ProviderResource.__init__(self, "test", name, {}, opts)
class Resource(CustomResource):
def __init__(self, name, create_children, opts=None):
CustomResource.__init__(self, "test:index:Resource", name, {}, opts)
if create_children is not None:
create_children(name, self)
class Component(ComponentResource):
def __init__(self, name, create_children, opts=None):
ComponentResource.__init__(self, "test:index:Component", name, {}, opts)
create_children(name, self)
def create_resources(name, create_children=None, parent=None):
# Use all parent defaults.
Resource(f"{name}/r0", create_children, ResourceOptions(parent=parent))
# Override protect
Resource(f"{name}/r1", create_children, ResourceOptions(parent=parent, protect=False))
Resource(f"{name}/r2", create_children, ResourceOptions(parent=parent, protect=True))
# Override provider
prov = Provider(f"{name}-p", ResourceOptions(parent=parent))
Resource(f"{name}/r3", create_children, ResourceOptions(parent=parent, provider=prov))
def create_components(name, create_children=None, parent=None):
# Use all parent defaults.
Component(f"{name}/c0", create_children, ResourceOptions(parent=parent))
# Override protect
Component(f"{name}/c1", create_children, ResourceOptions(parent=parent, protect=False))
Component(f"{name}/c2", create_children, ResourceOptions(parent=parent, protect=True))
# Override providers
providers = [Provider(f"{name}-p", ResourceOptions(parent=parent))]
Component(f"{name}/c3", create_children, ResourceOptions(parent=parent, providers=providers))
# Create default (unparent) resources
create_resources("unparented")
# Create singly-nested resources
create_components("single-nest", lambda name, parent: create_resources(name, None, parent))
# Create doubly-nested resources
create_components("double-nest", lambda name, parent: create_components(
name,
lambda name, parent: create_resources(name, None, parent),
parent))
# Create doubly-nested resources parented to other resources
create_components("double-nest-2", lambda name, parent: create_resources(
name,
lambda name, parent: create_resources(name, None, parent),
parent))

View file

@ -1,68 +0,0 @@
# Copyright 2016-2018, Pulumi Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from os import path
from ..util import LanghostTest
class ComponentResourceListOfProvidersTest(LanghostTest):
"""
Tests that resources inherit a variety of properties from their parents, when parents are present.
This test generates a multi-level tree of resources of different kinds and parents them in various ways.
The crux of the test is that all leaf resources in the resource tree should inherit a variety of properties
from their parents.
"""
def test_component_resource_list_of_providers(self):
self.run_test(
program=path.join(self.base_path(), "component_resource_list_of_providers"),
expected_resource_count=240)
def register_resource(self, _ctx, _dry_run, ty, name, _resource,
_dependencies, _parent, custom, protect, provider, _property_deps, _delete_before_replace):
if custom and not ty.startswith("pulumi:providers:"):
expect_protect = False
expect_provider_name = ""
rpath = name.split("/")
for i, component in enumerate(rpath[1:]):
if component in ["r0", "c0"]:
# No overrides - get all values from parent.
continue
if component in ["r1", "c1"]:
# Protect overriden to be false.
expect_protect = False
continue
if component in ["r2", "c2"]:
# Protect overriden to be true.
expect_protect = True
continue
if component in ["r3", "c3"]:
# Provider overriden.
expect_provider_name = "/".join(rpath[:i+1]) + "-p"
# r3 explicitly overrides its provider.
if rpath[-1] == "r3":
expect_provider_name = "/".join(rpath[:-1]) + "-p"
# "provider" is a provider reference. To get the provider name (technically its ID, but this test
# uses names as IDs), get the first string before the double-colon.
provider_name = provider.split("::")[-1]
self.assertEqual(f"{name}.protect: {protect}", f"{name}.protect: {expect_protect}")
self.assertEqual(f"{name}.provider: {provider_name}", f"{name}.provider: {expect_provider_name}")
return {
"urn": self.make_urn(ty, name),
"id": name,
}

View file

@ -1,13 +0,0 @@
# Copyright 2016-2018, Pulumi Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

View file

@ -1,71 +0,0 @@
# Copyright 2016-2018, Pulumi Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from pulumi import ProviderResource, CustomResource, ComponentResource, ResourceOptions
class Provider(ProviderResource):
def __init__(self, name, opts=None):
ProviderResource.__init__(self, "test", name, {}, opts)
class Resource(CustomResource):
def __init__(self, name, create_children, opts=None):
CustomResource.__init__(self, "test:index:Resource", name, {}, opts)
if create_children is not None:
create_children(name, self)
class Component(ComponentResource):
def __init__(self, name, create_children, opts=None):
ComponentResource.__init__(self, "test:index:Component", name, {}, opts)
create_children(name, self)
def create_resources(name, create_children=None, parent=None):
# Use all parent defaults.
Resource(f"{name}/r0", create_children, ResourceOptions(parent=parent))
# Override protect
Resource(f"{name}/r1", create_children, ResourceOptions(parent=parent, protect=False))
Resource(f"{name}/r2", create_children, ResourceOptions(parent=parent, protect=True))
# Override provider
prov = Provider(f"{name}-p", ResourceOptions(parent=parent))
Resource(f"{name}/r3", create_children, ResourceOptions(parent=parent, provider=prov))
def create_components(name, create_children=None, parent=None):
# Use all parent defaults.
Component(f"{name}/c0", create_children, ResourceOptions(parent=parent))
# Override protect
Component(f"{name}/c1", create_children, ResourceOptions(parent=parent, protect=False))
Component(f"{name}/c2", create_children, ResourceOptions(parent=parent, protect=True))
# Override providers
provider = Provider(f"{name}-p", ResourceOptions(parent=parent))
Component(f"{name}/c3", create_children, ResourceOptions(parent=parent, provider=provider))
# Create default (unparent) resources
create_resources("unparented")
# Create singly-nested resources
create_components("single-nest", lambda name, parent: create_resources(name, None, parent))
# Create doubly-nested resources
create_components("double-nest", lambda name, parent: create_components(
name,
lambda name, parent: create_resources(name, None, parent),
parent))
# Create doubly-nested resources parented to other resources
create_components("double-nest-2", lambda name, parent: create_resources(
name,
lambda name, parent: create_resources(name, None, parent),
parent))

View file

@ -1,68 +0,0 @@
# Copyright 2016-2018, Pulumi Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from os import path
from ..util import LanghostTest
class ComponentResourceSingleProviderTest(LanghostTest):
"""
Tests that resources inherit a variety of properties from their parents, when parents are present.
This test generates a multi-level tree of resources of different kinds and parents them in various ways.
The crux of the test is that all leaf resources in the resource tree should inherit a variety of properties
from their parents.
"""
def test_component_resource_single_provider(self):
self.run_test(
program=path.join(self.base_path(), "component_resource_single_provider"),
expected_resource_count=240)
def register_resource(self, _ctx, _dry_run, ty, name, _resource,
_dependencies, _parent, custom, protect, provider, _property_deps, _delete_before_replace):
if custom and not ty.startswith("pulumi:providers:"):
expect_protect = False
expect_provider_name = ""
rpath = name.split("/")
for i, component in enumerate(rpath[1:]):
if component in ["r0", "c0"]:
# No overrides - get all values from parent.
continue
if component in ["r1", "c1"]:
# Protect overriden to be false.
expect_protect = False
continue
if component in ["r2", "c2"]:
# Protect overriden to be true.
expect_protect = True
continue
if component in ["r3", "c3"]:
# Provider overriden.
expect_provider_name = "/".join(rpath[:i+1]) + "-p"
# r3 explicitly overrides its provider.
if rpath[-1] == "r3":
expect_provider_name = "/".join(rpath[:-1]) + "-p"
# "provider" is a provider reference. To get the provider name (technically its ID, but this test
# uses names as IDs), get the first string before the double-colon.
provider_name = provider.split("::")[-1]
self.assertEqual(f"{name}.protect: {protect}", f"{name}.protect: {expect_protect}")
self.assertEqual(f"{name}.provider: {provider_name}", f"{name}.provider: {expect_provider_name}")
return {
"urn": self.make_urn(ty, name),
"id": name,
}