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

adds instanceProfileName field to nodegroups #1496

Merged
merged 12 commits into from
Nov 25, 2024

Conversation

jdavredbeard
Copy link
Contributor

@jdavredbeard jdavredbeard commented Nov 18, 2024

Proposed changes

Add instanceProfileName as an Input<string> field to NodeGroup and NodeGroupV2. This would unblock pulumi/pulumi-self-hosted-installers#181 by creating a path for users to create an InstanceProfile in a separate stack from the NodeGroup and pass the instance profile's name by stack reference. Currently pulumi/pulumi#17515, prevents NodeGroup components from accepting InstanceProfile values created in another stack and provided to the NodeGroup's stack by aws.iam.InstanceProfile.get(), and the instanceProfile parameter cannot accept an InstanceProfile resource passed by stack reference because the instanceProfile parameter is a plain InstanceProfile type, not an Input<InstanceProfile>.

Related issues (optional)

Closes #1497

Copy link

Does the PR have any schema changes?

Looking good! No breaking changes found.
No new resources/functions.

@jdavredbeard jdavredbeard marked this pull request as draft November 18, 2024 15:15
@jdavredbeard jdavredbeard marked this pull request as ready for review November 19, 2024 14:39
Copy link
Contributor

@flostadler flostadler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments. Love the unit tests! But it would be great if we could add an integration test for this as well.

nodejs/eks/cluster.ts Show resolved Hide resolved
@@ -652,19 +653,54 @@ export function createNodeGroup(
return createNodeGroupInternal(name, args, pulumi.output(core), parent, provider);
}

export function resolveOrGetInstanceProfile(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add function docs explaining what this function is exactly doing and when it's throwing errors. Thanks!

nodejs/eks/nodegroup.ts Show resolved Hide resolved
@@ -4,28 +4,28 @@

"@ampproject/remapping@^2.2.0":
version "2.3.0"
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These seem to be unrelated changes

if (args.instanceProfile || c.nodeGroupOptions.instanceProfile) {
return args.instanceProfile ?? c.nodeGroupOptions.instanceProfile!;
}
return aws.iam.InstanceProfile.get(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think pulling in the resource with the .get function would incur RUM costs. We circumvent this by using the data source instead.

It seems like we're only interested in the ARN, right? Instance Profile ARNs follow this format: arn:aws:iam::<account-id>:instance-profile/<profile-name>.
If we know the name we can construct it without having to load the resource.

In that case we need other props, we could use iam.getInstanceProfileOutput instead.

},
"instanceProfileName": {
TypeSpec: schema.TypeSpec{Type: "string"},
Description: "The name of the IAM InstanceProfile to use on the NodeGroup.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should point out here that instanceProfile and instanceProfileName is mutually exclusive.

name: string,
args: Omit<NodeGroupOptions, "cluster">,
c: pulumi.UnwrappedObject<CoreData>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you have to make this change?

resolveOrGetInstanceProfile(name, args, c, parent, provider),
);

const instanceProfileName = resolveInstanceProfileName(name, args, core, parent)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not do core.apply(c => resolveInstanceProfileName(...)) instead like before?
That way resolveInstanceProfileName can stay out of the output-space and operate on promptly available data instead. That would simplify testing

Copy link
Contributor

@flostadler flostadler Nov 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function would change to this in that case:

export function resolveInstanceProfileName(
    nodeGroupName: string,
    args: Omit<NodeGroupOptions, "cluster">,
    c: pulumi.UnwrappedObject<CoreData>,
    parent: pulumi.ComponentResource,
): pulumi.Output<string> {
    if (
        !args.instanceProfile &&
        !args.instanceProfileName &&
        !c.nodeGroupOptions.instanceProfile &&
        !c.nodeGroupOptions.instanceProfileName
    ) {
        throw new pulumi.ResourceError(
            `an instanceProfile or instanceProfileName is required`,
            parent,
        );
    }
    if (
        (args.instanceProfile || c.nodeGroupOptions.instanceProfile) &&
        (args.instanceProfileName || c.nodeGroupOptions.instanceProfileName)
    ) {
        throw new pulumi.ResourceError(
            `invalid args for node group ${name}, instanceProfile and instanceProfileName are mutually exclusive`,
            parent,
        );
    }

    return args.instanceProfile?.name ?? pulumi.output(c.nodeGroupOptions.instanceProfileName!) 
}

Copy link
Contributor

@flostadler flostadler Nov 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd also slightly change the definedness checks to check for all possible cases:

export function resolveInstanceProfileName(
    name: string,
    args: Omit<NodeGroupOptions, "cluster">,
    c: pulumi.UnwrappedObject<CoreData>,
    parent: pulumi.ComponentResource,
): pulumi.Output<string> {
    // todo check the mutual exclusive'ness

    if (args.instanceProfileName) {
        return pulumi.output(args.instanceProfileName);
    } else if (c.nodeGroupOptions.instanceProfileName) {
        return pulumi.output(c.nodeGroupOptions.instanceProfileName);
    } else if (args.instanceProfile) {
        return args.instanceProfile.name;
    } else if (c.nodeGroupOptions.instanceProfile) {
        return c.nodeGroupOptions.instanceProfile.name;
    } else {
        throw new pulumi.ResourceError(
            `an instanceProfile or instanceProfileName is required`,
            parent,
        );
    }
}

(args.instanceProfile || c.nodeGroupOptions.instanceProfile) &&
(args.instanceProfileName || c.nodeGroupOptions.instanceProfileName)
) {
): pulumi.Output<string> | undefined {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this always return a value?

}
},
// Needed for AL2023 until the CNI is managed with an addon because our custom CNI is too old
useDefaultVpcCni: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can actually not needed anymore. I guess this is copied from

// Needed for AL2023 until the CNI is managed with an addon because our custom CNI is too old
?

I'll remove it there as well

});

export const passedInstanceProfileName = instanceProfile.name
export const kubeconfig = cluster_NoIp_NoIpn.kubeconfig;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to export the kubeconfig of all clusters and run acceptance tests using those. Right now only one cluster is tested.

The test is creating a lot of clusters and node groups right now. Aren't the unit tests already checking that we pick the right option for instance profile?
I think it would be good enough if you added a single cluster and two node groups (v1/v2) using the instanceProfileName arg

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops missed exporting the other kubeconfigs... sure I can reduce the scope of the tests, I was going for a more completionist approach

Copy link
Contributor

@flostadler flostadler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Thanks a lot

@flostadler flostadler merged commit 230eba5 into master Nov 25, 2024
34 checks passed
@flostadler flostadler deleted the jdavredbeard/addInstanceProfileName branch November 25, 2024 17:03
@pulumi-bot
Copy link
Contributor

This PR has been shipped in release v3.3.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add instanceProfileName resource property to NodeGroup/V2
3 participants