--- AWSTemplateFormatVersion: "2010-09-09" Description: >- (WWPS-GLS-WF-GWFCORE-LT) Creates an EC2 Launch Template for AWS Batch based genomics workflows Mappings: TagMap: default: architecture: "genomics-workflows" solution: "default" tags: - Key: "architecture" Value: "genomics-workflows" - Key: "solution" Value: "default" Parameters: Namespace: Type: String Description: Namespace (e.g. project name) to use to label resources LaunchTemplateNamePrefix: Type: String Default: gwfcore Description: Name of the launch template. This will be made unique using the Stack ID. DockerStorageVolumeSize: Type: Number Default: 100 Description: The initial size of the volume Docker will use for image and metadata storage (GB) MinValue: 0 Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: "Required" Parameters: - Namespace - Label: default: "Optional" Parameters: - LaunchTemplateNamePrefix - DockerStorageVolumeSize Conditions: NoNamespace: !Equals [ !Ref Namespace, "" ] Resources: EC2LaunchTemplate: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateName: Fn::Join: - "-" - - !Ref LaunchTemplateNamePrefix - Fn::If: - NoNamespace - !Select [2, !Split ["/", !Ref "AWS::StackId" ]] - !Ref Namespace LaunchTemplateData: # Used in tandem with UserData to check if the instance is provisioned # correctly. It is important to terminate mis-provisioned instances before # jobs are placed on them InstanceInitiatedShutdownBehavior: terminate TagSpecifications: - ResourceType: instance Tags: - Key: architecture Value: !FindInMap ["TagMap", "default", "architecture"] BlockDeviceMappings: - Ebs: DeleteOnTermination: True VolumeSize: 50 VolumeType: gp3 DeviceName: /dev/xvda - Ebs: Encrypted: True DeleteOnTermination: True VolumeSize: 22 VolumeType: gp3 DeviceName: /dev/xvdcz - Ebs: Encrypted: True DeleteOnTermination: True VolumeSize: !Ref DockerStorageVolumeSize VolumeType: gp3 DeviceName: /dev/xvdba UserData: Fn::Base64: Fn::Sub: | MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="==BOUNDARY==" --==BOUNDARY== Content-Type: text/cloud-config; charset="us-ascii" #cloud-config repo_update: true repo_upgrade: security packages: - jq - btrfs-progs - sed - git - amazon-ssm-agent - unzip - amazon-cloudwatch-agent - lustre-client write_files: - permissions: '0644' path: /opt/aws/amazon-cloudwatch-agent/etc/config.json content: | { "agent": { "logfile": "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log" }, "logs": { "logs_collected": { "files": { "collect_list": [ { "file_path": "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log", "log_group_name": "/aws/ecs/container-instance/${Namespace}", "log_stream_name": "/aws/ecs/container-instance/${Namespace}/{instance_id}/amazon-cloudwatch-agent.log" }, { "file_path": "/var/log/cloud-init.log", "log_group_name": "/aws/ecs/container-instance/${Namespace}", "log_stream_name": "/aws/ecs/container-instance/${Namespace}/{instance_id}/cloud-init.log" }, { "file_path": "/var/log/cloud-init-output.log", "log_group_name": "/aws/ecs/container-instance/${Namespace}", "log_stream_name": "/aws/ecs/container-instance/${Namespace}/{instance_id}/cloud-init-output.log" }, { "file_path": "/var/log/ecs/ecs-init.log", "log_group_name": "/aws/ecs/container-instance/${Namespace}", "log_stream_name": "/aws/ecs/container-instance/${Namespace}/{instance_id}/ecs-init.log" }, { "file_path": "/var/log/ecs/ecs-agent.log", "log_group_name": "/aws/ecs/container-instance/${Namespace}", "log_stream_name": "/aws/ecs/container-instance/${Namespace}/{instance_id}/ecs-agent.log" }, { "file_path": "/var/log/ecs/ecs-volume-plugin.log", "log_group_name": "/aws/ecs/container-instance/${Namespace}", "log_stream_name": "/aws/ecs/container-instance/${Namespace}/{instance_id}/ecs-volume-plugin.log" }, { "file_path": "/var/log/ebs-autoscale-install.log", "log_group_name": "/aws/ecs/container-instance/${Namespace}", "log_stream_name": "/aws/ecs/container-instance/${Namespace}/{instance_id}/ebs-autoscale-install.log" }, { "file_path": "/var/log/ebs-autoscale.log", "log_group_name": "/aws/ecs/container-instance/${Namespace}", "log_stream_name": "/aws/ecs/container-instance/${Namespace}/{instance_id}/ebs-autoscale.log" } ] } } } } runcmd: # start the amazon-cloudwatch-agent - /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/etc/config.json # install aws-cli v2 and copy the static binary in an easy to find location for bind-mounts into containers - curl -s "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "/tmp/awscliv2.zip" - unzip -q /tmp/awscliv2.zip -d /tmp - /tmp/aws/install -b /usr/bin # check that the aws-cli was actually installed. if not shutdown (terminate) the instance - command -v aws || shutdown -P now - mkdir -p /opt/aws-cli/bin - cp -a $(dirname $(find /usr/local/aws-cli -name 'aws' -type f))/. /opt/aws-cli/bin/ # optional EFS mount - USEEFS=`aws ssm get-parameter --name /gwfcore/${Namespace}/efs-shared-file-system --query 'Parameter.Value' --output text` - if [[ $USEEFS != "none" ]] - then - mkdir -p /mnt/efs - echo $USEEFS:/ /mnt/efs efs tls,_netdev >> /etc/fstab - mount -a -t efs defaults - fi # optional FSx mount # For loops added for retry logic as the limits could be exhausted for ssm # If the calls to get parameter is very high, make sure to increase the throughput from console. AWS Systems Manager -> Parameter Store -> Settings -> Parameter Store throughput -> paid tier/higher throughput limit. - for i in {1..5}; do FSxId=`aws ssm get-parameter --name /gwfcore/${Namespace}/fsx-file-system --query 'Parameter.Value' --output text` && break || sleep 15; done - if [[ $FSxId != "none" ]] - then - for i in {1..5}; do FSxMount=`aws ssm get-parameter --name /gwfcore/${Namespace}/fsx-mount-name --query 'Parameter.Value' --output text` && break || sleep 15; done - for i in {1..5}; do export S3_BUCKET_TO_MOUNT=$(aws ssm get-parameter --name /gwfcore/${Namespace}/installed-artifacts/bucket --query 'Parameter.Value' --output text) && break || sleep 15; done - mkdir -p /$S3_BUCKET_TO_MOUNT && chmod 777 /$S3_BUCKET_TO_MOUNT - sudo amazon-linux-extras install -y lustre2.10 - for i in {1..5}; do sudo mount -t lustre -o noatime,flock $FSxId.fsx.${AWS::Region}.amazonaws.com@tcp:/$FSxMount /$S3_BUCKET_TO_MOUNT && break || sleep 15; done - grep -qs /$S3_BUCKET_TO_MOUNT /proc/mounts;if [ $? -ne 0 ];then sudo shutdown -h now;else echo "FSx successfully mounted.";fi - fi # set environment variables for provisioning - for i in {1..5}; do export INSTALLED_ARTIFACTS_S3_ROOT_URL=$(aws ssm get-parameter --name /gwfcore/${Namespace}/installed-artifacts/s3-root-url --query 'Parameter.Value' --output text) && break || sleep 15; done # enable ecs , docker and autoscaling. - cd /opt - aws s3 sync $INSTALLED_ARTIFACTS_S3_ROOT_URL/ecs-additions ./ecs-additions - chmod a+x /opt/ecs-additions/provision.sh /opt/ecs-additions/ecs-logs-collector.sh - /opt/ecs-additions/provision.sh ${Namespace} $INSTALLED_ARTIFACTS_S3_ROOT_URL # Added below logic for collecting the ecs logs on s3 for troubleshooting - sudo /opt/ecs-additions/ecs-logs-collector.sh - aws s3 cp /opt/ecs-additions/collect-i*tgz s3://$S3_BUCKET_TO_MOUNT/ecs-instance-logs/ --==BOUNDARY==-- Outputs: LaunchTemplateId: Description: >- EC2 Launch Template ID to use when creating AWS Batch compute environments for genomics workflows Value: !Ref EC2LaunchTemplate ...