Make it possible to get a StackReference output promptly (#2824)
This commit is contained in:
parent
0b4d94a239
commit
11a19a4990
|
@ -2,6 +2,12 @@
|
||||||
|
|
||||||
- Allow setting backend URL explicitly in `Pulumi.yaml` file
|
- Allow setting backend URL explicitly in `Pulumi.yaml` file
|
||||||
|
|
||||||
|
- `StackReference` now has a `.getOutputSync` function to retrieve exported values from an existing
|
||||||
|
stack synchronously. This can be valuable when creating another stack that wants to base
|
||||||
|
flow-control off of the values of an existing stack (i.e. importing the information about all AZs
|
||||||
|
and basing logic off of that in a new stack). Note: this only works for importing values from
|
||||||
|
Stacks that have not exported `secrets`.
|
||||||
|
|
||||||
## 0.17.17 (Released June 12, 2019)
|
## 0.17.17 (Released June 12, 2019)
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
|
|
@ -21,7 +21,8 @@
|
||||||
"source-map-support": "^0.4.16",
|
"source-map-support": "^0.4.16",
|
||||||
"ts-node": "^7.0.0",
|
"ts-node": "^7.0.0",
|
||||||
"typescript": "^3.0.0",
|
"typescript": "^3.0.0",
|
||||||
"upath": "^1.1.0"
|
"upath": "^1.1.0",
|
||||||
|
"deasync": "^0.1.15"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/minimist": "^1.2.0",
|
"@types/minimist": "^1.2.0",
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
"@types/normalize-package-data": "^2.4.0",
|
"@types/normalize-package-data": "^2.4.0",
|
||||||
"@types/read-package-tree": "^5.2.0",
|
"@types/read-package-tree": "^5.2.0",
|
||||||
"@types/semver": "^5.5.0",
|
"@types/semver": "^5.5.0",
|
||||||
|
"@types/deasync": "^0.1.0",
|
||||||
"istanbul": "^0.4.5",
|
"istanbul": "^0.4.5",
|
||||||
"mocha": "^3.5.0",
|
"mocha": "^3.5.0",
|
||||||
"node-gyp": "^3.6.2",
|
"node-gyp": "^3.6.2",
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
import { all, Input, Output, output } from "./output";
|
import { all, Input, Output, output } from "./output";
|
||||||
import { CustomResource, CustomResourceOptions } from "./resource";
|
import { CustomResource, CustomResourceOptions } from "./resource";
|
||||||
|
import { promiseResult } from "./utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages a reference to a Pulumi stack. The referenced stack's outputs are available via the
|
* Manages a reference to a Pulumi stack. The referenced stack's outputs are available via the
|
||||||
|
@ -56,6 +57,25 @@ export class StackReference extends CustomResource {
|
||||||
public getOutput(name: Input<string>): Output<any> {
|
public getOutput(name: Input<string>): Output<any> {
|
||||||
return all([output(name), this.outputs]).apply(([n, os]) => os[n]);
|
return all([output(name), this.outputs]).apply(([n, os]) => os[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the value promptly of the named stack output. May return undefined if the value is
|
||||||
|
* not known for some reason.
|
||||||
|
*
|
||||||
|
* This operation is not supported (and will throw) if any exported values of the StackReference
|
||||||
|
* are secrets.
|
||||||
|
*
|
||||||
|
* @param name The name of the stack output to fetch.
|
||||||
|
*/
|
||||||
|
public getOutputSync(name: string): any {
|
||||||
|
const out = this.getOutput(name);
|
||||||
|
const isSecret = promiseResult(out.isSecret);
|
||||||
|
if (isSecret) {
|
||||||
|
throw new Error("Cannot call [getOutputSync] if the referenced stack has secret outputs. Use [getOutput] instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return promiseResult(out.promise());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
import * as deasync from "deasync";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common code for doing RTTI typechecks. RTTI is done by having a boolean property on an object
|
* Common code for doing RTTI typechecks. RTTI is done by having a boolean property on an object
|
||||||
* with a special name (like "__resource" or "__asset"). This function checks that the object
|
* with a special name (like "__resource" or "__asset"). This function checks that the object
|
||||||
|
@ -39,3 +41,42 @@ export function hasTrueBooleanMember(obj: any, memberName: string | number | sym
|
||||||
|
|
||||||
return val === true;
|
return val === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronously blocks until the result of this promise is computed. If the promise is rejected,
|
||||||
|
* this will throw the error the promise was rejected with. If this promise does not complete this
|
||||||
|
* will block indefinitely.
|
||||||
|
*
|
||||||
|
* Be very careful with this function. Only wait on a promise if you are certain it is safe to do
|
||||||
|
* so.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function promiseResult<T>(promise: Promise<T>): T {
|
||||||
|
enum State {
|
||||||
|
running,
|
||||||
|
finishedSuccessfully,
|
||||||
|
finishedWithError,
|
||||||
|
}
|
||||||
|
|
||||||
|
let result: T;
|
||||||
|
let error = undefined;
|
||||||
|
let state = <State>State.running;
|
||||||
|
|
||||||
|
promise.then(
|
||||||
|
val => {
|
||||||
|
result = val;
|
||||||
|
state = State.finishedSuccessfully;
|
||||||
|
},
|
||||||
|
err => {
|
||||||
|
error = err;
|
||||||
|
state = State.finishedWithError;
|
||||||
|
});
|
||||||
|
|
||||||
|
deasync.loopWhile(() => state === State.running);
|
||||||
|
if (state === State.finishedWithError) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result!;
|
||||||
|
}
|
||||||
|
|
|
@ -891,6 +891,16 @@ func TestStackReferenceNodeJS(t *testing.T) {
|
||||||
Config: map[string]string{
|
Config: map[string]string{
|
||||||
"org": os.Getenv("PULUMI_TEST_OWNER"),
|
"org": os.Getenv("PULUMI_TEST_OWNER"),
|
||||||
},
|
},
|
||||||
|
EditDirs: []integration.EditDir{
|
||||||
|
{
|
||||||
|
Dir: "step1",
|
||||||
|
Additive: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Dir: "step2",
|
||||||
|
Additive: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
integration.ProgramTest(t, opts)
|
integration.ProgramTest(t, opts)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,3 +6,5 @@ let config = new pulumi.Config();
|
||||||
let org = config.require("org");
|
let org = config.require("org");
|
||||||
let slug = `${org}/${pulumi.getProject()}/${pulumi.getStack()}`;
|
let slug = `${org}/${pulumi.getProject()}/${pulumi.getStack()}`;
|
||||||
let a = new pulumi.StackReference(slug);
|
let a = new pulumi.StackReference(slug);
|
||||||
|
|
||||||
|
export const val = ["a", "b"];
|
15
tests/integration/stack_reference/step1/index.ts
Normal file
15
tests/integration/stack_reference/step1/index.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2016-2018, Pulumi Corporation. All rights reserved.
|
||||||
|
|
||||||
|
import * as pulumi from "@pulumi/pulumi";
|
||||||
|
|
||||||
|
let config = new pulumi.Config();
|
||||||
|
let org = config.require("org");
|
||||||
|
let slug = `${org}/${pulumi.getProject()}/${pulumi.getStack()}`;
|
||||||
|
let a = new pulumi.StackReference(slug);
|
||||||
|
|
||||||
|
const oldVal: string[] = a.getOutputSync("val");
|
||||||
|
if (oldVal.length !== 2 || oldVal[0] !== "a" || oldVal[1] !== "b") {
|
||||||
|
throw new Error("Invalid result");
|
||||||
|
}
|
||||||
|
|
||||||
|
export const val2 = pulumi.secret(["a", "b"]);
|
22
tests/integration/stack_reference/step2/index.ts
Normal file
22
tests/integration/stack_reference/step2/index.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// Copyright 2016-2018, Pulumi Corporation. All rights reserved.
|
||||||
|
|
||||||
|
import * as pulumi from "@pulumi/pulumi";
|
||||||
|
|
||||||
|
let config = new pulumi.Config();
|
||||||
|
let org = config.require("org");
|
||||||
|
let slug = `${org}/${pulumi.getProject()}/${pulumi.getStack()}`;
|
||||||
|
let a = new pulumi.StackReference(slug);
|
||||||
|
|
||||||
|
let gotError = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
a.getOutputSync("val2");
|
||||||
|
}
|
||||||
|
catch (err)
|
||||||
|
{
|
||||||
|
gotError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gotError) {
|
||||||
|
throw new Error("Expected to get error trying to read secret from stack reference.");
|
||||||
|
}
|
Loading…
Reference in a new issue