pulumi / pulumi-eks

A Pulumi component for easily creating and managing an Amazon EKS Cluster
https://www.pulumi.com/registry/packages/eks/
Apache License 2.0
169 stars 78 forks source link

Document the issue with rehydrating Cluster resource #830

Open MMartyn opened 1 year ago

MMartyn commented 1 year ago

What happened?

I spent several days trying to figure out why passing a eks.Cluster into a custom component wasn't working and it seems that this is a known (undocumented) issue.

Steps to reproduce

Try creating a new component and passing a eks.Cluster into it and try using something like endpoint.

Expected Behavior

I expected that I would be able to pass a cluster into a custom component and make use of it.

Actual Behavior

Didn't work.

Output of pulumi about

No response

Additional context

No response

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

lblackstone commented 1 year ago

@justinvp Do you know of any reason eks.Cluster wouldn't work in a ComponentResource? I'm not sure the code comment indicates that.

@MMartyn Could you provide more information about the languages and plugin versions that you're using?

justinvp commented 1 year ago

@MMartyn, is your custom component in a component package or is it a component for a single language? It sounds like a component in a component package, implemented in TypeScript. Is that correct?

justinvp commented 1 year ago

@MMartyn, I see from #829 you're using Go. Can you provide a snippet of what your component is doing and how it's trying to access the eks.Cluster?

MMartyn commented 1 year ago

I am creating a component package in Typescript and then consuming it via GO. The component written in Typescript is what is getting the eks.Cluster and not hydrating correctly. More info in the #contributor channel in slack.

justinvp commented 1 year ago

Thanks for the extra information and sorry for the trouble. This issue is largely due to the fact that we're not currently generating a Node.js SDK for EKS from the schema: https://github.com/pulumi/pulumi-eks/issues/603. The Node.js SDK in 1.0 is still the same API surface it's always had from when this was originally a Node.js-only library.

Had we taken the breaking change for 1.0 to make @pulumi/eks be the schema-generated SDK, then all this would have worked for you out-of-the-box. But since we didn't do that, and you're trying to implement your own component package in TypeScript, it'll take a little bit of work to make this work.

You'll basically have to use the same technique that we're using internally.

In your component package's schema, for your component's input properties, still reference the Cluster with:

"cluster": {
    "$ref": "/eks/v1.0.0/schema.json#/resources/eks:index:Cluster",
    "plain": true
}

But inside your TypeScript implementation, you'll need to use an internal stand-in version of Cluster, similar to our ClusterInternal:

export interface ComponentArgs {
    cluster: InternalCluster;
}

export class Component extends pulumi.ComponentResource {
    ...
}

export class ClusterInternal extends pulumi.ComponentResource {
    public readonly clusterSecurityGroup!: pulumi.Output<aws.ec2.SecurityGroup>;
    public readonly core!: pulumi.Output<pulumi.Unwrap<eks.CoreData>>;
    public readonly defaultNodeGroup!: pulumi.Output<pulumi.Unwrap<eks.NodeGroupData> | undefined>;
    public readonly eksCluster!: pulumi.Output<aws.eks.Cluster>;
    public readonly eksClusterIngressRule!: pulumi.Output<aws.ec2.SecurityGroupRule>;
    public readonly instanceRoles!: pulumi.Output<aws.iam.Role[]>;
    public readonly kubeconfig!: pulumi.Output<any>;
    public readonly kubeconfigJson!: pulumi.Output<string>;
    public readonly nodeSecurityGroup!: pulumi.Output<aws.ec2.SecurityGroup>;

    constructor(name: string, opts: pulumi.ComponentResourceOptions) {
        if (!opts.urn) {
            throw new Error("This component is only meant to be rehydrated from a resource reference.");
        }
        const props = {
            clusterSecurityGroup: undefined,
            core: undefined,
            defaultNodeGroup: undefined,
            eksCluster: undefined,
            eksClusterIngressRule: undefined,
            instanceRoles: undefined,
            kubeconfig: undefined,
            kubeconfigJson: undefined,
            nodeSecurityGroup: undefined,
        };
        super("eks:index:Cluster", name, props, opts);
    }
}

// This is needed so the deserializer will instantiate an instance of your `ClusterInternal` when it gets a resource reference for `eks:index:Cluster`.
pulumi.runtime.registerResourceModule("eks", "index", {
    version: "1.0.0",
    construct: (name: string, type: string, urn: string): pulumi.Resource => {
        switch (type) {
            case "eks:index:Cluster":
                return new ClusterInternal(name, { urn })
            default:
                throw new Error(`unknown resource type ${type}`);
        }
    },
});

We're likely going to be following-up soon with a 2.0 release that switches the @pulumi/eks Node.js SDK over to using the schema-generated SDK. When that happens, you can delete all this internal workaround code and rely on the public eks.Cluster component.

MMartyn commented 1 year ago

Thanks @justinvp, that got me passed my first hurdle. Now I am hitting an issue trying to use args.cluster.eksCluster.name is there a trick to getting that to properly rehydrate? I tried changing eksCluster to be public readonly eksCluster!: pulumi.Output<pulumi.Unwrap<aws.eks.Cluster>>; but that didn't seem to work.