pulumi/tests/integration/transformations/nodejs/simple/index.ts

136 lines
5.0 KiB
TypeScript

// Copyright 2016-2018, Pulumi Corporation. All rights reserved.
import * as pulumi from "@pulumi/pulumi";
import { Random } from "./random";
class MyComponent extends pulumi.ComponentResource {
child: Random;
constructor(name: string, opts?: pulumi.ComponentResourceOptions) {
super("my:component:MyComponent", name, {}, opts);
this.child = new Random(`${name}-child`, { length: 5 }, {
parent: this,
additionalSecretOutputs: ["length"],
});
this.registerOutputs({});
}
}
// Scenario #1 - apply a transformation to a CustomResource
const res1 = new Random("res1", { length: 5 }, {
transformations: [
({ props, opts }) => {
console.log("res1 transformation");
return {
props: props,
opts: pulumi.mergeOptions(opts, { additionalSecretOutputs: ["result"] }),
};
},
],
});
// Scenario #2 - apply a transformation to a Component to transform it's children
const res2 = new MyComponent("res2", {
transformations: [
({ type, props, opts }) => {
console.log("res2 transformation");
if (type === "testprovider:index:Random") {
return {
props: { prefix: "newDefault", ...props },
opts: pulumi.mergeOptions(opts, { additionalSecretOutputs: ["result"] }),
};
}
},
],
});
// Scenario #3 - apply a transformation to the Stack to transform all (future) resources in the stack
pulumi.runtime.registerStackTransformation(({ type, props, opts }) => {
console.log("stack transformation");
if (type === "testprovider:index:Random") {
return {
props: { ...props, prefix: "stackDefault" },
opts: pulumi.mergeOptions(opts, { additionalSecretOutputs: ["result"] }),
};
}
});
const res3 = new Random("res3", { length: 5 });
// Scenario #4 - transformations are applied in order of decreasing specificity
// 1. (not in this example) Child transformation
// 2. First parent transformation
// 3. Second parent transformation
// 4. Stack transformation
const res4 = new MyComponent("res4", {
transformations: [
({ type, props, opts }) => {
console.log("res4 transformation");
if (type === "testprovider:index:Random") {
return {
props: { ...props, prefix: "default1" },
opts,
};
}
},
({ type, props, opts }) => {
console.log("res4 transformation 2");
if (type === "testprovider:index:Random") {
return {
props: { ...props, prefix: "default2" },
opts,
};
}
},
],
});
// Scenario #5 - cross-resource transformations that inject dependencies on one resource into another.
class MyOtherComponent extends pulumi.ComponentResource {
child1: Random;
child2: Random;
constructor(name: string, opts?: pulumi.ComponentResourceOptions) {
super("my:component:MyOtherComponent", name, {}, opts);
this.child1 = new Random(`${name}-child1`, { length: 5 }, { parent: this });
this.child2 = new Random(`${name}-child2`, { length: 5 }, { parent: this });
this.registerOutputs({});
}
}
const transformChild1DependsOnChild2: pulumi.ResourceTransformation = (() => {
console.log("res5 transformation")
// Create a promise that wil be resolved once we find child2. This is needed because we do not
// know what order we will see the resource registrations of child1 and child2.
let child2Found: (res: pulumi.Resource) => void;
const child2 = new Promise<pulumi.Resource>((res) => child2Found = res);
// Return a transformation which will rewrite child1 to depend on the promise for child2, and
// will resolve that promise when it finds child2.
return (args: pulumi.ResourceTransformationArgs) => {
if (args.name.endsWith("-child2")) {
// Resolve the child2 promise with the child2 resource.
child2Found(args.resource);
return undefined;
} else if (args.name.endsWith("-child1")) {
// Overwrite the `prefix` to child2 with a dependency on the `length` from child1.
const child2Result = pulumi.output(args.props["length"]).apply(async (input) => {
if (input !== 5) {
// Not strictly necessary - but shows we can confirm invariants we expect to be
// true.
throw new Error("unexpected input value");
}
return child2.then(c2Res => c2Res["result"]);
});
// Finally - overwrite the input of child2.
return {
props: { ...args.props, prefix: child2Result },
opts: args.opts,
};
}
};
})();
const res5 = new MyOtherComponent("res5", {
transformations: [ transformChild1DependsOnChild2 ],
});