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

Support MIME multipart format in UserData #8315

Assignees
Labels
@aws-cdk/aws-ec2 Related to Amazon Elastic Compute Cloud effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. p2

Comments

@reisingerf
Copy link

Support generation of MIME multipart format user data scripts via the CDK UserData class/implementations.

Use Case

We are using user data (via launch templates) to configure our AWS Batch instances. This has to be in MIME multi-part archive format as stated here: https://docs.aws.amazon.com/batch/latest/userguide/launch-templates.html

However, that format does not seem to be supported by the current UserData implementations. We currently end up using a combination of CustomUserData to define the MIME multi-part format and LinuxUserData with addS3DownloadCommand to pull in Assets (reusable parts of the user data).

This quickly gets and looks messy.

Proposed Solution

Add support for properly MIME multi-part archive formatted user data that can be used in LaunchTemplates

Other

Note that we are quite new to AWS CDK, so if we have missed something or there are alternative better approaches, we'd be more than happy to hear about it!

Our current approach looks something like this:

umccrise_wrapper_asset = assets.Asset(
    self,
    'UmccriseWrapperAsset',
    path=os.path.join(dirname, '..', 'assets', "umccrise-wrapper.sh")
)
umccrise_wrapper_asset.grant_read(batch_instance_role)

user_data_asset = assets.Asset(
    self,
    'UserDataAsset',
    path=os.path.join(dirname, '..', 'assets', "batch-user-data.sh")
)
user_data_asset.grant_read(batch_instance_role)

user_data = ec2.UserData.for_linux()
local_path = user_data.add_s3_download_command(
    bucket=user_data_asset.bucket,
    bucket_key=user_data_asset.s3_object_key
)
user_data.add_execute_file_command(
    file_path=local_path,
    arguments=f"s3://{umccrise_wrapper_asset.bucket.bucket_name}/{umccrise_wrapper_asset.s3_object_key}"
)

# create wrapper for MIME multi-part archive format
user_data_wrapper = ec2.UserData.custom('MIME-Version: 1.0')
user_data_wrapper.add_commands('Content-Type: multipart/mixed; boundary="==MYBOUNDARY=="')
user_data_wrapper.add_commands('')
user_data_wrapper.add_commands('--==MYBOUNDARY==')
user_data_wrapper.add_commands('Content-Type: text/x-shellscript; charset="us-ascii"')
user_data_wrapper.add_commands('')
user_data_wrapper.add_commands(user_data.render())
user_data_wrapper.add_commands('--==MYBOUNDARY==--')

launch_template = ec2.CfnLaunchTemplate(
    self,
    'UmccriseBatchComputeLaunchTemplate',
    launch_template_name='UmccriseBatchComputeLaunchTemplate',
    launch_template_data={
        'userData': core.Fn.base64(user_data_wrapper.render())
    }
)

This is a 🚀 Feature Request

@reisingerf reisingerf added feature-request A feature should be added or improved. needs-triage This issue or PR still needs to be triaged. labels Jun 2, 2020
@SomayaB SomayaB added the @aws-cdk/aws-ec2 Related to Amazon Elastic Compute Cloud label Jun 2, 2020
@rix0rrr
Copy link
Contributor

rix0rrr commented Jun 3, 2020

You're on the right track, but you probably want to define your own MimeUserData class (rather than filling an existing UserData class with MIME content).

@rix0rrr rix0rrr closed this as completed Jun 3, 2020
@rix0rrr rix0rrr reopened this Jun 3, 2020
@rix0rrr rix0rrr added the effort/medium Medium work item – several days of effort label Jun 3, 2020
@reisingerf
Copy link
Author

I just thought this is a common/valid enough use case (as that format is required by LaunchTemplates) to perhaps think about supporting it within the framework rather than letting each end user having to build their own solution.

There are already 3 implementations of UserData, one doing nothing more than joining strings with '\n'. If that's supported, why not a MIME wrapper, which has more potential for screwing things up and therefore would benefit from a default implementation?

I may miss the point here and I am not an expert on the topic (hence would benefit from a solution that helps me deal with it), so would be happy to hear about reasons this should not be included.

@SomayaB SomayaB removed the needs-triage This issue or PR still needs to be triaged. label Jun 18, 2020
@rix0rrr rix0rrr added the p2 label Aug 12, 2020
@rsmogura
Copy link
Contributor

