diff --git a/submodule05_Nextflow_AWSBatch.ipynb b/submodule05_Nextflow_AWSBatch.ipynb index 0503a62..3e33079 100755 --- a/submodule05_Nextflow_AWSBatch.ipynb +++ b/submodule05_Nextflow_AWSBatch.ipynb @@ -9,18 +9,13 @@ ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "4126cb07-34ee-4780-838f-872015a882b3", - "metadata": {}, - "source": [ - "## Overview" - ] - }, - { - "cell_type": "markdown", - "id": "f15ea992-faa6-4705-8384-eb5d81f5daff", + "id": "c090b42f-ffd5-41c0-b599-9e1f8a463369", "metadata": {}, "source": [ + "## Overview\n", + "\n", "This short tutorial demonstrates how to run a comparative genomics workflow using a bacteria data set. Steps in the workflow combine the analyses you performed in previous submodules, and include:\n", "- Read QC and trimming (fastqc, fastp)\n", "- Genome assembly (SPAdes)\n", @@ -33,18 +28,14 @@ "\n", "The tutorial uses a popular workflow manager called [Nextflow](https://www.nextflow.io) run via [AWS Batch](https://aws.amazon.com/batch/) to automate the processes run in Submodules 1 & 2.\n", "\n", - "AWS Batch will create the needed permissions, roles and resources to run Nextflow in a serverless manner. You can set up AWS Batch manually or deploy it **automatically** with a stack template. The Launch Stack button below will take you to the cloud formation create stack webpage with the template with required resources already linked. \n", - "\n", - "If you prefer to skip manual deployment and deploy automatically in the cloud, click the Launch Stack button below. For a walkthrough of the screens during automatic deployment please click [here](https://github.com/NIGMS/NIGMS-Sandbox/blob/main/docs/HowToLaunchAWSBatch.md). The deployment should take ~5 min and then the resources will be ready for use. \n", - "\n", - "[![Launch Stack](images/LaunchStack.jpg)](https://console.aws.amazon.com/cloudformation/home?#/stacks/new?stackName=aws-batch-nigms&templateURL=https://nigms-sandbox.s3.us-east-1.amazonaws.com/cf-templates/AWSBatch_template.yaml )\n", "\n", - "Before begining this tutorial, if you do not have required roles, policies, permissions or compute environment and would like to **manually** set those up please click [here](https://github.com/NIGMS/NIGMS-Sandbox/blob/main/docs/AWS-Batch-Setup.md) to set that up.\n" + "#### About AWS Batch\n", + "AWS Batch will create the needed permissions, roles and resources to run Nextflow in a serverless manner. You can set up AWS Batch manually or deploy it **automatically** with a stack template. Please see **Setting up AWS Batch** in the Get Started section below to learn more about how to use it.\n" ] }, { "cell_type": "markdown", - "id": "56d718a8", + "id": "80e981d2-010c-4139-80d5-7e7c4b14f8a5", "metadata": {}, "source": [ "## Prerequisites\n", @@ -55,8 +46,9 @@ "+ Please ensure you have a VPC, subnets, and security group set up before running this tutorial.\n", "+ Role with AdministratorAccess, AmazonSageMakerFullAccess, S3 access and AWSBatchServiceRole.\n", "+ Instance Role with AmazonECS_FullAccess, AmazonEC2ContainerRegistryFullAccess, and S3 access.\n", - "+ If you do not have the required set-up for AWS Batch please follow this tutorial [here](https://github.com/STRIDES/NIHCloudLabAWS/blob/zbyosufzai-awsbatch-1/notebooks/AWSBatch/Intro_AWS_Batch.ipynb#install_nextflow). ***When making the instance role, make another for SageMaker notebooks with the following permissions: AdminstratorAccess, AmazonEC2ContainerRegistryFullAccess, AmazonECS_FullAccess, AmazonS3FullAccess, AmazonSageMakerFullAccess, and AWSBatchServiceRole.***\n", - "It is recommended that specific permission to folders are added through inline policy. An example of the JSON is below:\n", + "+ If you do not have the required set-up for AWS Batch please follow this tutorial [here](https://github.com/STRIDES/NIHCloudLabAWS/blob/main/notebooks/AWSBatch/Intro_AWS_Batch.ipynb).\n", + "+ ***When making the instance role, make another for SageMaker notebooks with the following permissions: AdminstratorAccess, AmazonEC2ContainerRegistryFullAccess, AmazonECS_FullAccess, AmazonS3FullAccess, AmazonSageMakerFullAccess, and AWSBatchServiceRole.***\n", + "+ It is recommended that specific permission to folders are added through inline policy. An example of the JSON is below:\n", "\n", "
\n",
     "{\n",
@@ -84,21 +76,68 @@
     "    ]\n",
     "}\n",
     "
\n", - "For AWS bucket naming conventions, please click [here](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)." + "For AWS bucket naming conventions, please click [here](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html).\n", + "\n", + "\n", + "\n", + "
\n", + "
\n", + " Before using AWS Batch \n", + "
\n", + "

\n", + "Before begining this tutorial, if you do not have required roles, policies, permissions or compute environment and would like to manually set those up please click here to set that up.\n", + "

\n", + "
" ] }, { "cell_type": "markdown", - "id": "f940d3ca", + "id": "5ebe2e1f-1dc1-44a3-a0e3-f5fac1dac374", + "metadata": {}, + "source": [ + "## Get Started\n", + "### Step 0. Setting up AWS Batch\n", + "AWS Batch manages the provisioning of compute environments (EC2, Fargate), container orchestration, job queues, IAM roles, and permissions. We can deploy a full environment either:\n", + "- Automatically using a preconfigured AWS CloudFormation stack (**recommended**)\n", + "- Manually by setting up roles, queues, and buckets\n", + "The Launch Stack button below will take you to the cloud formation create stack webpage with the template with required resources already linked. \n", + "\n", + "If you prefer to skip manual deployment and deploy automatically in the cloud, click the **Launch Stack** button below. For a walkthrough of the screens during automatic deployment please click [here](https://github.com/NIGMS/NIGMS-Sandbox/blob/main/docs/HowToLaunchAWSBatch.md). The deployment should take ~5 min and then the resources will be ready for use. \n", + "\n", + "[![Launch Stack](images/LaunchStack.jpg)](https://console.aws.amazon.com/cloudformation/home?#/stacks/new?stackName=aws-batch-nigms&templateURL=https://nigms-sandbox.s3.us-east-1.amazonaws.com/cf-templates/AWSBatch_template.yaml )\n", + "\n", + "### Step 1. Install dependencies, update paths and create a new S3 Bucket to store input and output files\n", + "After setting up a AWS CloudFormation stack, need to let the nextflow workflow to know where are those resrouces by providing the configuration:\n", + "
\n", + "
\n", + " Important - Customize Required\n", + "
\n", + "

\n", + "After successfull creation of your stack you must attatch a new role to SageMaker to be able to submit batch jobs. Please following the the following steps to change your SageMaker role:
\n", + "

  1. Navigate to your SageMaker AI notebook dashboard (where you initially created and launched your VM)
  2. Locate your instance and click the Stop button
  3. Once the instance is stopped:
    • Click Edit
    • Scroll to the \"Permissions and encryption\" section
    • Click the IAM role dropdown
    • Select the new role created during stack formation (named something like aws-batch-nigms-SageMakerExecutionRole)
  4. \n", + "
  5. Click Update notebook instance to save your changes
  6. \n", + "
  7. After the update completes:
    • Click Start to relaunch your instance
    • Reconnect to your instance
    • Resume your work from this point
\n", + "\n", + "Warning: Make sure to replace the stack name to the stack that you just created. STACK_NAME = \"your-stack-name-here\"\n", + "

\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "536d98ed-54f8-43a8-aeeb-08859f85f1d6", "metadata": {}, + "outputs": [], "source": [ - "### Step 1. Install required dependencies, update paths and create a new S3 Bucket to store input and output files (if needed)\n" + "# dfine a stack name variable\n", + "STACK_NAME = \"aws-batch-nigms-test\"" ] }, { "cell_type": "code", "execution_count": null, - "id": "3d8b6d24", + "id": "a25ee32c-644e-4935-b2d6-7f0effcb2e7d", "metadata": {}, "outputs": [], "source": [ @@ -111,18 +150,27 @@ { "cell_type": "code", "execution_count": null, - "id": "0fb43e35", + "id": "aa828d0a-388e-487b-b8d5-b957774c153b", "metadata": {}, "outputs": [], "source": [ "# Set variable names \n", "# These variables should come from the Intro AWS Batch tutorial (or leave as-is if using the launch stack button)\n", - "BUCKET_NAME = \"aws-batch-nigms-batch-bucket-\" + account_id\n", + "BUCKET_NAME = f\"{STACK_NAME}-batch-bucket-{account_id}\"\n", + "AWS_QUEUE = f\"{STACK_NAME}-JobQueue\"\n", "INPUT_FOLDER = 'nigms-sandbox/unh-wgsbac-pipeline'\n", - "AWS_QUEUE = 'aws-batch-nigms-JobQueue'\n", "AWS_REGION = region" ] }, + { + "cell_type": "markdown", + "id": "7e4ebe7d-e5e4-4ef4-a4da-61a7d7b05984", + "metadata": {}, + "source": [ + "#### Install dependencies\n", + "Installs Nextflow and Java, which are required to execute the pipeline. In environments like SageMaker, Java is usually pre-installed. But if you're running outside SageMaker (e.g., EC2 or local), you’ll need to manually install it." + ] + }, { "cell_type": "code", "execution_count": null, @@ -135,92 +183,136 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "fdc0c5dc", + "cell_type": "markdown", + "id": "9309e19c-440d-4d33-9813-087ba645f527", "metadata": {}, - "outputs": [], "source": [ - "##### Import relevant libraries\n", - "# Created using this https://github.com/STRIDES/NIHCloudLabAWS/blob/zbyosufzai-awsbatch-1/notebooks/AWSBatch/Intro_AWS_Batch.ipynb#install_nextflow\n", - "#Run if you don't have Java installed\n", - "! sudo apt update\n", - "! sudo apt-get install default-jdk -y\n", - "! java -version" + "
\n", + "Install Java and Nextflow if needed in other systems\n", + "If using other system other than AWS SageMaker Notebook, you might need to install java and nextflow using the code below:\n", + "
# Install java
\n",
+    "    sudo apt update\n",
+    "    sudo apt-get install default-jdk -y\n",
+    "    java -version\n",
+    "    
\n", + " # Install Nextflow
\n",
+    "    curl https://get.nextflow.io | bash\n",
+    "    chmod +x nextflow\n",
+    "    ./nextflow self-update\n",
+    "    ./nextflow plugin update\n",
+    "    
\n", + "
" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "3124016c", + "cell_type": "markdown", + "id": "d1d3c2cf-c12c-4343-871e-14e147d79929", "metadata": {}, - "outputs": [], "source": [ - "#Install nexflow, make it exceutable, and update it\n", - "! curl https://get.nextflow.io | bash\n", - "! chmod +x nextflow\n", - "! ./nextflow self-update\n", - "! ./nextflow plugin update" + "#### Create additional .config file needed\n", + "A configuration template (aws_batch_template.config) is customized below with your actual AWS values:\n", + "- S3 bucket name\n", + "- AWS job queue name\n", + "- AWS region\n", + "\n", + "This file tells Nextflow later how to communicate with AWS Batch and where to find the resources it needs." ] }, { "cell_type": "code", "execution_count": null, - "id": "cfa2e068", + "id": "44c9fb02-dbe9-41d2-a984-7634f6aebd91", "metadata": {}, "outputs": [], "source": [ + "# copy the aws batch configuration file \n", + "! cp wgsbac/conf/aws_batch_template.config aws_batch_submodule5.config \n", "# replace batch bucket name in nextflow configuration file\n", - "! sed -i \"s/aws-batch-nigms-batch-bucket-/$BUCKET_NAME/g\" wgsbac/nextflow.config" + "! sed -i \"s/aws-batch-nigms-batch-bucket-/$BUCKET_NAME/g\" aws_batch_submodule5.config \n", + "# replace job queue name in configuration file \n", + "! sed -i \"s/aws-batch-nigms-JobQueue/$AWS_QUEUE/g\" aws_batch_submodule5.config \n", + "# replace the region placeholder with your region\n", + "! sed -i \"s/us-east-1/$AWS_REGION/g\" aws_batch_submodule5.config " ] }, { - "cell_type": "code", - "execution_count": null, - "id": "9417e8be", + "cell_type": "markdown", + "id": "fa9cbd3e-d003-48d1-8b41-924c74b9486f", "metadata": {}, - "outputs": [], "source": [ - "# replace job queue name in configuration file \n", - "! sed -i \"s/aws-batch-nigms-JobQueue/$AWS_QUEUE/g\" wgsbac/nextflow.config" + "### Step 2. Enable AWS Batch for the nextflow script \n", + "Run the pipeline in a cloud-native, serverless manner using AWS Batch. AWS Batch offloads the burden of provisioning and managing compute resources. When you execute this command:\n", + "- Nextflow uploads tasks to AWS Batch. \n", + "- AWS Batch pulls the necessary containers.\n", + "- Each process/task in the pipeline runs as an isolated job in the cloud." ] }, { "cell_type": "code", "execution_count": null, - "id": "09770029", + "id": "065b7e42-53f4-4cd9-a067-d03c7b87f482", "metadata": {}, "outputs": [], "source": [ - "# replace the region placeholder with your region\n", - "! sed -i \"s/aws-region/$AWS_REGION/g\" wgsbac/nextflow.config" + "# Run nextflow script with parameters \n", + "! nextflow run wgsbac/main.nf -profile docker,awsbatch \\\n", + " --input s3://$INPUT_FOLDER/samplesheet_test.csv \\\n", + " -c aws_batch_submodule5.config \\\n", + " -resume" ] }, { "cell_type": "markdown", - "id": "d6424c54-108f-459e-8f14-f2866bfc0141", + "id": "309fff1d-9c02-4386-895d-787fb8c3b5b4", "metadata": {}, "source": [ - "### Step 2. Enable AWS Batch for the nextflow script " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d6cb4617-b98c-41b6-995d-711d2f722cbf", - "metadata": {}, - "outputs": [], - "source": [ - "# Run nextflow script with parameters \n", - "! ./nextflow run wgsbac/main.nf --input s3://$INPUT_FOLDER/samplesheet_test.csv -profile docker,awsbatch -c wgsbac/nextflow.config --awsqueue $AWS_QUEUE --awsregion $AWS_REGION" + "#### Key Differences from Local Execution:\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
FeatureLocal Execution (e.g., SageMaker)AWS Batch Execution
ComputeUses notebook’s limited CPU/memoryUses scalable EC2/Fargate resources
Data LocationReads from local diskReads directly from S3
Job ManagementManual or single-threadedDistributed via job queues
ReproducibilityDepends on local environmentFully containerized via Docker
Fault ToleranceLimitedRetries & logs handled by AWS Batch
" ] }, { "cell_type": "markdown", - "id": "7187f8dc-bcb6-4caf-b17c-183fc776147f", + "id": "7e18731d-59ef-4c45-bc9e-6e5773f1b786", "metadata": {}, "source": [ - "### Step 3: Explore Results" + "### Step 3: Explore Results\n", + "This command lets you preview the full paths of output files within the S3 bucket. These results should be identical to the ones generated in Submodule 4, where the pipeline was run locally. The only differences lie in: (1) Execution environment: Local notebook vs. AWS Batch; (2)Data paths: Local file system vs. S3 input/output directories. Everything else: tools, parameters, and pipeline structure, remains the same, ensuring consistency across both local and cloud executions." ] }, { @@ -293,9 +385,60 @@ "from IPython.display import Image\n", "Image('wgsbac/assets/results/final_results/blobtools_plots/SRR10056829_T1_blobplot_read_cov.png', width=1200)" ] + }, + { + "cell_type": "markdown", + "id": "bb75509d-3000-4cfd-93ac-d910d2a97dca", + "metadata": {}, + "source": [ + "## Clean Up the AWS Environment\n", + "\n", + "Once you've successfully run your analysis and downloaded the results, it's a good idea to clean up unused resources to avoid unnecessary charges.\n", + "\n", + "#### Recommended Cleanup Steps:\n", + "\n", + "- **Delete Output Files from S3 (Optional)** \n", + " If you've downloaded your results locally and no longer need them stored in the cloud.\n", + "- **Delete the S3 Bucket (Optional)** \n", + " To remove the entire bucket (only do this if you're sure!)\n", + "- **Shut Down AWS Batch Resources (Optional but Recommended):** \n", + " If you used a CloudFormation stack to set up AWS Batch, you can delete all associated resources in one step (⚠️ Note: Deleting the stack will also remove IAM roles and compute environments created by the template.):\n", + " + Go to the AWS CloudFormation Console\n", + " + Select your stack (e.g., aws-batch-nigms-test1)\n", + " + Click Delete\n", + " + Wait for all resources (compute environments, roles, queues) to be removed\n", + " \n", + "
\n", + "
\n", + " Tips\n", + "
\n", + "

\n", + "It’s always good practice to periodically review your EC2 instances, ECR containers, S3 storage, and CloudWatch logs to ensure no stray resources are incurring charges.\n", + "

\n", + "
\n", + "\n" + ] } ], - "metadata": {}, + "metadata": { + "kernelspec": { + "display_name": "conda_python3", + "language": "python", + "name": "conda_python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.18" + } + }, "nbformat": 4, "nbformat_minor": 5 } diff --git a/wgsbac/AWSBatch_template.yaml b/wgsbac/AWSBatch_template.yaml deleted file mode 100755 index b51f36b..0000000 --- a/wgsbac/AWSBatch_template.yaml +++ /dev/null @@ -1,297 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Description: AWS Batch setup with IAM Roles -Resources: -######## Roles & Permissions ############# - SageMakerExecutionRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Principal: - Service: sagemaker.amazonaws.com - Action: sts:AssumeRole - Path: / - ManagedPolicyArns: - - arn:aws:iam::aws:policy/AdministratorAccess - - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess - - arn:aws:iam::aws:policy/AmazonECS_FullAccess - - arn:aws:iam::aws:policy/AmazonS3FullAccess - - arn:aws:iam::aws:policy/AmazonSageMakerFullAccess - - arn:aws:iam::aws:policy/service-role/AWSBatchServiceRole - Policies: - - PolicyName: S3SageMakerAccessPolicy - PolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: - - s3:GetObject - - s3:PutObject - - s3:ListBucket - - s3:GetBucketLocation - - s3:CreateBucket - Resource: - - arn:aws:s3:::nigms-sandbox/ - - arn:aws:s3:::nigms-sandbox/* - - !Sub arn:aws:s3:::${BatchBucket} - - arn:aws:s3:::ngi-igenomes - - arn:aws:s3:::ngi-igenomes/* - - AWSBatchEC2InstanceRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Principal: - Service: ec2.amazonaws.com - Action: sts:AssumeRole - Path: / - ManagedPolicyArns: - - arn:aws:iam::aws:policy/service-role/AWSBatchServiceRole - - arn:aws:iam::aws:policy/AmazonS3FullAccess - - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess - - arn:aws:iam::aws:policy/AmazonECS_FullAccess - - BatchInstanceProfile: - Type: AWS::IAM::InstanceProfile - Properties: - Path: / - Roles: - - !Ref AWSBatchEC2InstanceRole - - ####### Spin up compute environment ########### - BatchComputeEnvironment: - Type: AWS::Batch::ComputeEnvironment - Properties: - ComputeEnvironmentName: !Sub ${AWS::StackName}-ComputeEnvironment - Type: MANAGED - State: ENABLED - ComputeResources: - Type: SPOT - AllocationStrategy: SPOT_PRICE_CAPACITY_OPTIMIZED - MinvCpus: 0 - MaxvCpus: 256 - DesiredvCpus: 0 - InstanceTypes: - - optimal - Subnets: !Split [',', !GetAtt GetNetworkingResource.SubnetIds] - SecurityGroupIds: - - !GetAtt GetNetworkingResource.SecurityGroupId - - InstanceRole: !GetAtt BatchInstanceProfile.Arn - ServiceRole: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/batch.amazonaws.com/AWSServiceRoleForBatch - - ######## Job Queue ############# - BatchJobQueue: - Type: AWS::Batch::JobQueue - Properties: - JobQueueName: !Sub ${AWS::StackName}-JobQueue - State: ENABLED - ComputeEnvironmentOrder: - - ComputeEnvironment: !Ref BatchComputeEnvironment - Order: 1 - Priority: 1000 - DependsOn: BatchComputeEnvironment - - ######## Output Bucket ############# - BatchBucket: - Type: AWS::S3::Bucket - Properties: - BucketName: !Sub ${AWS::StackName}-batch-bucket-${AWS::AccountId} - BucketEncryption: - ServerSideEncryptionConfiguration: - - ServerSideEncryptionByDefault: - SSEAlgorithm: aws:kms - KMSMasterKeyID: alias/aws/s3 - PublicAccessBlockConfiguration: - IgnorePublicAcls: true - RestrictPublicBuckets: true - BucketBucketPolicy: - Type: AWS::S3::BucketPolicy - Properties: - Bucket: !Ref BatchBucket - PolicyDocument: - Id: RequireEncryptionInTransit - Version: '2012-10-17' - Statement: - - Principal: '*' - Action: '*' - Effect: Deny - Resource: - - !GetAtt BatchBucket.Arn - - !Sub ${BatchBucket.Arn}/* - Condition: - Bool: - aws:SecureTransport: 'false' - - ####### - CustomECSLambdaExecutionRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: sts:AssumeRole - Principal: - Service: lambda.amazonaws.com - Policies: - - PolicyName: LambdaExecutionPolicy - PolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: - - ec2:DescribeSubnets - - ec2:DescribeVpcs - - ec2:DescribeSecurityGroups - Resource: '*' - - Effect: Allow - Action: - - logs:CreateLogGroup - - logs:CreateLogStream - - logs:PutLogEvents - Resource: arn:aws:logs:*:*:* - GetNetworkingFunction: - Type: AWS::Lambda::Function - Properties: - Handler: index.lambda_handler - Role: !GetAtt CustomECSLambdaExecutionRole.Arn - FunctionName: GetNetworkingFunction - Runtime: python3.12 - Timeout: 60 - Code: - ZipFile: | - import json - import boto3 - import urllib3 - http = urllib3.PoolManager() - - def send_response( - response_url, - stack_id, - logical_id, - request_id, - status, - data, - physical_resource_id=None, - reason=None - ): - response_body = { - 'Status': status, - 'Reason': reason or 'See the details in CloudWatch Log Stream: {}'.format(data), - 'PhysicalResourceId': physical_resource_id or 'Subnets', - 'RequestId': request_id, # Include the RequestId in the response - 'Data': data, - 'StackId': stack_id, - 'LogicalResourceId': logical_id - } - headers = { - 'Content-Type': '', - 'Content-Length': str(len(json.dumps(response_body))) - } - - try: - # Send the response to CloudFormation - response = http.request( - 'PUT', - response_url, - body=json.dumps(response_body), - headers=headers - ) - - # Capture and print the HTTP response - print(f'Response sent to CloudFormation: HTTP {response.status}') - print(f'Response details: {response.data.decode("utf-8")}') - return response - - except Exception as e: - print(f'Error sending response to CloudFormation: {str(e)}') - raise e - - def lambda_handler(event, context): - print(f"HERE IS EVENT:\n {json.dumps(event)}") - ####################################################### - ##### what happens if they have multiple VPCs? ####### - ####################################################### - # Extract the VPCId from ResourceProperties - # vpc_id = event['ResourceProperties']['VPCId'] - response_url = event['ResponseURL'] # Response URL to send status back to CloudFormation - request_id = event['RequestId'] # Extract the RequestId from the event - stack_id = event['StackId'] - logical_id = event['LogicalResourceId'] - - # print(f"VPCId: {vpc_id}") - print(f"RESPONSE_URL: {response_url}") - print(f"REQUEST_ID: {request_id}") - print(f"STACK_ID: {stack_id}") - print(f"LOGICAL_ID: {logical_id}") - - ec2 = boto3.client('ec2') - try: - # Extract VPCId - response_vpc = ec2.describe_vpcs() - - # Check if response vpc list is empty - if len(response_vpc['Vpcs']) != 0: - vpc_id = '' - for vpc in response_vpc['Vpcs']: - # Check if vpc is default vpc if it is then store in vpc_id variable - if vpc['IsDefault'] == True: - vpc_id = response_vpc['Vpcs'][0]['VpcId'] - # Check if string (vpc_id) is empty and if it is then add first vpc from unfilterd vpc list - if len(vpc_id) == 0: - vpc_id = response_vpc['Vpcs'][0]['VpcId'] - - # Describe subnets in the given VPC - response = ec2.describe_subnets( - Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}] - ) - - # Describe security group Ids - response_sg = ec2.describe_security_groups( - Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}, - {'Name': 'group-name', 'Values':['default']}]) - - # Extract subnet IDs - subnet_ids = [subnet['SubnetId'] for subnet in response['Subnets']] - - # Extract default security group from VPC - default_security_group_id = response_sg['SecurityGroups'][0]['GroupId'] - - # Prepare success response data - data = { - 'SubnetIds': ','.join(subnet_ids), # Return as comma-separated string - 'VpcId': vpc_id, - 'SecurityGroupId': default_security_group_id - } - - # Send success response to CloudFormation with the correct RequestId - print(f"SENDING RESPONSE...") - send_response(response_url, stack_id, logical_id, request_id, 'SUCCESS', data) - - except Exception as e: - print(f"Error: {e}") - # Send failure response to CloudFormation with the correct RequestId - error_message = str(e) - send_response(response_url, stack_id, logical_id, request_id, 'FAILED', {}, reason=error_message) - GetNetworkingResource: - Type: AWS::CloudFormation::CustomResource - Properties: - ServiceToken: !GetAtt GetNetworkingFunction.Arn - ServiceTimeout: 60 - -Outputs: - ComputeEnvironmentArn: - Description: ARN of the Batch Computer Environment - Value: !Ref BatchComputeEnvironment - JobQueueArn: - Description: ARN of the Batch Job Queue - Value: !Ref BatchJobQueue - OutputBucketName: - Description: Name of the S3 Output Bucket - Value: !Ref BatchBucket \ No newline at end of file diff --git a/wgsbac/AWSBatch_template_fargate.yaml b/wgsbac/AWSBatch_template_fargate.yaml deleted file mode 100755 index 38fba1b..0000000 --- a/wgsbac/AWSBatch_template_fargate.yaml +++ /dev/null @@ -1,356 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Description: AWS Batch setup with IAM Roles -Resources: -######## Roles & Permissions ############# - SageMakerExecutionRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Principal: - Service: sagemaker.amazonaws.com - Action: sts:AssumeRole - Path: / - ManagedPolicyArns: - - arn:aws:iam::aws:policy/AdministratorAccess - - arn:aws:iam::aws:policy/AmazonECS_FullAccess - - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess - - arn:aws:iam::aws:policy/AmazonS3FullAccess - - arn:aws:iam::aws:policy/AmazonSageMakerFullAccess - - arn:aws:iam::aws:policy/service-role/AWSBatchServiceRole - Policies: - - PolicyName: S3SageMakerAccessPolicy - PolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: - - s3:GetObject - - s3:PutObject - - s3:ListBucket - - s3:GetBucketLocation - - s3:CreateBucket - Resource: - - arn:aws:s3:::nigms-sandbox/ - - arn:aws:s3:::nigms-sandbox/* - - !Sub arn:aws:s3:::${BatchBucket} - - arn:aws:s3:::ngi-igenomes - - arn:aws:s3:::ngi-igenomes/* - RoleName: !Sub ${AWS::StackName}-SageMakerExecutionRole - - AWSBatchFargateInstanceRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Principal: - Service: - - batch.amazonaws.com - - ecs-tasks.amazonaws.com - Action: sts:AssumeRole - Path: / - ManagedPolicyArns: - - arn:aws:iam::aws:policy/service-role/AWSBatchServiceRole - - arn:aws:iam::aws:policy/AmazonS3FullAccess - - arn:aws:iam::aws:policy/AmazonECS_FullAccess - - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role - - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess - # Policy for the job to access resources on AWS - Policies: - - PolicyName: BatchFargatePermissions - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - ec2:Describe* - - ecs:Describe* - - ecs:RunTask - - batch:SubmitJob - - iam:PassRole - - ecr:GetDownloadUrlForLayer - - ecr:BatchCheckLayerAvailability - - ecr:GetDownloadUrlForLayer - - ecr:BatchGetImage - - ecr:GetAuthorizationToken - - logs:CreateLogGroup - - logs:CreateLogStream - - logs:PutLogEvents - - s3:GetObject - - s3:PutObject - - ecs:CreateCluster - - ecs:DeleteCluster - - ecs:DescribeClusters - - ecs:ListClusters - Resource: "*" - RoleName: !Sub ${AWS::StackName}-AWSBatchFargateRole - ExecutionRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - Service: - - ecs-tasks.amazonaws.com - Action: - - sts:AssumeRole - ManagedPolicyArns: - - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy - - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess - - arn:aws:iam::aws:policy/AmazonECS_FullAccess - RoleName: !Sub ${AWS::StackName}-ExecutionRole - ####### Job definition ###### - BatchFargateJobDefinition: - Type: AWS::Batch::JobDefinition - Properties: - JobDefinitionName: !Sub ${AWS::StackName}-JobDefinition - Type: container - Timeout: - AttemptDurationSeconds: 600 - RetryStrategy: - Attempts: 1 - ContainerProperties: - Image: nextflow/nextflow:latest # public.ecr.aws/amazonlinux/amazonlinux:latest - NetworkConfiguration: - AssignPublicIp: ENABLED - ResourceRequirements: - - Type: VCPU - Value: 1 - - Type: MEMORY - Value: 2048 - JobRoleArn: !GetAtt AWSBatchFargateInstanceRole.Arn - ExecutionRoleArn: !GetAtt ExecutionRole.Arn - PlatformCapabilities: - - FARGATE - - ####### Spin up compute environment for AWS Batch ########### - BatchComputeEnvironment: - Type: AWS::Batch::ComputeEnvironment - Properties: - ComputeEnvironmentName: !Sub ${AWS::StackName}-ComputeEnvironment - Type: MANAGED - State: ENABLED - ComputeResources: - Type: FARGATE - MaxvCpus: 256 - Subnets: !Split [',', !GetAtt GetVpcResource.SubnetIds] - SecurityGroupIds: - - !GetAtt GetVpcResource.SecurityGroupId - ServiceRole: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/batch.amazonaws.com/AWSServiceRoleForBatch - - ######## Job Queue ############# - BatchJobQueue: - Type: AWS::Batch::JobQueue - Properties: - JobQueueName: !Sub ${AWS::StackName}-JobQueue - State: ENABLED - ComputeEnvironmentOrder: - - ComputeEnvironment: !Ref BatchComputeEnvironment - Order: 1 - Priority: 1000 - DependsOn: BatchComputeEnvironment - - ######## Output Bucket ############# - BatchBucket: - Type: AWS::S3::Bucket - Properties: - BucketName: !Sub ${AWS::StackName}-batch-bucket-${AWS::AccountId} - BucketEncryption: - ServerSideEncryptionConfiguration: - - ServerSideEncryptionByDefault: - SSEAlgorithm: aws:kms - KMSMasterKeyID: alias/aws/s3 - PublicAccessBlockConfiguration: - IgnorePublicAcls: true - RestrictPublicBuckets: true - BucketBucketPolicy: - Type: AWS::S3::BucketPolicy - Properties: - Bucket: !Ref BatchBucket - PolicyDocument: - Id: RequireEncryptionInTransit - Version: '2012-10-17' - Statement: - - Principal: '*' - Action: '*' - Effect: Deny - Resource: - - !GetAtt BatchBucket.Arn - - !Sub ${BatchBucket.Arn}/* - Condition: - Bool: - aws:SecureTransport: 'false' - - ####### Get networking settings ########## - CustomECSLambdaExecutionRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: sts:AssumeRole - Principal: - Service: lambda.amazonaws.com - Policies: - - PolicyName: LambdaExecutionPolicy - PolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: - - ec2:DescribeSubnets - - ec2:DescribeVpcs - - ec2:DescribeSecurityGroups - Resource: '*' - - Effect: Allow - Action: - - logs:CreateLogGroup - - logs:CreateLogStream - - logs:PutLogEvents - Resource: arn:aws:logs:*:*:* - GetVpcResourcesFunction: - Type: AWS::Lambda::Function - Properties: - Handler: index.lambda_handler - Role: !GetAtt CustomECSLambdaExecutionRole.Arn - FunctionName: GetVpcResourcesFunction - Runtime: python3.12 - Timeout: 60 - Code: - ZipFile: | - import json - import boto3 - import urllib3 - http = urllib3.PoolManager() - - def send_response( - response_url, - stack_id, - logical_id, - request_id, - status, - data, - physical_resource_id=None, - reason=None - ): - response_body = { - 'Status': status, - 'Reason': reason or 'See the details in CloudWatch Log Stream: {}'.format(data), - 'PhysicalResourceId': physical_resource_id or 'Subnets', - 'RequestId': request_id, # Include the RequestId in the response - 'Data': data, - 'StackId': stack_id, - 'LogicalResourceId': logical_id - } - headers = { - 'Content-Type': '', - 'Content-Length': str(len(json.dumps(response_body))) - } - - try: - # Send the response to CloudFormation - response = http.request( - 'PUT', - response_url, - body=json.dumps(response_body), - headers=headers - ) - - # Capture and print the HTTP response - print(f'Response sent to CloudFormation: HTTP {response.status}') - print(f'Response details: {response.data.decode("utf-8")}') - return response - - except Exception as e: - print(f'Error sending response to CloudFormation: {str(e)}') - raise e - - def lambda_handler(event, context): - print(f"HERE IS EVENT:\n {json.dumps(event)}") - # Extract the VPCId from ResourceProperties - # vpc_id = event['ResourceProperties']['VPCId'] - response_url = event['ResponseURL'] # Response URL to send status back to CloudFormation - request_id = event['RequestId'] # Extract the RequestId from the event - stack_id = event['StackId'] - logical_id = event['LogicalResourceId'] - - # print(f"VPCId: {vpc_id}") - print(f"RESPONSE_URL: {response_url}") - print(f"REQUEST_ID: {request_id}") - print(f"STACK_ID: {stack_id}") - print(f"LOGICAL_ID: {logical_id}") - - ec2 = boto3.client('ec2') - try: - # Extract VPCId - response_vpc = ec2.describe_vpcs() - - # Check if response vpc list is empty - if len(response_vpc['Vpcs']) != 0: - vpc_id = '' - for vpc in response_vpc['Vpcs']: - # Check if vpc is default vpc if it is then store in vpc_id variable - if vpc['IsDefault'] == True: - vpc_id = response_vpc['Vpcs'][0]['VpcId'] - # Check if string (vpc_id) is empty and if it is then add first vpc from unfilterd vpc list - if len(vpc_id) == 0: - vpc_id = response_vpc['Vpcs'][0]['VpcId'] - - # Describe subnets in the given VPC - response = ec2.describe_subnets( - Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}] - ) - - # Describe security group Ids - response_sg = ec2.describe_security_groups( - Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}, - {'Name': 'group-name', 'Values':['default']}]) - - # Extract subnet IDs - subnet_ids = [subnet['SubnetId'] for subnet in response['Subnets']] - - # Extract default security group from VPC - default_security_group_id = response_sg['SecurityGroups'][0]['GroupId'] - - # Prepare success response data - data = { - 'SubnetIds': ','.join(subnet_ids), # Return as comma-separated string - 'VpcId': vpc_id, - 'SecurityGroupId': default_security_group_id - } - - # Send success response to CloudFormation with the correct RequestId - print(f"SENDING RESPONSE...") - send_response(response_url, stack_id, logical_id, request_id, 'SUCCESS', data) - - except Exception as e: - print(f"Error: {e}") - # Send failure response to CloudFormation with the correct RequestId - error_message = str(e) - send_response(response_url, stack_id, logical_id, request_id, 'FAILED', {}, reason=error_message) - GetVpcResource: - Type: AWS::CloudFormation::CustomResource - Properties: - ServiceToken: !GetAtt GetVpcResourcesFunction.Arn - ServiceTimeout: 60 - -Outputs: - ComputeEnvironmentArn: - Description: ARN of the Batch Computer Environment - Value: !Ref BatchComputeEnvironment - JobQueueArn: - Description: ARN of the Batch Job Queue - Value: !Ref BatchJobQueue - OutputBucketName: - Description: Name of the S3 Output Bucket - Value: !Ref BatchBucket - FargateJobDefinition: - Value: !Ref BatchFargateJobDefinition - Description: The job definition for AWS Batch using Fargates diff --git a/wgsbac/nextflow.config b/wgsbac/nextflow.config index 9ccd879..3ff357e 100755 --- a/wgsbac/nextflow.config +++ b/wgsbac/nextflow.config @@ -46,7 +46,7 @@ params { awsregion = 'us-east-1' awsworkdir = 's3://aws-batch-nigms-batch-bucket-/nextflow_env/' outdir = 's3://aws-batch-nigms-batch-bucket-/nextflow_output/' - awscli_path = '/home/ec2-user/anaconda3/bin/aws' + awscli_path = '/home/ec2-user/miniconda/bin/aws' aws_execrole = 'ExecutionRole' // Boilerplate options @@ -99,8 +99,8 @@ profiles { } workDir = params.awsworkdir outdir = params.outdir - fusion.enabled = true - wave.enabled = true + fusion.enabled = false + wave.enabled = false // Give path to where aws is installed aws.batch.cliPath = params.awscli_path aws {