Open adriangb opened 5 months ago
Thanks @adriangb; yes, while the CustomResource
resource type accepts arbitrary input fields, only the apiVersion
kind
and metadata
input properties are copied to the output.
You could potentially work around this limitation by just using the values you passed as inputs?
It seems like at runtime the input data is copied. I used a @ts-ignore
(I’m guessing as any
) would work as well.
The problem with using the input values directly is that you need to then add dependsOn
and also reference the CustomResource anywhere you want to use the value (and need the CustomResource to be created).
I’m no typescript expert, but could you make the input generic (requiring the apiVersion and kind keys via an interface or similar) so that the input data is type safe available in the output?
Glad that workaround worked for you. I did some digging on whether we can make the typing better here, and it seems we're a little hamstrung by the fact that CustomResource
is a class. It's possible in ts to define a type that copies field names from some other type:
type Copy<Type> = {
[Property in keyof Type]: Type[Property];
};
So you could imagine doing something like:
type CustomResourceOutputs<T> = {
readonly [K in keyof T]: pulumi.Output<any>;
}
export declare class CustomResource<T> extends pulumi.CustomResource implements CustomResourceOutputs<T> {
...
}
but that blows up because "A class can only implement an object type or intersection of object types with statically known members."
FWIW mapped types syntax is not supported directly on the class either:
export declare class CustomResource<T> extends pulumi.CustomResource {
readonly [K in keyof T]: pulumi.Output<any>;
...
}
(yields lots of syntax errors)
So while we could create a function that does ~ the same work as the constructor for CustomeResource
where the fields on output type would reflect the fields on input type, but we can't coerce the type of the class itself to vary based on the inputs.
Probably the best we could do is a wrapper for the type coercion like this:
type CustomResourceOutputs<T> = {
readonly [K in keyof T]: pulumi.Output<T[K]>;
} & CustomResource
function wrapper<T extends CustomResourceArgs>(name: string, args: T, opts?: pulumi.CustomResourceOptions): CustomResourceOutputs<T> {
return new CustomResource(name, args, opts) as CustomResourceOutputs<T>
}
const out = wrapper("foo", {
apiVersion : "1",
kind : "foo",
spec: {
bar: "baz"
}
})
const spec: pulumi.Output<{bar: string}> = out.spec
(There's still some gotchas to work out when some of the input parameters are already pulumi.Output
s, but I think it's theoretically possible.)
Could you put the input into CustomResource.input
but just mark it as Output<InputT>
? That way it can be references and the reference works with pulumi’s DAG
What happened?
I'm unable to access the
spec
of a custom resourceExample
Output of
pulumi about
❯ pulumi about
CLI
Version 3.111.0 Go Version go1.22.1 Go Compiler gc
Plugins NAME VERSION cloudflare 5.21.0 gcp 7.11.0 google-native 0.32.0 kubernetes 4.8.0 nodejs unknown random 4.15.1 tls 5.0.1
Host
OS darwin Version 14.3.1 Arch arm64
Dependencies: NAME VERSION @pulumi/cloudflare v5.21.0 @pulumi/kubernetes v4.8.0 @pulumi/tls v5.0.1 prettier 3.2.5 @pulumi/google-native v0.32.0 @pulumi/pulumi 3.107.0 eslint-plugin-simple-import-sort 10.0.0 eslint 8.56.0 typescript 5.3.3 @pulumi/gcp v7.11.0 @typescript-eslint/eslint-plugin 6.21.0 @typescript-eslint/parser 6.21.0 eslint-config-prettier 9.1.0 eslint-config-standard 17.1.0 @pulumi/random v4.15.1 @types/node 20.11.20
Additional context
https://pulumi-community.slack.com/archives/CRFURDVQB/p1710688887460189
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).