I'm a bit interested in this change, as I would like to use it to configure AWS Batch (AWS Batch requires UserData to be in MultiPart format).

Can I propose following factoring:

/**
 * The single part of data, which can be added to {@link MultipartUserData}.
 */
export class UserDataMimePart {
  /** The body of this MIME part. */
  public readonly body: string;

  /** Represents `Content-Type` header of this part */
  public readonly contentType: string;
}

/**
 * Interface indicating that a class can produce {@link UserDataMimePart}.
 */
export interface IMultipartUserDataProducer {
  /**
   * Called to create the {@link UserDataMimePart}.
   */
  renderAsMimePart(): UserDataMimePart;
}

/**
 * Mime multipart user data.
 */
export class MultipartUserData extends UserData {
  public addPart(producer: IMultipartUserDataProducer): this {}

  public addRawPart(part: UserDataMimePart): this {}
}

Plus changes to existing UserData classes

class LinuxUserData extends UserData implements IMultipartUserDataProducer 

In order to use MultipartUserData users will have to:

  1. Create instance of MultipartUserData
  2. Add the existing UserData as part to MultipartUserData

The CDK will:

  1. Generate raw parts by calling IMultipartUserDataProducer.renderAsMimePart
  2. Add MIME header and concatenate parts with MIME separator (boundary)

For Linux user data raw part will look like

{
contentType: 'text/x-shellscript',
body: '#!/bin/bash\necho Hello world'
}

With this factoring users still will be able to use very useful, current implementations of UserData, and feature will be backward compatible. From the other hand, there still will be fallback path to build arbitrary part by directly constructing MultipartUserData and adding it MultipartUserData?

rsmogura pushed a commit to rsmogura/aws-cdk that referenced this issue Dec 2, 2020
Add support for multiparat (MIME) user data for Linux environments. This
type is more versatile type of user data, and some AWS service
(i.e. AWS Batch) requires it in order to customize the launch
behaviour.

Change was tested in integ environment to check if all
user data parts has been executed correctly and with proper charset
encoding.

fixes aws#8315
rsmogura pushed a commit to rsmogura/aws-cdk that referenced this issue Dec 2, 2020
Add support for multiparat (MIME) user data for Linux environments. This
type is more versatile type of user data, and some AWS service
(i.e. AWS Batch) requires it in order to customize the launch
behaviour.

Change was tested in integ environment to check if all
user data parts has been executed correctly and with proper charset
encoding.

fixes aws#8315
rsmogura pushed a commit to rsmogura/aws-cdk that referenced this issue Dec 2, 2020
Add support for multiparat (MIME) user data for Linux environments. This
type is more versatile type of user data, and some AWS service
(i.e. AWS Batch) requires it in order to customize the launch
behaviour.

Change was tested in integ environment to check if all
user data parts has been executed correctly and with proper charset
encoding.

fixes aws#8315
rsmogura pushed a commit to rsmogura/aws-cdk that referenced this issue Mar 4, 2021
Add support for multiparat (MIME) user data for Linux environments. This
type is more versatile type of user data, and some AWS service
(i.e. AWS Batch) requires it in order to customize the launch
behaviour.

Change was tested in integ environment to check if all
user data parts has been executed correctly and with proper charset
encoding.

fixes aws#8315
@mergify mergify bot closed this as completed in #11843 Mar 8, 2021
mergify bot pushed a commit that referenced this issue Mar 8, 2021
Add support for multiparat (MIME) user data for Linux environments. This
type is more versatile type of user data, and some AWS service
(i.e. AWS Batch) requires it in order to customize the launch
behaviour.

Change was tested in integ environment to check if all
user data parts has been executed correctly and with proper charset
encoding.

fixes #8315


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
@github-actions
Copy link

github-actions bot commented Mar 8, 2021

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

cornerwings pushed a commit to cornerwings/aws-cdk that referenced this issue Mar 8, 2021
Add support for multiparat (MIME) user data for Linux environments. This
type is more versatile type of user data, and some AWS service
(i.e. AWS Batch) requires it in order to customize the launch
behaviour.

Change was tested in integ environment to check if all
user data parts has been executed correctly and with proper charset
encoding.

fixes aws#8315


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
This was referenced Mar 17, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment