pulumi/sdk/nodejs/tests/resource.spec.ts

305 lines
11 KiB
TypeScript
Raw Permalink Normal View History

Support aliases for renaming, re-typing, or re-parenting resources (#2774) Adds a new resource option `aliases` which can be used to rename a resource. When making a breaking change to the name or type of a resource or component, the old name can be added to the list of `aliases` for a resource to ensure that existing resources will be migrated to the new name instead of being deleted and replaced with the new named resource. There are two key places this change is implemented. The first is the step generator in the engine. When computing whether there is an old version of a registered resource, we now take into account the aliases specified on the registered resource. That is, we first look up the resource by its new URN in the old state, and then by any aliases provided (in order). This can allow the resource to be matched as a (potential) update to an existing resource with a different URN. The second is the core `Resource` constructor in the JavaScript (and soon Python) SDKs. This change ensures that when a parent resource is aliased, that all children implicitly inherit corresponding aliases. It is similar to how many other resource options are "inherited" implicitly from the parent. Four specific scenarios are explicitly tested as part of this PR: 1. Renaming a resource 2. Adopting a resource into a component (as the owner of both component and consumption codebases) 3. Renaming a component instance (as the owner of the consumption codebase without changes to the component) 4. Changing the type of a component (as the owner of the component codebase without changes to the consumption codebase) 4. Combining (1) and (3) to make both changes to a resource at the same time
2019-06-01 06:01:01 +00:00
// 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.
/* eslint-disable */
Support aliases for renaming, re-typing, or re-parenting resources (#2774) Adds a new resource option `aliases` which can be used to rename a resource. When making a breaking change to the name or type of a resource or component, the old name can be added to the list of `aliases` for a resource to ensure that existing resources will be migrated to the new name instead of being deleted and replaced with the new named resource. There are two key places this change is implemented. The first is the step generator in the engine. When computing whether there is an old version of a registered resource, we now take into account the aliases specified on the registered resource. That is, we first look up the resource by its new URN in the old state, and then by any aliases provided (in order). This can allow the resource to be matched as a (potential) update to an existing resource with a different URN. The second is the core `Resource` constructor in the JavaScript (and soon Python) SDKs. This change ensures that when a parent resource is aliased, that all children implicitly inherit corresponding aliases. It is similar to how many other resource options are "inherited" implicitly from the parent. Four specific scenarios are explicitly tested as part of this PR: 1. Renaming a resource 2. Adopting a resource into a component (as the owner of both component and consumption codebases) 3. Renaming a component instance (as the owner of the consumption codebase without changes to the component) 4. Changing the type of a component (as the owner of the component codebase without changes to the consumption codebase) 4. Combining (1) and (3) to make both changes to a resource at the same time
2019-06-01 06:01:01 +00:00
import * as assert from "assert";
import { all } from "../output";
Support aliases for renaming, re-typing, or re-parenting resources (#2774) Adds a new resource option `aliases` which can be used to rename a resource. When making a breaking change to the name or type of a resource or component, the old name can be added to the list of `aliases` for a resource to ensure that existing resources will be migrated to the new name instead of being deleted and replaced with the new named resource. There are two key places this change is implemented. The first is the step generator in the engine. When computing whether there is an old version of a registered resource, we now take into account the aliases specified on the registered resource. That is, we first look up the resource by its new URN in the old state, and then by any aliases provided (in order). This can allow the resource to be matched as a (potential) update to an existing resource with a different URN. The second is the core `Resource` constructor in the JavaScript (and soon Python) SDKs. This change ensures that when a parent resource is aliased, that all children implicitly inherit corresponding aliases. It is similar to how many other resource options are "inherited" implicitly from the parent. Four specific scenarios are explicitly tested as part of this PR: 1. Renaming a resource 2. Adopting a resource into a component (as the owner of both component and consumption codebases) 3. Renaming a component instance (as the owner of the consumption codebase without changes to the component) 4. Changing the type of a component (as the owner of the component codebase without changes to the consumption codebase) 4. Combining (1) and (3) to make both changes to a resource at the same time
2019-06-01 06:01:01 +00:00
import * as runtime from "../runtime";
import {
allAliases,
createUrn,
ProviderResource,
CustomResource,
ComponentResource,
ComponentResourceOptions,
CustomResourceOptions,
DependencyProviderResource,
} from "../resource";
Support aliases for renaming, re-typing, or re-parenting resources (#2774) Adds a new resource option `aliases` which can be used to rename a resource. When making a breaking change to the name or type of a resource or component, the old name can be added to the list of `aliases` for a resource to ensure that existing resources will be migrated to the new name instead of being deleted and replaced with the new named resource. There are two key places this change is implemented. The first is the step generator in the engine. When computing whether there is an old version of a registered resource, we now take into account the aliases specified on the registered resource. That is, we first look up the resource by its new URN in the old state, and then by any aliases provided (in order). This can allow the resource to be matched as a (potential) update to an existing resource with a different URN. The second is the core `Resource` constructor in the JavaScript (and soon Python) SDKs. This change ensures that when a parent resource is aliased, that all children implicitly inherit corresponding aliases. It is similar to how many other resource options are "inherited" implicitly from the parent. Four specific scenarios are explicitly tested as part of this PR: 1. Renaming a resource 2. Adopting a resource into a component (as the owner of both component and consumption codebases) 3. Renaming a component instance (as the owner of the consumption codebase without changes to the component) 4. Changing the type of a component (as the owner of the component codebase without changes to the consumption codebase) 4. Combining (1) and (3) to make both changes to a resource at the same time
2019-06-01 06:01:01 +00:00
class MyResource extends ComponentResource {
constructor(name: string, opts?: ComponentResourceOptions) {
Support aliases for renaming, re-typing, or re-parenting resources (#2774) Adds a new resource option `aliases` which can be used to rename a resource. When making a breaking change to the name or type of a resource or component, the old name can be added to the list of `aliases` for a resource to ensure that existing resources will be migrated to the new name instead of being deleted and replaced with the new named resource. There are two key places this change is implemented. The first is the step generator in the engine. When computing whether there is an old version of a registered resource, we now take into account the aliases specified on the registered resource. That is, we first look up the resource by its new URN in the old state, and then by any aliases provided (in order). This can allow the resource to be matched as a (potential) update to an existing resource with a different URN. The second is the core `Resource` constructor in the JavaScript (and soon Python) SDKs. This change ensures that when a parent resource is aliased, that all children implicitly inherit corresponding aliases. It is similar to how many other resource options are "inherited" implicitly from the parent. Four specific scenarios are explicitly tested as part of this PR: 1. Renaming a resource 2. Adopting a resource into a component (as the owner of both component and consumption codebases) 3. Renaming a component instance (as the owner of the consumption codebase without changes to the component) 4. Changing the type of a component (as the owner of the component codebase without changes to the consumption codebase) 4. Combining (1) and (3) to make both changes to a resource at the same time
2019-06-01 06:01:01 +00:00
super("my:mod:MyResource", name, {}, opts);
}
}
class MyParentResource extends ComponentResource {
child: MyResource;
constructor(name: string, opts?: ComponentResourceOptions) {
Support aliases for renaming, re-typing, or re-parenting resources (#2774) Adds a new resource option `aliases` which can be used to rename a resource. When making a breaking change to the name or type of a resource or component, the old name can be added to the list of `aliases` for a resource to ensure that existing resources will be migrated to the new name instead of being deleted and replaced with the new named resource. There are two key places this change is implemented. The first is the step generator in the engine. When computing whether there is an old version of a registered resource, we now take into account the aliases specified on the registered resource. That is, we first look up the resource by its new URN in the old state, and then by any aliases provided (in order). This can allow the resource to be matched as a (potential) update to an existing resource with a different URN. The second is the core `Resource` constructor in the JavaScript (and soon Python) SDKs. This change ensures that when a parent resource is aliased, that all children implicitly inherit corresponding aliases. It is similar to how many other resource options are "inherited" implicitly from the parent. Four specific scenarios are explicitly tested as part of this PR: 1. Renaming a resource 2. Adopting a resource into a component (as the owner of both component and consumption codebases) 3. Renaming a component instance (as the owner of the consumption codebase without changes to the component) 4. Changing the type of a component (as the owner of the component codebase without changes to the consumption codebase) 4. Combining (1) and (3) to make both changes to a resource at the same time
2019-06-01 06:01:01 +00:00
super("my:mod:MyParentResource", name, {}, opts);
this.child = new MyResource(`${name}-child`, { parent: this });
}
}
describe("createUrn", () => {
before(() => {
runtime._setProject("myproject");
runtime._setStack("mystack");
Support aliases for renaming, re-typing, or re-parenting resources (#2774) Adds a new resource option `aliases` which can be used to rename a resource. When making a breaking change to the name or type of a resource or component, the old name can be added to the list of `aliases` for a resource to ensure that existing resources will be migrated to the new name instead of being deleted and replaced with the new named resource. There are two key places this change is implemented. The first is the step generator in the engine. When computing whether there is an old version of a registered resource, we now take into account the aliases specified on the registered resource. That is, we first look up the resource by its new URN in the old state, and then by any aliases provided (in order). This can allow the resource to be matched as a (potential) update to an existing resource with a different URN. The second is the core `Resource` constructor in the JavaScript (and soon Python) SDKs. This change ensures that when a parent resource is aliased, that all children implicitly inherit corresponding aliases. It is similar to how many other resource options are "inherited" implicitly from the parent. Four specific scenarios are explicitly tested as part of this PR: 1. Renaming a resource 2. Adopting a resource into a component (as the owner of both component and consumption codebases) 3. Renaming a component instance (as the owner of the consumption codebase without changes to the component) 4. Changing the type of a component (as the owner of the component codebase without changes to the consumption codebase) 4. Combining (1) and (3) to make both changes to a resource at the same time
2019-06-01 06:01:01 +00:00
});
after(() => {
runtime._setProject(undefined);
runtime._setStack(undefined);
});
Support aliases for renaming, re-typing, or re-parenting resources (#2774) Adds a new resource option `aliases` which can be used to rename a resource. When making a breaking change to the name or type of a resource or component, the old name can be added to the list of `aliases` for a resource to ensure that existing resources will be migrated to the new name instead of being deleted and replaced with the new named resource. There are two key places this change is implemented. The first is the step generator in the engine. When computing whether there is an old version of a registered resource, we now take into account the aliases specified on the registered resource. That is, we first look up the resource by its new URN in the old state, and then by any aliases provided (in order). This can allow the resource to be matched as a (potential) update to an existing resource with a different URN. The second is the core `Resource` constructor in the JavaScript (and soon Python) SDKs. This change ensures that when a parent resource is aliased, that all children implicitly inherit corresponding aliases. It is similar to how many other resource options are "inherited" implicitly from the parent. Four specific scenarios are explicitly tested as part of this PR: 1. Renaming a resource 2. Adopting a resource into a component (as the owner of both component and consumption codebases) 3. Renaming a component instance (as the owner of the consumption codebase without changes to the component) 4. Changing the type of a component (as the owner of the component codebase without changes to the consumption codebase) 4. Combining (1) and (3) to make both changes to a resource at the same time
2019-06-01 06:01:01 +00:00
it("handles name and type", async () => {
Support aliases for renaming, re-typing, or re-parenting resources (#2774) Adds a new resource option `aliases` which can be used to rename a resource. When making a breaking change to the name or type of a resource or component, the old name can be added to the list of `aliases` for a resource to ensure that existing resources will be migrated to the new name instead of being deleted and replaced with the new named resource. There are two key places this change is implemented. The first is the step generator in the engine. When computing whether there is an old version of a registered resource, we now take into account the aliases specified on the registered resource. That is, we first look up the resource by its new URN in the old state, and then by any aliases provided (in order). This can allow the resource to be matched as a (potential) update to an existing resource with a different URN. The second is the core `Resource` constructor in the JavaScript (and soon Python) SDKs. This change ensures that when a parent resource is aliased, that all children implicitly inherit corresponding aliases. It is similar to how many other resource options are "inherited" implicitly from the parent. Four specific scenarios are explicitly tested as part of this PR: 1. Renaming a resource 2. Adopting a resource into a component (as the owner of both component and consumption codebases) 3. Renaming a component instance (as the owner of the consumption codebase without changes to the component) 4. Changing the type of a component (as the owner of the component codebase without changes to the consumption codebase) 4. Combining (1) and (3) to make both changes to a resource at the same time
2019-06-01 06:01:01 +00:00
const urn = await createUrn("n", "t").promise();
assert.strictEqual(urn, "urn:pulumi:mystack::myproject::t::n");
});
Support aliases for renaming, re-typing, or re-parenting resources (#2774) Adds a new resource option `aliases` which can be used to rename a resource. When making a breaking change to the name or type of a resource or component, the old name can be added to the list of `aliases` for a resource to ensure that existing resources will be migrated to the new name instead of being deleted and replaced with the new named resource. There are two key places this change is implemented. The first is the step generator in the engine. When computing whether there is an old version of a registered resource, we now take into account the aliases specified on the registered resource. That is, we first look up the resource by its new URN in the old state, and then by any aliases provided (in order). This can allow the resource to be matched as a (potential) update to an existing resource with a different URN. The second is the core `Resource` constructor in the JavaScript (and soon Python) SDKs. This change ensures that when a parent resource is aliased, that all children implicitly inherit corresponding aliases. It is similar to how many other resource options are "inherited" implicitly from the parent. Four specific scenarios are explicitly tested as part of this PR: 1. Renaming a resource 2. Adopting a resource into a component (as the owner of both component and consumption codebases) 3. Renaming a component instance (as the owner of the consumption codebase without changes to the component) 4. Changing the type of a component (as the owner of the component codebase without changes to the consumption codebase) 4. Combining (1) and (3) to make both changes to a resource at the same time
2019-06-01 06:01:01 +00:00
it("handles name and type and parent", async () => {
Support aliases for renaming, re-typing, or re-parenting resources (#2774) Adds a new resource option `aliases` which can be used to rename a resource. When making a breaking change to the name or type of a resource or component, the old name can be added to the list of `aliases` for a resource to ensure that existing resources will be migrated to the new name instead of being deleted and replaced with the new named resource. There are two key places this change is implemented. The first is the step generator in the engine. When computing whether there is an old version of a registered resource, we now take into account the aliases specified on the registered resource. That is, we first look up the resource by its new URN in the old state, and then by any aliases provided (in order). This can allow the resource to be matched as a (potential) update to an existing resource with a different URN. The second is the core `Resource` constructor in the JavaScript (and soon Python) SDKs. This change ensures that when a parent resource is aliased, that all children implicitly inherit corresponding aliases. It is similar to how many other resource options are "inherited" implicitly from the parent. Four specific scenarios are explicitly tested as part of this PR: 1. Renaming a resource 2. Adopting a resource into a component (as the owner of both component and consumption codebases) 3. Renaming a component instance (as the owner of the consumption codebase without changes to the component) 4. Changing the type of a component (as the owner of the component codebase without changes to the consumption codebase) 4. Combining (1) and (3) to make both changes to a resource at the same time
2019-06-01 06:01:01 +00:00
const res = new MyResource("myres");
const urn = await createUrn("n", "t", res).promise();
assert.strictEqual(urn, "urn:pulumi:mystack::myproject::my:mod:MyResource$t::n");
});
Support aliases for renaming, re-typing, or re-parenting resources (#2774) Adds a new resource option `aliases` which can be used to rename a resource. When making a breaking change to the name or type of a resource or component, the old name can be added to the list of `aliases` for a resource to ensure that existing resources will be migrated to the new name instead of being deleted and replaced with the new named resource. There are two key places this change is implemented. The first is the step generator in the engine. When computing whether there is an old version of a registered resource, we now take into account the aliases specified on the registered resource. That is, we first look up the resource by its new URN in the old state, and then by any aliases provided (in order). This can allow the resource to be matched as a (potential) update to an existing resource with a different URN. The second is the core `Resource` constructor in the JavaScript (and soon Python) SDKs. This change ensures that when a parent resource is aliased, that all children implicitly inherit corresponding aliases. It is similar to how many other resource options are "inherited" implicitly from the parent. Four specific scenarios are explicitly tested as part of this PR: 1. Renaming a resource 2. Adopting a resource into a component (as the owner of both component and consumption codebases) 3. Renaming a component instance (as the owner of the consumption codebase without changes to the component) 4. Changing the type of a component (as the owner of the component codebase without changes to the consumption codebase) 4. Combining (1) and (3) to make both changes to a resource at the same time
2019-06-01 06:01:01 +00:00
it("handles name and type and parent with parent", async () => {
Support aliases for renaming, re-typing, or re-parenting resources (#2774) Adds a new resource option `aliases` which can be used to rename a resource. When making a breaking change to the name or type of a resource or component, the old name can be added to the list of `aliases` for a resource to ensure that existing resources will be migrated to the new name instead of being deleted and replaced with the new named resource. There are two key places this change is implemented. The first is the step generator in the engine. When computing whether there is an old version of a registered resource, we now take into account the aliases specified on the registered resource. That is, we first look up the resource by its new URN in the old state, and then by any aliases provided (in order). This can allow the resource to be matched as a (potential) update to an existing resource with a different URN. The second is the core `Resource` constructor in the JavaScript (and soon Python) SDKs. This change ensures that when a parent resource is aliased, that all children implicitly inherit corresponding aliases. It is similar to how many other resource options are "inherited" implicitly from the parent. Four specific scenarios are explicitly tested as part of this PR: 1. Renaming a resource 2. Adopting a resource into a component (as the owner of both component and consumption codebases) 3. Renaming a component instance (as the owner of the consumption codebase without changes to the component) 4. Changing the type of a component (as the owner of the component codebase without changes to the consumption codebase) 4. Combining (1) and (3) to make both changes to a resource at the same time
2019-06-01 06:01:01 +00:00
const res = new MyParentResource("myres");
const urn = await createUrn("n", "t", res.child).promise();
assert.strictEqual(urn, "urn:pulumi:mystack::myproject::my:mod:MyParentResource$my:mod:MyResource$t::n");
});
});
class TestResource extends ComponentResource {
constructor(name: string, opts?: CustomResourceOptions) {
super("test:resource:type", name, {}, opts);
}
}
describe("allAliases", () => {
before(() => {
runtime._setProject("project");
runtime._setStack("stack");
});
after(() => {
runtime._setProject(undefined);
runtime._setStack(undefined);
});
const testCases = [
{
name: "no aliases",
parentAliases: [],
childAliases: [],
results: [],
},
{
name: "one child alias (type), no parent aliases",
parentAliases: [],
childAliases: [{ type: "test:resource:child2" }],
results: ["urn:pulumi:stack::project::test:resource:type$test:resource:child2::myres-child"],
},
{
name: "one child alias (name), no parent aliases",
parentAliases: [],
childAliases: [{ name: "child2" }],
results: ["urn:pulumi:stack::project::test:resource:type$test:resource:child::child2"],
},
{
name: "one child alias (name), one parent alias (type)",
parentAliases: [{ type: "test:resource:type3" }],
childAliases: [{ name: "myres-child2" }],
results: [
"urn:pulumi:stack::project::test:resource:type$test:resource:child::myres-child2",
"urn:pulumi:stack::project::test:resource:type3$test:resource:child::myres-child",
"urn:pulumi:stack::project::test:resource:type3$test:resource:child::myres-child2",
],
},
{
name: "one child alias (name), one parent alias (name)",
parentAliases: [{ name: "myres2" }],
childAliases: [{ name: "myres-child2" }],
results: [
"urn:pulumi:stack::project::test:resource:type$test:resource:child::myres-child2",
"urn:pulumi:stack::project::test:resource:type$test:resource:child::myres2-child",
"urn:pulumi:stack::project::test:resource:type$test:resource:child::myres2-child2",
],
},
{
name: "two child aliases, three parent aliases",
parentAliases: [{ name: "myres2" }, { type: "test:resource:type3" }, { name: "myres3" }],
childAliases: [{ name: "myres-child2" }, { type: "test:resource:child2" }],
results: [
"urn:pulumi:stack::project::test:resource:type$test:resource:child::myres-child2",
"urn:pulumi:stack::project::test:resource:type$test:resource:child2::myres-child",
"urn:pulumi:stack::project::test:resource:type$test:resource:child::myres2-child",
"urn:pulumi:stack::project::test:resource:type$test:resource:child::myres2-child2",
"urn:pulumi:stack::project::test:resource:type$test:resource:child2::myres2-child",
"urn:pulumi:stack::project::test:resource:type3$test:resource:child::myres-child",
"urn:pulumi:stack::project::test:resource:type3$test:resource:child::myres-child2",
"urn:pulumi:stack::project::test:resource:type3$test:resource:child2::myres-child",
"urn:pulumi:stack::project::test:resource:type$test:resource:child::myres3-child",
"urn:pulumi:stack::project::test:resource:type$test:resource:child::myres3-child2",
"urn:pulumi:stack::project::test:resource:type$test:resource:child2::myres3-child",
],
},
];
for (const testCase of testCases) {
it(testCase.name, async () => {
const res = new TestResource("myres", { aliases: testCase.parentAliases });
const aliases = allAliases(testCase.childAliases, "myres-child", "test:resource:child", res, "myres");
assert.strictEqual(aliases.length, testCase.results.length);
const aliasURNs = await all(aliases).promise();
for (let i = 0; i < aliasURNs.length; i++) {
assert.strictEqual(aliasURNs[i], testCase.results[i]);
}
});
}
});
describe("DependencyProviderResource", () => {
describe("getPackage", () => {
it("returns the expected package", () => {
const res = new DependencyProviderResource(
"urn:pulumi:stack::project::pulumi:providers:aws::default_4_13_0",
);
assert.strictEqual(res.getPackage(), "aws");
});
});
});
[sdk/nodejs] Fix provider for resource methods (#13796) The `Resource` class in the Node.js SDK has the following internal property: ```typescript /** @internal */ readonly __prov?: ProviderResource; ``` When a resource is created, the provider specified for the resource is stored in this property. If it is set, it is passed along in the `Call` request when a method is called on the resource. Prior to #13282, the property was only set for custom resources in `Resource`'s constructor: ```typescript this.__prov = custom ? opts.provider : undefined; ``` With #13282, it was changed to also store the value for remote components: ```diff - this.__prov = custom ? opts.provider : undefined; + this.__prov = custom || remote ? opts.provider : undefined; ``` This regressed the behavior when calling a method on a remote component that had an explicit provider that wasn't the component provider, but some other provider (e.g. AWS provider) specified as: ```typescript const component = new MyRemoteComponent("comp", { }, { provider: awsProvider }); ``` The `awsProvider` was being stored in `Resource.__prov`, and when making the method call on the resource, it would try to invoke `Call` on the AWS provider, rather than calling the remote component provider's `Call`, which resulted in an error. Note that specifying the AWS provider using the more verbose `providers: [awsProvider]` works around the issue. The fix is to only set `__prov` if the provider's package is the same as the resource's package. Otherwise, don't set it, because the user is specifying a provider with the `provider: awsProvider` syntax as shorthand for `providers: [awsProvider]`. Fixes #13777
2023-08-30 14:49:53 +00:00
describe("CustomResource", () => {
runtime.setMocks({
call: (_) => {
throw new Error("unexpected call");
},
newResource: (args) => {
return { id: `${args.name}_id`, state: {} };
},
});
// https://github.com/pulumi/pulumi/issues/13777
it("saves provider with same package as the resource in __prov", async () => {
const provider = new MyProvider("prov");
const custom = new MyCustomResource("custom", { provider: provider });
assert.strictEqual(custom.__prov, provider);
});
// https://github.com/pulumi/pulumi/issues/13777
it("does not save provider with different package as the resource in __prov", async () => {
const provider = new MyOtherProvider("prov");
const custom = new MyCustomResource("custom", { provider: provider });
assert.strictEqual(custom.__prov, undefined);
});
});
describe("ComponentResource", () => {
runtime.setMocks({
call: (_) => {
throw new Error("unexpected call");
},
newResource: (args) => {
return { id: `${args.name}_id`, state: {} };
},
});
// https://github.com/pulumi/pulumi/issues/12161
it("propagates provider to children", async () => {
const provider = new MyProvider("prov");
const component = new MyResource("comp", { provider: provider });
const custom = new MyCustomResource("custom", { parent: component });
assert.strictEqual(custom.__prov, provider);
});
// https://github.com/pulumi/pulumi/issues/12161
it("propagates providers list to children", async () => {
const provider = new MyProvider("prov");
const component = new MyResource("comp", { providers: [provider] });
const custom = new MyCustomResource("custom", { parent: component });
assert.strictEqual(custom.__prov, provider);
});
});
[sdk/nodejs] Fix provider for resource methods (#13796) The `Resource` class in the Node.js SDK has the following internal property: ```typescript /** @internal */ readonly __prov?: ProviderResource; ``` When a resource is created, the provider specified for the resource is stored in this property. If it is set, it is passed along in the `Call` request when a method is called on the resource. Prior to #13282, the property was only set for custom resources in `Resource`'s constructor: ```typescript this.__prov = custom ? opts.provider : undefined; ``` With #13282, it was changed to also store the value for remote components: ```diff - this.__prov = custom ? opts.provider : undefined; + this.__prov = custom || remote ? opts.provider : undefined; ``` This regressed the behavior when calling a method on a remote component that had an explicit provider that wasn't the component provider, but some other provider (e.g. AWS provider) specified as: ```typescript const component = new MyRemoteComponent("comp", { }, { provider: awsProvider }); ``` The `awsProvider` was being stored in `Resource.__prov`, and when making the method call on the resource, it would try to invoke `Call` on the AWS provider, rather than calling the remote component provider's `Call`, which resulted in an error. Note that specifying the AWS provider using the more verbose `providers: [awsProvider]` works around the issue. The fix is to only set `__prov` if the provider's package is the same as the resource's package. Otherwise, don't set it, because the user is specifying a provider with the `provider: awsProvider` syntax as shorthand for `providers: [awsProvider]`. Fixes #13777
2023-08-30 14:49:53 +00:00
describe("RemoteComponentResource", () => {
runtime.setMocks({
call: (_) => {
throw new Error("unexpected call");
},
newResource: (args) => {
return { id: `${args.name}_id`, state: {} };
},
});
// https://github.com/pulumi/pulumi/issues/13777
it("saves provider with same package as the resource in __prov", async () => {
const provider = new MyProvider("prov");
const comp = new MyRemoteComponentResource("comp", { provider: provider });
assert.strictEqual(comp.__prov, provider);
});
// https://github.com/pulumi/pulumi/issues/13777
it("does not save provider with different package as the resource in __prov", async () => {
const provider = new MyOtherProvider("prov");
const comp = new MyRemoteComponentResource("comp", { provider: provider });
assert.strictEqual(comp.__prov, undefined);
});
});
class MyProvider extends ProviderResource {
constructor(name: string) {
super("test", name);
}
}
[sdk/nodejs] Fix provider for resource methods (#13796) The `Resource` class in the Node.js SDK has the following internal property: ```typescript /** @internal */ readonly __prov?: ProviderResource; ``` When a resource is created, the provider specified for the resource is stored in this property. If it is set, it is passed along in the `Call` request when a method is called on the resource. Prior to #13282, the property was only set for custom resources in `Resource`'s constructor: ```typescript this.__prov = custom ? opts.provider : undefined; ``` With #13282, it was changed to also store the value for remote components: ```diff - this.__prov = custom ? opts.provider : undefined; + this.__prov = custom || remote ? opts.provider : undefined; ``` This regressed the behavior when calling a method on a remote component that had an explicit provider that wasn't the component provider, but some other provider (e.g. AWS provider) specified as: ```typescript const component = new MyRemoteComponent("comp", { }, { provider: awsProvider }); ``` The `awsProvider` was being stored in `Resource.__prov`, and when making the method call on the resource, it would try to invoke `Call` on the AWS provider, rather than calling the remote component provider's `Call`, which resulted in an error. Note that specifying the AWS provider using the more verbose `providers: [awsProvider]` works around the issue. The fix is to only set `__prov` if the provider's package is the same as the resource's package. Otherwise, don't set it, because the user is specifying a provider with the `provider: awsProvider` syntax as shorthand for `providers: [awsProvider]`. Fixes #13777
2023-08-30 14:49:53 +00:00
class MyOtherProvider extends ProviderResource {
constructor(name: string) {
super("other", name);
}
}
class MyCustomResource extends CustomResource {
constructor(name: string, opts?: CustomResourceOptions) {
super("test:index:MyCustomResource", name, {}, opts);
}
}
[sdk/nodejs] Fix provider for resource methods (#13796) The `Resource` class in the Node.js SDK has the following internal property: ```typescript /** @internal */ readonly __prov?: ProviderResource; ``` When a resource is created, the provider specified for the resource is stored in this property. If it is set, it is passed along in the `Call` request when a method is called on the resource. Prior to #13282, the property was only set for custom resources in `Resource`'s constructor: ```typescript this.__prov = custom ? opts.provider : undefined; ``` With #13282, it was changed to also store the value for remote components: ```diff - this.__prov = custom ? opts.provider : undefined; + this.__prov = custom || remote ? opts.provider : undefined; ``` This regressed the behavior when calling a method on a remote component that had an explicit provider that wasn't the component provider, but some other provider (e.g. AWS provider) specified as: ```typescript const component = new MyRemoteComponent("comp", { }, { provider: awsProvider }); ``` The `awsProvider` was being stored in `Resource.__prov`, and when making the method call on the resource, it would try to invoke `Call` on the AWS provider, rather than calling the remote component provider's `Call`, which resulted in an error. Note that specifying the AWS provider using the more verbose `providers: [awsProvider]` works around the issue. The fix is to only set `__prov` if the provider's package is the same as the resource's package. Otherwise, don't set it, because the user is specifying a provider with the `provider: awsProvider` syntax as shorthand for `providers: [awsProvider]`. Fixes #13777
2023-08-30 14:49:53 +00:00
class MyRemoteComponentResource extends ComponentResource {
constructor(name: string, opts?: ComponentResourceOptions) {
super("test:index:MyRemoteComponentResource", name, {}, opts, true /*remote*/);
}
}
// Regression test for https://github.com/pulumi/pulumi/issues/12032
describe("parent and dependsOn are the same 12032", () => {
runtime.setMocks({
call: (_) => {
throw new Error("unexpected call");
},
newResource: (args) => {
return { id: `${args.name}_id`, state: {} };
},
});
// https://github.com/pulumi/pulumi/issues/12161
it("runs without error", async () => {
const parent = new ComponentResource("pkg:index:first", "first");
const child = new ComponentResource(
"pkg:index:second",
"second",
{},
{
parent,
dependsOn: parent,
},
);
// This would result in warnings about leaked promises before the fix.
new MyCustomResource("myresource", {
parent: child,
});
});
});