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

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

jdavredbeard
Copy link

@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?

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
2 participants