Skip to content
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

spec is missing in output of CustomResource #2890

Open
adriangb opened this issue Mar 17, 2024 · 5 comments
Open

spec is missing in output of CustomResource #2890

adriangb opened this issue Mar 17, 2024 · 5 comments
Labels
area/custom-resources kind/enhancement Improvements or new features

Comments

@adriangb
Copy link

What happened?

I'm unable to access the spec of a custom resource

Example

const cert = new k8s.apiextensions.CustomResource(
  "cert",
  {
    apiVersion: "cert-manager.io/v1",
    kind: "Certificate",
    spec: {
      secretName: "foo-bar",
      dnsNames: ["example.default.svc.cluster.local"],
      issuerRef: { .. },
    },
  }
)

const secretName = cert.spec.secretName // type error!

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).

@adriangb adriangb added kind/bug Some behavior is incorrect or out of spec needs-triage Needs attention from the triage team labels Mar 17, 2024
@mjeffryes
Copy link
Contributor

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?

@mjeffryes mjeffryes added kind/question Questions about existing features awaiting-feedback Blocked on input from the author and removed kind/bug Some behavior is incorrect or out of spec needs-triage Needs attention from the triage team labels Mar 20, 2024
@adriangb
Copy link
Author

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).

@adriangb
Copy link
Author

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?

@mjeffryes
Copy link
Contributor

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.Outputs, but I think it's theoretically possible.)

@mjeffryes mjeffryes added kind/enhancement Improvements or new features area/custom-resources and removed kind/question Questions about existing features awaiting-feedback Blocked on input from the author labels Mar 20, 2024
@adriangb
Copy link
Author

adriangb commented Mar 21, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/custom-resources kind/enhancement Improvements or new features
Projects
None yet
Development

No branches or pull requests

2 participants