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

aws-ec2: Import of existing launch template via attributes doesn't work #26035

Open
aramfe opened this issue Jun 19, 2023 · 11 comments
Open

aws-ec2: Import of existing launch template via attributes doesn't work #26035

aramfe opened this issue Jun 19, 2023 · 11 comments
Assignees
Labels
@aws-cdk/aws-ec2 Related to Amazon Elastic Compute Cloud bug This issue is a bug. effort/medium Medium work item – several days of effort p2

Comments

@aramfe
Copy link

aramfe commented Jun 19, 2023

Describe the bug

CDK function fromLaunchTemplateAttributes doesn't import existing templates as expected, when trying to get an already existing launch template by launchTemplateName or launchTemplateId. It also throws a misleading error message.

Expected Behavior

CDK returns an object accordingly to the attributes given.

Also: If it can't be found - for whatever reason -, the error message should at least be more precise in so far, that the launch template itself couldn't be found, instead of throwing the misleading Error: The provided launch template does not expose its user data. error message.

Current Behavior

Doesn't return the expected Launch Template reference and CDK therefore can't synthesize with the misleading error message: Error: The provided launch template does not expose its user data.

Reproduction Steps

  1. Create a new launch template named TestTemplate via AWS console.
  2. Set it up accordingly, so that it is useable.
  3. Try to import the created launch template via launchTemplateName or launchTemplateid:

const importedLaunchTemplate = ec2.LaunchTemplate.fromLaunchTemplateAttributes(this, "ImportedLaunchTemplate", { launchTemplateName: "TestTemplate", })

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.83

Framework Version

No response

Node.js Version

13.2.1 (22D68)

OS

Mac

Language

Typescript

Language Version

No response

Other information

No response

@aramfe aramfe added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Jun 19, 2023
@github-actions github-actions bot added the @aws-cdk/aws-ec2 Related to Amazon Elastic Compute Cloud label Jun 19, 2023
@aramfe aramfe changed the title ec2: can't import existing launch template aws-ec2: can't import existing launch template Jun 19, 2023
@aramfe aramfe changed the title aws-ec2: can't import existing launch template aws-ec2: Import of existing launch template via attributes doesn't work Jun 19, 2023
@pahud
Copy link
Contributor

pahud commented Jun 19, 2023

Can you share more details about your CDK code?

I don't think simply import the template as below throw the error because technically CDK just create a reference for that without checking if the template really exists.

I guess you probably have create some other resource that consume this imported template and that resource strictly require user data exposed in the template. In this case I am afraid this is not something the fromLaunchTemplateAttributes can validate.

const importedLaunchTemplate = ec2.LaunchTemplate.fromLaunchTemplateAttributes(this, "ImportedLaunchTemplate", { launchTemplateName: "TestTemplate", })

@pahud pahud added p2 effort/medium Medium work item – several days of effort response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. and removed needs-triage This issue or PR still needs to be triaged. labels Jun 19, 2023
@colifran colifran self-assigned this Jun 19, 2023
@aramfe
Copy link
Author

aramfe commented Jun 21, 2023

