-
Notifications
You must be signed in to change notification settings - Fork 209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Typescript: dynamic.Resource outputs are not available if defined on Resource class #11639
Comments
I think this is a limitation of TypeScript, that's not been well documented. The code line So the TypeScript SDK can't use property reflection to work out what fields to set because just declaring them doesn't make a field, so instead it works out the output fields to set based on the input properties it gets given. If you look at any of the codegen'd sdks you'll see a lot of If writing dynamic providers you need to copy that style of passing in input properties. I'll move this over to the docs repo that we should update the examples at https://www.pulumi.com/docs/intro/concepts/resources/dynamic-providers/#dynamic-resource-outputs |
class Test {
public readonly password!: string;
}
const test = new Test();
console.log(test.hasOwnProperty('password')); // true
console.log(test); // Test { password: undefined } So I'm confused about what the issue actually is. EDIT : Also, a resource can have an output field that is not in the input. So how do you populate that ? |
Huh interesting. If that's the case we can probably simplify codegen for custom resources as well. |
@Frassle I’m very happy for you, but that doesn’t solve the issue 😅 : the resource properties are not populated with previous output |
Hah my thought was if that's true we can simplify codegen and fix this to work with those annotated properties as well. At which point the above just works. If you need to work with problem of outputs that don't have inputs today, the current codegen just fills in the props dictionary with undefined. e.g. https://github.com/pulumi/pulumi-aws/blob/master/sdk/nodejs/acm/certificate.ts#L321 |
Now I'm very confused. The code you pointed assign default values to the Does the resource actually receive a merge of inputs & outputs as second parameter during an update ? That's what it looks like when I read https://github.com/pulumi/pulumi-aws/blob/master/sdk/nodejs/acm/certificate.ts#L321 const botUsername = "robotsatan";
const botPassword = new HashedPasswordResource("robotsatan-password", { length: 30 });
botPassword.password.apply(pwd => {
console.log(pwd); // undefined during 'deployment time', create or update lifecycle
}); |
You can. The nodesdk just has this oddity of needing to also set the outputs so that the runtime knows what fields to deserialise to in the response. You don't need actual values for them, I'd guess this is because |
If anyone is still interested, I fixed it by using import * as pulumi from "@pulumi/pulumi";
import { strict as assert } from "node:assert";
import * as crypto from "node:crypto";
const _hashedPasswordProvider: pulumi.dynamic.ResourceProvider = {
async create (inputs: {length: number}) {
const password = "dummy";
const hashedPassword = "my-super-pass-hashed-with-unique-salt";
return { id: crypto.randomUUID(), outs: { password, hashedPassword } };
}
};
class HashedPasswordResource extends pulumi.dynamic.Resource {
declare readonly password: pulumi.Output<string>;
declare readonly hashedPassword: pulumi.Output<string>;
constructor (name: string, props: {length: pulumi.Input<number>}, opts?: pulumi.CustomResourceOptions) {
const innerOpts = pulumi.mergeOptions(opts, { additionalSecretOutputs: ["password"] });
const innerProps = {password: undefined, hashedPassword: undefined, ...props};
super(_hashedPasswordProvider, name, innerProps, innerOpts);
}
}
function main() {
const botUsername = "robotsatan";
const botPassword = new HashedPasswordResource("robotsatan-password", { length: 30 });
// now passes
assert.notEqual(botPassword.password, undefined);
assert.notEqual(botPassword.hashedPassword, undefined);
} Found this out after commenting out the property definitions then worked backwards to find a way to make them visible to TypeScript. Would be nice if the docs were updated to reflect this. |
What happened?
I tried to follow the docs to create a custom resource (to generate a password and its hash), but the outputs are always
undefined
. I figured out that this is a bug caused by the class member definitions, as removing them make it work.Expected Behavior
It should have worked on the first try. I closely followed https://www.pulumi.com/docs/intro/concepts/resources/dynamic-providers/#dynamic-resource-outputs.
Steps to reproduce
Original code:
Diff to make it work:
Output of
pulumi about
my package-lock.json says I have
node_modules/@pulumi/pulumi
version": "3.54.0",
Additional context
Shout-out to the poor souls @ pulumi/pulumi#2931
Contributing
Vote on this issue by adding a 👍 reaction.
To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).
EDIT
Ok, this stuff is VERY freaking unstable.
I changed my resource to return
Buffer.from(hash).toString('base64');
instead ofhash
=> it started returningundefined
again until I renamed my resource !The text was updated successfully, but these errors were encountered: