pulumi/sdk/nodejs/runtime/mocks.ts

276 lines
9.1 KiB
TypeScript
Raw Permalink Normal View History

// 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.
import { deserializeProperties, serializeProperties } from "./rpc";
import { getProject, getStack, setMockOptions } from "./settings";
Move nodejs feature checks to startup (#14856) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> We need to synchronously check for transform support in `registerStackTransformation` and resource constructors when adding remote transform support to node (c.f. https://github.com/pulumi/pulumi/pull/14303). This change changes all the feature checks to be done at startup and then accessed via just a field lookup. Adding the "transform" feature to this set is clearly simple. Sadly there's no single entry point to make these changes in. So we need to update entry point of construct/call, the entry point of programs, and test setup. Miss any one of these and current tests start failing. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [x] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2023-12-19 14:35:23 +00:00
import { getStore } from "./state";
import * as structproto from "google-protobuf/google/protobuf/struct_pb";
import * as provproto from "../proto/provider_pb";
import * as resproto from "../proto/resource_pb";
/**
* {@link MockResourceArgs} is used to construct a new resource mock.
*/
export interface MockResourceArgs {
/**
* The token that indicates which resource type is being constructed. This
* token is of the form "package:module:type".
*/
type: string;
/**
* The logical name of the resource instance.
*/
name: string;
/**
* The inputs for the resource.
*/
inputs: any;
/**
* If provided, the identifier of the provider instance being used to manage
* this resource.
*/
provider?: string;
/**
* Specifies whether or not the resource is Custom (i.e. managed by a
* resource provider).
*/
custom?: boolean;
/**
* If provided, the physical identifier of an existing resource to read or
* import.
*/
id?: string;
}
2023-06-01 11:54:55 +00:00
/**
* {@link MockResourceResult} is the result of a new resource mock, returning a
* physical identifier and the output properties for the resource being
* constructed.
2023-06-01 11:54:55 +00:00
*/
export type MockResourceResult = {
id: string | undefined;
state: Record<string, any>;
};
/**
* {@link MockResourceArgs} is used to construct call mocks.
*/
export interface MockCallArgs {
/**
* The token that indicates which function is being called. This token is of
* the form "package:module:function".
*/
token: string;
/**
* The arguments provided to the function call.
*/
inputs: any;
/**
* If provided, the identifier of the provider instance being used to make
* the call.
*/
provider?: string;
}
/**
* {@link MockCallResult} is the result of a call mock.
2023-06-01 11:54:55 +00:00
*/
export type MockCallResult = Record<string, any>;
/**
* {@link Mocks} allows implementations to replace operations normally
* implemented by the Pulumi engine with their own implementations. This can be
* used during testing to ensure that calls to provider functions and resource
* constructors return predictable values.
*/
export interface Mocks {
2023-06-01 12:49:11 +00:00
/**
* Mocks provider-implemented function calls (e.g. `aws.get_availability_zones`).
2023-06-01 12:49:11 +00:00
*
* @param args MockCallArgs
2023-06-01 12:49:11 +00:00
*/
2023-06-01 11:54:55 +00:00
call(args: MockCallArgs): MockCallResult | Promise<MockCallResult>;
2023-06-01 12:49:11 +00:00
/**
* Mocks resource construction calls. This function should return the
* physical identifier and the output properties for the resource being
* constructed.
2023-06-01 12:49:11 +00:00
*
* @param args MockResourceArgs
2023-06-01 12:49:11 +00:00
*/
2023-06-01 11:54:55 +00:00
newResource(args: MockResourceArgs): MockResourceResult | Promise<MockResourceResult>;
}
export class MockMonitor {
readonly resources = new Map<string, { urn: string; id: string | null; state: any }>();
constructor(readonly mocks: Mocks) {}
private newUrn(parent: string, type: string, name: string): string {
if (parent) {
const qualifiedType = parent.split("::")[2];
const parentType = qualifiedType.split("$").pop();
type = parentType + "$" + type;
}
return "urn:pulumi:" + [getStack(), getProject(), type, name].join("::");
}
public async invoke(req: any, callback: (err: any, innerResponse: any) => void) {
try {
const tok = req.getTok();
const inputs = deserializeProperties(req.getArgs());
if (tok === "pulumi:pulumi:getResource") {
const registeredResource = this.resources.get(inputs.urn);
if (!registeredResource) {
throw new Error(`unknown resource ${inputs.urn}`);
}
const resp = new provproto.InvokeResponse();
resp.setReturn(structproto.Struct.fromJavaScript(registeredResource));
callback(null, resp);
return;
}
2023-06-01 11:54:55 +00:00
const result: MockCallResult = await this.mocks.call({
token: tok,
inputs: inputs,
provider: req.getProvider(),
});
const response = new provproto.InvokeResponse();
response.setReturn(structproto.Struct.fromJavaScript(await serializeProperties("", result)));
callback(null, response);
} catch (err) {
callback(err, undefined);
}
}
public async readResource(req: any, callback: (err: any, innterResponse: any) => void) {
try {
2023-06-01 11:54:55 +00:00
const result: MockResourceResult = await this.mocks.newResource({
type: req.getType(),
name: req.getName(),
inputs: deserializeProperties(req.getProperties()),
provider: req.getProvider(),
custom: true,
id: req.getId(),
});
const urn = this.newUrn(req.getParent(), req.getType(), req.getName());
const serializedState = await serializeProperties("", result.state);
this.resources.set(urn, { urn, id: result.id ?? null, state: serializedState });
const response = new resproto.ReadResourceResponse();
response.setUrn(urn);
response.setProperties(structproto.Struct.fromJavaScript(serializedState));
callback(null, response);
} catch (err) {
callback(err, undefined);
}
}
public async registerResource(req: any, callback: (err: any, innerResponse: any) => void) {
try {
2023-06-01 11:54:55 +00:00
const result: MockResourceResult = await this.mocks.newResource({
type: req.getType(),
name: req.getName(),
inputs: deserializeProperties(req.getObject()),
provider: req.getProvider(),
custom: req.getCustom(),
id: req.getImportid(),
});
const urn = this.newUrn(req.getParent(), req.getType(), req.getName());
const serializedState = await serializeProperties("", result.state);
this.resources.set(urn, { urn, id: result.id ?? null, state: serializedState });
const response = new resproto.RegisterResourceResponse();
response.setUrn(urn);
response.setId(result.id || "");
response.setObject(structproto.Struct.fromJavaScript(serializedState));
callback(null, response);
} catch (err) {
callback(err, undefined);
}
}
public registerResourceOutputs(req: any, callback: (err: any, innerResponse: any) => void) {
try {
const registeredResource = this.resources.get(req.getUrn());
if (!registeredResource) {
throw new Error(`unknown resource ${req.getUrn()}`);
}
registeredResource.state = req.getOutputs();
callback(null, {});
} catch (err) {
callback(err, undefined);
}
}
public supportsFeature(req: any, callback: (err: any, innerResponse: any) => void) {
const id = req.getId();
// Support for "outputValues" is deliberately disabled for the mock monitor so
// instances of `Output` don't show up in `MockResourceArgs` inputs.
fix MockMonitor reporting DeletedWith wasn't supported (#14118) We should support all features in mocks that we are supporting otherwise. We did a similar thing in pulumi-dotnet: https://github.com/pulumi/pulumi-dotnet/pull/93. However here we're not simply changing hasSupport to true. https://github.com/pulumi/pulumi/commit/1e09626bc731ad2379d646b0b3b46036e8a7661e has a good explanation of why we only support specific values here. However really we only need to disable support for `outputValues`, and that only if output values are disabled. Originally this was true if `PULUMI_ENABLE_OUTPUT_VALUES` was set, but that environment variable was later inverted: 3027d01f259d304abb764a0e8793ed2996cede56. This ended up being a little bit more complicated than just passing true, but I think it's more correct this way. I'm also happy to change it back to just passing through `true` if that's preferred. Once we decided on whether this is the right way to do it vs. just passing `true` unconditionally I'll also update `java` and `dotnet` (if we're going this way) to do the same. Fixes #13355 ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [x] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2023-10-09 14:21:54 +00:00
const hasSupport = id !== "outputValues";
callback(null, {
getHassupport: () => hasSupport,
});
}
}
/**
* Configures the Pulumi runtime to use the given mocks for testing.
*
* @param mocks
* The mocks to use for calls to provider functions and resource construction.
* @param project
* If provided, the name of the Pulumi project. Defaults to "project".
* @param stack
* If provided, the name of the Pulumi stack. Defaults to "stack".
* @param preview
* If provided, indicates whether or not the program is running a preview. Defaults to false.
* @param organization
* If provided, the name of the Pulumi organization. Defaults to nothing.
*/
Move nodejs feature checks to startup (#14856) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> We need to synchronously check for transform support in `registerStackTransformation` and resource constructors when adding remote transform support to node (c.f. https://github.com/pulumi/pulumi/pull/14303). This change changes all the feature checks to be done at startup and then accessed via just a field lookup. Adding the "transform" feature to this set is clearly simple. Sadly there's no single entry point to make these changes in. So we need to update entry point of construct/call, the entry point of programs, and test setup. Miss any one of these and current tests start failing. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [x] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2023-12-19 14:35:23 +00:00
export async function setMocks(
mocks: Mocks,
project?: string,
stack?: string,
preview?: boolean,
organization?: string,
) {
setMockOptions(new MockMonitor(mocks), project, stack, preview, organization);
Move nodejs feature checks to startup (#14856) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> We need to synchronously check for transform support in `registerStackTransformation` and resource constructors when adding remote transform support to node (c.f. https://github.com/pulumi/pulumi/pull/14303). This change changes all the feature checks to be done at startup and then accessed via just a field lookup. Adding the "transform" feature to this set is clearly simple. Sadly there's no single entry point to make these changes in. So we need to update entry point of construct/call, the entry point of programs, and test setup. Miss any one of these and current tests start failing. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [x] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2023-12-19 14:35:23 +00:00
// Mocks enable all features except outputValues.
const store = getStore();
store.supportsSecrets = true;
store.supportsResourceReferences = true;
store.supportsOutputValues = false;
store.supportsDeletedWith = true;
store.supportsAliasSpecs = true;
NodeJS transforms (#15532) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> This adds a new experimental feature to the NodeJS SDK to register remote transform functions. These are currently all prefixed 'X' to show they're experimental. These transform functions will run even for resources created inside MLCs. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [x] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [x] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [x] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-03-07 08:52:34 +00:00
store.supportsTransforms = false;
}