Sure, here is the full code example:

    const securityGroup = EcsClusterStack.createEcsHostSecurityGroup(ecsCluster, vpc)

    const launchTemplateRole = new iam.Role(ecsCluster, "launchTemplateRole", { assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com") })
    launchTemplateRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName(ManagedPolicies.AMAZON_SSM_MANAGED_INSTANCE_CORE))

    // ecsCluster as scope is necessary here, otherwise EC2 instances won't scale out automatically for some reason
    const launchTemplate = new cdk.aws_ec2.CfnLaunchTemplate(ecsCluster, "LaunchTemplateECSDeployment", {
      launchTemplateName: "LaunchTemplateECSDeployment",
      launchTemplateData: {
        imageId: ecs.EcsOptimizedImage.amazonLinux2().getImage(ecsCluster).imageId,
        userData: ec2.UserData.forLinux().render(),
        securityGroupIds: [securityGroup.securityGroupId],
        iamInstanceProfile: {
          arn: launchTemplateRole.roleArn,
        },
        //Staging
        instanceRequirements: props.launchTemplateData.instanceRequirements ?? undefined,
        //Prod
        instanceType: props.launchTemplateData.instanceType ?? undefined,
      },
    })

    const importedLaunchTemplate = ec2.LaunchTemplate.fromLaunchTemplateAttributes(ecsCluster, "ImportedLaunchTemplatImportedECSDepyloment", {
      launchTemplateName: "LaunchTemplateECSDeployment",
    })
    importedLaunchTemplate.node.addDependency(launchTemplate)

    let mixedInstancesPolicy: autoscaling.MixedInstancesPolicy | undefined

    if (mixedInstancesOptions) {
      mixedInstancesPolicy = {
        launchTemplate: importedLaunchTemplate,
        instancesDistribution: {
          spotAllocationStrategy: mixedInstancesOptions.instancesDistribution?.spotAllocationStrategy,
          spotMaxPrice: mixedInstancesOptions.instancesDistribution?.spotMaxPrice,
        },
      }
    }

    // ecsCluster as scope is necessary here, otherwise EC2 instances won't scale out automatically for some reason
    const autoScalingGroup = new autoscaling.AutoScalingGroup(ecsCluster, "AutoScalingGroup", {
      vpc: vpc,
      launchTemplate: !mixedInstancesPolicy ? importedLaunchTemplate : undefined,
      mixedInstancesPolicy: mixedInstancesPolicy,
      updatePolicy: capacityOptions.updatePolicy,
      minCapacity: capacityOptions.minCapacity,
      maxCapacity: capacityOptions.maxCapacity,
    })

    // ecsCluster as scope is necessary here, otherwise EC2 instances won't scale out automatically for some reason
    const capacityProvider = new ecs.AsgCapacityProvider(ecsCluster, "AsgCapacityProvider", {
      autoScalingGroup: autoScalingGroup,
      machineImageType: ecs.MachineImageType.AMAZON_LINUX_2,
      enableManagedScaling: true,
      enableManagedTerminationProtection: true,
      spotInstanceDraining: capacityOptions.spotInstanceDraining,
    })

    ecsCluster.addAsgCapacityProvider(capacityProvider)

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Jun 21, 2023
@pahud
Copy link
Contributor

pahud commented Jun 21, 2023

Looks like this error was thrown from here

public get userData(): ec2.UserData {

And this might be triggered from addUserData here

autoScalingGroup.addUserData(

I guess we probably can check the UserData availability in the AsgCapacityProvider class to improve the error message.

@colifran
Copy link
Contributor

colifran commented Jun 21, 2023

@pahud @aramfe we have a feature flag that will add user data from the machine image if user data isn't explicitly provided as a property when creating the launch template. If you enable EC2_LAUNCH_TEMPLATE_DEFAULT_USER_DATA does this fix the error you're running into? I haven't had a chance to try for myself but will give it a shot today.

Edit: I ran it with this feature flag set and it didn't resolve the issue. It looks like we're attempting to add user data when configuring the auto scaling group as part of adding an auto scaling group capacity provider, but the imported launch template doesn't have user data with it. As @pahud mentioned, addUserData is first attempting to get the attached userData which then results in the error being thrown.

@aramfe
Copy link
Author

aramfe commented Jun 23, 2023

Okay, thanks for clarification:

How can I fix my problem then, given my code context? I still haven't really understood, yet, how I can bypass this issue.

@aramfe
Copy link
Author

aramfe commented Jun 27, 2023

@pahud @colifran

What should I do now? Any workaround for this?

@colifran
Copy link
Contributor

@aramfe I don't think it will be possible to use an imported launch template for this since we're not able to import it with user data. I think the error message probably needs to be improved, but I think the way forward is to use a launch template that is created as part of your app.

@aramfe
Copy link
Author

aramfe commented Jun 28, 2023

@colifran

Thanks. So you mean I can only use the Layer-2 (CDK constructs) and not Layer-1-Constructs (CFN)? Problem is, that CDK-Layer-2 constructs for launch templates do not have all configurations available (especially regarding the instanceRequirements, which is not implemented yet in the CDK-Layer-2-Construct class object). So now that I can't use the CFN-Layer-1 construct (as in the example given by me) I simply can't configure that option via code or CDK at all, as I need to use the CDK-Layer-2-Construct to make it usable in my CDK context. This is quite a problem, as I need to use the instanceRequirements configuration option for my case.

Could you clarify if I got that right?

@colifran
Copy link
Contributor

colifran commented Jun 28, 2023

@aramfe I was strictly speaking about using an imported LaunchTemplate which is what was generating the error message you're seeing as a result of it not including a userData property. Based on what you're saying, it seems like you're using the imported LaunchTemplate as a way of converting the L1 to an L2 since you need to use the instanceRequirement property which isn't currently available on the L2 LaunchTemplate. I think a possible path forward for you would be to create an L2 LaunchTemplate and then use an escape hatch to configure the instanceRequirements of the underlying L1. Have a look at this guide and let me know if this makes sense to you or if you have any additional questions about this - https://docs.aws.amazon.com/cdk/v2/guide/cfn_layer.html#cfn_layer_resource. I would also encourage you to open an issue to request instanceRequirements be implemented as part of our existing LaunchTemplate construct.

@colifran
Copy link
Contributor

colifran commented Jul 6, 2023

@aramfe was this able to unblock you? Am I okay to close this issue?

@mithunlatiff
Copy link

mithunlatiff commented Jul 10, 2023

@colifran I m facing the same issue too. I tried to use the L1 construct to pass userdata, initialized from L2 construct,,following your advice, still same error. Is there any other way to fix this error? The launch template is imported, same situation. IS there any other way the LT can be imported?
ltcfn = lt.node.default_child
ltcfn.LaunchTemplateDataProperty(user_data="userdata")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-ec2 Related to Amazon Elastic Compute Cloud bug This issue is a bug. effort/medium Medium work item – several days of effort p2
Projects
None yet
Development

No branches or pull requests

4 participants