├── examples ├── ec2 │ ├── variables.tf │ ├── versions.tf │ ├── outputs.tf │ ├── README.md │ └── main.tf ├── fargate │ ├── variables.tf │ ├── versions.tf │ ├── outputs.tf │ ├── README.md │ └── main.tf └── README.md ├── versions.tf ├── .editorconfig ├── .gitignore ├── migrations.tf ├── .github └── workflows │ ├── lock.yml │ ├── release.yml │ ├── stale-actions.yaml │ ├── pr-title.yml │ └── pre-commit.yml ├── .releaserc.json ├── .pre-commit-config.yaml ├── outputs.tf ├── docs └── UPGRADE-3.0.md ├── CHANGELOG.md ├── LICENSE ├── variables.tf ├── main.tf └── README.md /examples/ec2/variables.tf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/fargate/variables.tf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.5.7" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 6.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/ec2/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.5.7" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 6.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/fargate/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.5.7" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 6.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | Please note - the examples provided serve two primary means: 4 | 5 | 1. Show users working examples of the various ways in which the module can be configured and features supported 6 | 2. A means of testing/validating module changes 7 | 8 | Please do not mistake the examples provided as "best practices". It is up to users to consult the AWS service documentation for best practices, usage recommendations, etc. 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | # Uses editorconfig to maintain consistent coding styles 3 | 4 | # top-most EditorConfig file 5 | root = true 6 | 7 | # Unix-style newlines with a newline ending every file 8 | [*] 9 | charset = utf-8 10 | end_of_line = lf 11 | indent_size = 2 12 | indent_style = space 13 | insert_final_newline = true 14 | max_line_length = 80 15 | trim_trailing_whitespace = true 16 | 17 | [*.{tf,tfvars}] 18 | indent_size = 2 19 | indent_style = space 20 | 21 | [*.md] 22 | max_line_length = 0 23 | trim_trailing_whitespace = false 24 | 25 | [Makefile] 26 | tab_width = 2 27 | indent_style = tab 28 | 29 | [COMMIT_EDITMSG] 30 | max_line_length = 0 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # Terraform lockfile 5 | .terraform.lock.hcl 6 | 7 | # .tfstate files 8 | *.tfstate 9 | *.tfstate.* 10 | 11 | # Crash log files 12 | crash.log 13 | 14 | # Exclude all .tfvars files, which are likely to contain sentitive data, such as 15 | # password, private keys, and other secrets. These should not be part of version 16 | # control as they are data points which are potentially sensitive and subject 17 | # to change depending on the environment. 18 | *.tfvars 19 | 20 | # Ignore override files as they are usually used to override resources locally and so 21 | # are not checked in 22 | override.tf 23 | override.tf.json 24 | *_override.tf 25 | *_override.tf.json 26 | 27 | # Ignore CLI configuration files 28 | .terraformrc 29 | terraform.rc 30 | 31 | # Lambda build artifacts 32 | builds/ 33 | __pycache__/ 34 | *.zip 35 | .tox 36 | 37 | # Local editors/macos files 38 | .DS_Store 39 | .idea 40 | -------------------------------------------------------------------------------- /migrations.tf: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Migrations: v2.x -> v3.0.0 3 | ################################################################################ 4 | 5 | moved { 6 | from = aws_iam_role_policy_attachment.instance["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"] 7 | to = aws_iam_role_policy_attachment.instance["AmazonSSMManagedInstanceCore"] 8 | } 9 | 10 | moved { 11 | from = aws_iam_role_policy_attachment.instance["arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"] 12 | to = aws_iam_role_policy_attachment.instance["AmazonEC2ContainerServiceforEC2Role"] 13 | } 14 | 15 | moved { 16 | from = aws_iam_role_policy_attachment.spot_fleet["arn:aws:iam::aws:policy/service-role/AmazonEC2SpotFleetTaggingRole"] 17 | to = aws_iam_role_policy_attachment.spot_fleet["AmazonEC2SpotFleetTaggingRole"] 18 | } 19 | 20 | moved { 21 | from = aws_iam_role_policy_attachment.service["arn:aws:iam::aws:policy/service-role/AWSBatchServiceRole"] 22 | to = aws_iam_role_policy_attachment.service["AWSBatchServiceRole"] 23 | } 24 | -------------------------------------------------------------------------------- /.github/workflows/lock.yml: -------------------------------------------------------------------------------- 1 | name: 'Lock Threads' 2 | 3 | on: 4 | schedule: 5 | - cron: '50 1 * * *' 6 | 7 | jobs: 8 | lock: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: dessant/lock-threads@v5 12 | with: 13 | github-token: ${{ secrets.GITHUB_TOKEN }} 14 | issue-comment: > 15 | I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues. 16 | If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. 17 | issue-inactive-days: '30' 18 | pr-comment: > 19 | I'm going to lock this pull request because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues. 20 | If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. 21 | pr-inactive-days: '30' 22 | -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "branches": [ 3 | "main", 4 | "master" 5 | ], 6 | "ci": false, 7 | "plugins": [ 8 | [ 9 | "@semantic-release/commit-analyzer", 10 | { 11 | "preset": "conventionalcommits" 12 | } 13 | ], 14 | [ 15 | "@semantic-release/release-notes-generator", 16 | { 17 | "preset": "conventionalcommits" 18 | } 19 | ], 20 | [ 21 | "@semantic-release/github", 22 | { 23 | "successComment": "This ${issue.pull_request ? 'PR is included' : 'issue has been resolved'} in version ${nextRelease.version} :tada:", 24 | "labels": false, 25 | "releasedLabels": false 26 | } 27 | ], 28 | [ 29 | "@semantic-release/changelog", 30 | { 31 | "changelogFile": "CHANGELOG.md", 32 | "changelogTitle": "# Changelog\n\nAll notable changes to this project will be documented in this file." 33 | } 34 | ], 35 | [ 36 | "@semantic-release/git", 37 | { 38 | "assets": [ 39 | "CHANGELOG.md" 40 | ], 41 | "message": "chore(release): version ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 42 | } 43 | ] 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | - master 9 | paths: 10 | - '**/*.tpl' 11 | - '**/*.py' 12 | - '**/*.tf' 13 | - '.github/workflows/release.yml' 14 | 15 | jobs: 16 | release: 17 | name: Release 18 | runs-on: ubuntu-latest 19 | # Skip running release workflow on forks 20 | if: github.repository_owner == 'terraform-aws-modules' 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v5 24 | with: 25 | persist-credentials: false 26 | fetch-depth: 0 27 | 28 | - name: Set correct Node.js version 29 | uses: actions/setup-node@v6 30 | with: 31 | node-version: 24 32 | 33 | - name: Install dependencies 34 | run: | 35 | npm install \ 36 | @semantic-release/changelog@6.0.3 \ 37 | @semantic-release/git@10.0.1 \ 38 | conventional-changelog-conventionalcommits@9.1.0 39 | 40 | - name: Release 41 | uses: cycjimmy/semantic-release-action@v5 42 | with: 43 | semantic_version: 25.0.0 44 | env: 45 | GITHUB_TOKEN: ${{ secrets.SEMANTIC_RELEASE_TOKEN }} 46 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/antonbabenko/pre-commit-terraform 3 | rev: v1.103.0 4 | hooks: 5 | - id: terraform_fmt 6 | - id: terraform_docs 7 | args: 8 | - '--args=--lockfile=false' 9 | - id: terraform_tflint 10 | args: 11 | - '--args=--only=terraform_deprecated_interpolation' 12 | - '--args=--only=terraform_deprecated_index' 13 | - '--args=--only=terraform_unused_declarations' 14 | - '--args=--only=terraform_comment_syntax' 15 | - '--args=--only=terraform_documented_outputs' 16 | - '--args=--only=terraform_documented_variables' 17 | - '--args=--only=terraform_typed_variables' 18 | - '--args=--only=terraform_module_pinned_source' 19 | - '--args=--only=terraform_naming_convention' 20 | - '--args=--only=terraform_required_version' 21 | - '--args=--only=terraform_required_providers' 22 | - '--args=--only=terraform_standard_module_structure' 23 | - '--args=--only=terraform_workspace_remote' 24 | - id: terraform_validate 25 | - repo: https://github.com/pre-commit/pre-commit-hooks 26 | rev: v6.0.0 27 | hooks: 28 | - id: check-merge-conflict 29 | - id: end-of-file-fixer 30 | - id: trailing-whitespace 31 | -------------------------------------------------------------------------------- /.github/workflows/stale-actions.yaml: -------------------------------------------------------------------------------- 1 | name: 'Mark or close stale issues and PRs' 2 | on: 3 | schedule: 4 | - cron: '0 0 * * *' 5 | 6 | jobs: 7 | stale: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/stale@v10 11 | with: 12 | repo-token: ${{ secrets.GITHUB_TOKEN }} 13 | # Staling issues and PR's 14 | days-before-stale: 30 15 | stale-issue-label: stale 16 | stale-pr-label: stale 17 | stale-issue-message: | 18 | This issue has been automatically marked as stale because it has been open 30 days 19 | with no activity. Remove stale label or comment or this issue will be closed in 10 days 20 | stale-pr-message: | 21 | This PR has been automatically marked as stale because it has been open 30 days 22 | with no activity. Remove stale label or comment or this PR will be closed in 10 days 23 | # Not stale if have this labels or part of milestone 24 | exempt-issue-labels: bug,wip,on-hold 25 | exempt-pr-labels: bug,wip,on-hold 26 | exempt-all-milestones: true 27 | # Close issue operations 28 | # Label will be automatically removed if the issues are no longer closed nor locked. 29 | days-before-close: 10 30 | delete-branch: true 31 | close-issue-message: This issue was automatically closed because of stale in 10 days 32 | close-pr-message: This PR was automatically closed because of stale in 10 days 33 | -------------------------------------------------------------------------------- /.github/workflows/pr-title.yml: -------------------------------------------------------------------------------- 1 | name: 'Validate PR title' 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | jobs: 11 | main: 12 | name: Validate PR title 13 | runs-on: ubuntu-latest 14 | steps: 15 | # Please look up the latest version from 16 | # https://github.com/amannn/action-semantic-pull-request/releases 17 | - uses: amannn/action-semantic-pull-request@v6.1.1 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | with: 21 | # Configure which types are allowed. 22 | # Default: https://github.com/commitizen/conventional-commit-types 23 | types: | 24 | fix 25 | feat 26 | docs 27 | ci 28 | chore 29 | # Configure that a scope must always be provided. 30 | requireScope: false 31 | # Configure additional validation for the subject based on a regex. 32 | # This example ensures the subject starts with an uppercase character. 33 | subjectPattern: ^[A-Z].+$ 34 | # If `subjectPattern` is configured, you can use this property to override 35 | # the default error message that is shown when the pattern doesn't match. 36 | # The variables `subject` and `title` can be used within the message. 37 | subjectPatternError: | 38 | The subject "{subject}" found in the pull request title "{title}" 39 | didn't match the configured pattern. Please ensure that the subject 40 | starts with an uppercase character. 41 | # For work-in-progress PRs you can typically use draft pull requests 42 | # from Github. However, private repositories on the free plan don't have 43 | # this option and therefore this action allows you to opt-in to using the 44 | # special "[WIP]" prefix to indicate this state. This will avoid the 45 | # validation of the PR title and the pull request checks remain pending. 46 | # Note that a second check will be reported if this is enabled. 47 | wip: true 48 | # When using "Squash and merge" on a PR with only one commit, GitHub 49 | # will suggest using that commit message instead of the PR title for the 50 | # merge commit, and it's easy to commit this by mistake. Enable this option 51 | # to also validate the commit message for one commit PRs. 52 | validateSingleCommit: false 53 | -------------------------------------------------------------------------------- /examples/ec2/outputs.tf: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Compute Environment(s) 3 | ################################################################################ 4 | 5 | output "compute_environments" { 6 | description = "Map of compute environments created and their associated attributes" 7 | value = module.batch.compute_environments 8 | } 9 | 10 | ################################################################################ 11 | # Compute Environment - Instance Role 12 | ################################################################################ 13 | 14 | output "instance_iam_role_name" { 15 | description = "The name of the IAM role" 16 | value = module.batch.instance_iam_role_name 17 | } 18 | 19 | output "instance_iam_role_arn" { 20 | description = "The Amazon Resource Name (ARN) specifying the IAM role" 21 | value = module.batch.instance_iam_role_arn 22 | } 23 | 24 | output "instance_iam_role_unique_id" { 25 | description = "Stable and unique string identifying the IAM role" 26 | value = module.batch.instance_iam_role_unique_id 27 | } 28 | 29 | output "instance_iam_instance_profile_arn" { 30 | description = "ARN assigned by AWS to the instance profile" 31 | value = module.batch.instance_iam_instance_profile_arn 32 | } 33 | 34 | output "instance_iam_instance_profile_id" { 35 | description = "Instance profile's ID" 36 | value = module.batch.instance_iam_instance_profile_id 37 | } 38 | 39 | output "instance_iam_instance_profile_unique" { 40 | description = "Stable and unique string identifying the IAM instance profile" 41 | value = module.batch.instance_iam_instance_profile_unique 42 | } 43 | 44 | ################################################################################ 45 | # Compute Environment - Service Role 46 | ################################################################################ 47 | 48 | output "service_iam_role_name" { 49 | description = "The name of the IAM role" 50 | value = module.batch.service_iam_role_name 51 | } 52 | 53 | output "service_iam_role_arn" { 54 | description = "The Amazon Resource Name (ARN) specifying the IAM role" 55 | value = module.batch.service_iam_role_arn 56 | } 57 | 58 | output "service_iam_role_unique_id" { 59 | description = "Stable and unique string identifying the IAM role" 60 | value = module.batch.service_iam_role_unique_id 61 | } 62 | 63 | ################################################################################ 64 | # Compute Environment - Spot Fleet Role 65 | ################################################################################ 66 | 67 | output "spot_fleet_iam_role_name" { 68 | description = "The name of the IAM role" 69 | value = module.batch.spot_fleet_iam_role_name 70 | } 71 | 72 | output "spot_fleet_iam_role_arn" { 73 | description = "The Amazon Resource Name (ARN) specifying the IAM role" 74 | value = module.batch.spot_fleet_iam_role_arn 75 | } 76 | 77 | output "spot_fleet_iam_role_unique_id" { 78 | description = "Stable and unique string identifying the IAM role" 79 | value = module.batch.spot_fleet_iam_role_unique_id 80 | } 81 | 82 | ################################################################################ 83 | # Job Queue 84 | ################################################################################ 85 | 86 | output "job_queues" { 87 | description = "Map of job queues created and their associated attributes" 88 | value = module.batch.job_queues 89 | } 90 | 91 | ################################################################################ 92 | # Scheduling Policy 93 | ################################################################################ 94 | 95 | output "scheduling_policies" { 96 | description = "Map of scheduling policies created and their associated attributes" 97 | value = module.batch.scheduling_policies 98 | } 99 | 100 | ################################################################################ 101 | # Job Definitions 102 | ################################################################################ 103 | 104 | output "job_definitions" { 105 | description = "Map of job defintions created and their associated attributes" 106 | value = module.batch.job_definitions 107 | } 108 | -------------------------------------------------------------------------------- /examples/fargate/outputs.tf: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Compute Environment(s) 3 | ################################################################################ 4 | 5 | output "compute_environments" { 6 | description = "Map of compute environments created and their associated attributes" 7 | value = module.batch.compute_environments 8 | } 9 | 10 | ################################################################################ 11 | # Compute Environment - Instance Role 12 | ################################################################################ 13 | 14 | output "instance_iam_role_name" { 15 | description = "The name of the IAM role" 16 | value = module.batch.instance_iam_role_name 17 | } 18 | 19 | output "instance_iam_role_arn" { 20 | description = "The Amazon Resource Name (ARN) specifying the IAM role" 21 | value = module.batch.instance_iam_role_arn 22 | } 23 | 24 | output "instance_iam_role_unique_id" { 25 | description = "Stable and unique string identifying the IAM role" 26 | value = module.batch.instance_iam_role_unique_id 27 | } 28 | 29 | output "instance_iam_instance_profile_arn" { 30 | description = "ARN assigned by AWS to the instance profile" 31 | value = module.batch.instance_iam_instance_profile_arn 32 | } 33 | 34 | output "instance_iam_instance_profile_id" { 35 | description = "Instance profile's ID" 36 | value = module.batch.instance_iam_instance_profile_id 37 | } 38 | 39 | output "instance_iam_instance_profile_unique" { 40 | description = "Stable and unique string identifying the IAM instance profile" 41 | value = module.batch.instance_iam_instance_profile_unique 42 | } 43 | 44 | ################################################################################ 45 | # Compute Environment - Service Role 46 | ################################################################################ 47 | 48 | output "service_iam_role_name" { 49 | description = "The name of the IAM role" 50 | value = module.batch.service_iam_role_name 51 | } 52 | 53 | output "service_iam_role_arn" { 54 | description = "The Amazon Resource Name (ARN) specifying the IAM role" 55 | value = module.batch.service_iam_role_arn 56 | } 57 | 58 | output "service_iam_role_unique_id" { 59 | description = "Stable and unique string identifying the IAM role" 60 | value = module.batch.service_iam_role_unique_id 61 | } 62 | 63 | ################################################################################ 64 | # Compute Environment - Spot Fleet Role 65 | ################################################################################ 66 | 67 | output "spot_fleet_iam_role_name" { 68 | description = "The name of the IAM role" 69 | value = module.batch.spot_fleet_iam_role_name 70 | } 71 | 72 | output "spot_fleet_iam_role_arn" { 73 | description = "The Amazon Resource Name (ARN) specifying the IAM role" 74 | value = module.batch.spot_fleet_iam_role_arn 75 | } 76 | 77 | output "spot_fleet_iam_role_unique_id" { 78 | description = "Stable and unique string identifying the IAM role" 79 | value = module.batch.spot_fleet_iam_role_unique_id 80 | } 81 | 82 | ################################################################################ 83 | # Job Queue 84 | ################################################################################ 85 | 86 | output "job_queues" { 87 | description = "Map of job queues created and their associated attributes" 88 | value = module.batch.job_queues 89 | } 90 | 91 | ################################################################################ 92 | # Scheduling Policy 93 | ################################################################################ 94 | 95 | output "scheduling_policies" { 96 | description = "Map of scheduling policies created and their associated attributes" 97 | value = module.batch.scheduling_policies 98 | } 99 | 100 | ################################################################################ 101 | # Job Definitions 102 | ################################################################################ 103 | 104 | output "job_definitions" { 105 | description = "Map of job defintions created and their associated attributes" 106 | value = module.batch.job_definitions 107 | } 108 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Compute Environment(s) 3 | ################################################################################ 4 | 5 | output "compute_environments" { 6 | description = "Map of compute environments created and their associated attributes" 7 | value = aws_batch_compute_environment.this 8 | } 9 | 10 | ################################################################################ 11 | # Compute Environment - Instance Role 12 | ################################################################################ 13 | 14 | output "instance_iam_role_name" { 15 | description = "The name of the IAM role" 16 | value = try(aws_iam_role.instance[0].name, null) 17 | } 18 | 19 | output "instance_iam_role_arn" { 20 | description = "The Amazon Resource Name (ARN) specifying the IAM role" 21 | value = try(aws_iam_role.instance[0].arn, null) 22 | } 23 | 24 | output "instance_iam_role_unique_id" { 25 | description = "Stable and unique string identifying the IAM role" 26 | value = try(aws_iam_role.instance[0].unique_id, null) 27 | } 28 | 29 | output "instance_iam_instance_profile_arn" { 30 | description = "ARN assigned by AWS to the instance profile" 31 | value = try(aws_iam_instance_profile.instance[0].arn, null) 32 | } 33 | 34 | output "instance_iam_instance_profile_id" { 35 | description = "Instance profile's ID" 36 | value = try(aws_iam_instance_profile.instance[0].id, null) 37 | } 38 | 39 | output "instance_iam_instance_profile_unique" { 40 | description = "Stable and unique string identifying the IAM instance profile" 41 | value = try(aws_iam_instance_profile.instance[0].unique_id, null) 42 | } 43 | 44 | ################################################################################ 45 | # Compute Environment - Service Role 46 | ################################################################################ 47 | 48 | output "service_iam_role_name" { 49 | description = "The name of the IAM role" 50 | value = try(aws_iam_role.service[0].name, null) 51 | } 52 | 53 | output "service_iam_role_arn" { 54 | description = "The Amazon Resource Name (ARN) specifying the IAM role" 55 | value = try(aws_iam_role.service[0].arn, null) 56 | } 57 | 58 | output "service_iam_role_unique_id" { 59 | description = "Stable and unique string identifying the IAM role" 60 | value = try(aws_iam_role.service[0].unique_id, null) 61 | } 62 | 63 | ################################################################################ 64 | # Compute Environment - Spot Fleet Role 65 | ################################################################################ 66 | 67 | output "spot_fleet_iam_role_name" { 68 | description = "The name of the IAM role" 69 | value = try(aws_iam_role.spot_fleet[0].name, null) 70 | } 71 | 72 | output "spot_fleet_iam_role_arn" { 73 | description = "The Amazon Resource Name (ARN) specifying the IAM role" 74 | value = try(aws_iam_role.spot_fleet[0].arn, null) 75 | } 76 | 77 | output "spot_fleet_iam_role_unique_id" { 78 | description = "Stable and unique string identifying the IAM role" 79 | value = try(aws_iam_role.spot_fleet[0].unique_id, null) 80 | } 81 | 82 | ################################################################################ 83 | # Job Queue 84 | ################################################################################ 85 | 86 | output "job_queues" { 87 | description = "Map of job queues created and their associated attributes" 88 | value = aws_batch_job_queue.this 89 | } 90 | 91 | ################################################################################ 92 | # Scheduling Policy 93 | ################################################################################ 94 | 95 | output "scheduling_policies" { 96 | description = "Map of scheduling policies created and their associated attributes" 97 | value = aws_batch_scheduling_policy.this 98 | } 99 | 100 | ################################################################################ 101 | # Job Definitions 102 | ################################################################################ 103 | 104 | output "job_definitions" { 105 | description = "Map of job defintions created and their associated attributes" 106 | value = aws_batch_job_definition.this 107 | } 108 | -------------------------------------------------------------------------------- /docs/UPGRADE-3.0.md: -------------------------------------------------------------------------------- 1 | # Upgrade from v2.x to v3.x 2 | 3 | If you have any questions regarding this upgrade process, please consult the `examples` directory: 4 | 5 | - [EC2](https://github.com/terraform-aws-modules/terraform-aws-batch/tree/master/examples/ec2) 6 | - [Fargate](https://github.com/terraform-aws-modules/terraform-aws-batch/tree/master/examples/fargate) 7 | 8 | If you find a bug, please open an issue with supporting configuration to reproduce. 9 | 10 | ## List of backwards incompatible changes 11 | 12 | - Terraform v1.5.7 is now minimum supported version 13 | - AWS provider v6.0.0 is now minimum supported version 14 | - `instance_iam_role_additional_policies`, `service_iam_role_additional_policies`, `spot_fleet_iam_role_additional_policies` types are now `map(string)` instead of `list(string)` 15 | - IAM assume role policy SIDs have been modified to match their use (previously all were `ECSAssumeRole` which is inaccurate) 16 | - `compute_environment_order` is now a required argument for `aws_batch_job_queue` per the Batch API and replaces `compute_environments` 17 | 18 | ## Additional changes 19 | 20 | ### Added 21 | 22 | - Support for `region` parameter to specify the AWS region for the resources created if different from the provider region. 23 | - Support for `compute_environment_order`, `job_state_time_limit_action`, `timeouts` arguments for job queues 24 | - All (currently) supported arguments for `eks_properties` argument have been added to the job definition resource 25 | - Support for `scheduling_priority` and `node_properties` arguments for job definitions 26 | 27 | ### Modified 28 | 29 | - Variable definitions now contain detailed `object` types in place of the previously used any type. 30 | - `compute_environment_name` argument has been changed to `name` per provider `v6.x` API; no-op for users 31 | - `compute_environment_name_prefix` argument has been changed to `name_prefix` per provider `v6.x` API; no-op for users 32 | 33 | ### Removed 34 | 35 | - None 36 | 37 | ### Variable and output changes 38 | 39 | 1. Removed variables: 40 | 41 | - None 42 | 43 | 2. Renamed variables: 44 | 45 | - None 46 | 47 | 3. Added variables: 48 | 49 | - None 50 | 51 | 4. Removed outputs: 52 | 53 | - None 54 | 55 | 5. Renamed outputs: 56 | 57 | - None 58 | 59 | 6. Added outputs: 60 | 61 | - None 62 | 63 | ## Upgrade State Migrations 64 | 65 | ### Before 2.x Example 66 | 67 | ```hcl 68 | module "batch" { 69 | source = "terraform-aws-modules/batch/aws" 70 | version = "2.1.0" 71 | 72 | # Truncated for brevity, only relevant module API changes are shown ... 73 | 74 | instance_iam_role_additional_policies = [ 75 | "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" 76 | ] 77 | 78 | compute_environments = { 79 | a_ec2 = { 80 | ... # Other properties for a_ec2 compute environment 81 | } 82 | 83 | b_ec2_spot = { 84 | ... # Other properties for b_ec2_spot compute environment 85 | } 86 | } 87 | 88 | tags = local.tags 89 | } 90 | ``` 91 | 92 | ### After 3.x Example 93 | 94 | ```hcl 95 | module "batch" { 96 | source = "terraform-aws-modules/batch/aws" 97 | version = "3.0.0" 98 | 99 | # Truncated for brevity, only relevant module API changes are shown ... 100 | 101 | instance_iam_role_additional_policies = { 102 | AmazonSSMManagedInstanceCore = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" 103 | } 104 | 105 | compute_environments = { 106 | a_ec2 = { 107 | ... # Other properties for a_ec2 compute environment 108 | } 109 | 110 | b_ec2_spot = { 111 | ... # Other properties for b_ec2_spot compute environment 112 | } 113 | } 114 | # Now required 115 | compute_environment_order = { 116 | 0 = { 117 | compute_environment_key = "a_ec2" 118 | } 119 | 1 = { 120 | compute_environment_key = "b_ec2_spot" 121 | } 122 | } 123 | 124 | tags = local.tags 125 | } 126 | ``` 127 | 128 | To migrate from the `v2.x` version to `v3.x` version example shown above, the following state move commands can be performed to maintain the current resources without modification: 129 | 130 | ```bash 131 | # For each additional policy in instance_iam_role_additional_policies, simply move the prior value to the new key you have defined in your configuration 132 | # This can be done similarly for aws_iam_role_policy_attachment.service and aws_iam_role_policy_attachment.spot_fleet 133 | terraform state mv \ 134 | 'module.batch.aws_iam_role_policy_attachment.instance["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"]' \ 135 | 'module.batch.aws_iam_role_policy_attachment.instance["AmazonSSMManagedInstanceCore"]' 136 | ``` 137 | -------------------------------------------------------------------------------- /examples/ec2/README.md: -------------------------------------------------------------------------------- 1 | # AWS Batch Example - EC2 2 | 3 | Configuration in this directory creates: 4 | 5 | - AWS Batch compute environments using managed EC2, managed EC2 Spot, and unmanaged EC2 6 | - AWS Batch job queue for high priority tasks with scheduling policy 7 | - AWS Batch job queue for low priority tasks 8 | - AWS Batch job definition using busybox container image 9 | 10 | ## Usage 11 | 12 | To run this example you need to execute: 13 | 14 | ```bash 15 | $ terraform init 16 | $ terraform plan 17 | $ terraform apply 18 | ``` 19 | 20 | Note that this example may create resources which will incur monetary charges on your AWS bill. Run `terraform destroy` when you no longer need these resources. 21 | 22 | 23 | ## Requirements 24 | 25 | | Name | Version | 26 | |------|---------| 27 | | [terraform](#requirement\_terraform) | >= 1.5.7 | 28 | | [aws](#requirement\_aws) | >= 6.0 | 29 | 30 | ## Providers 31 | 32 | | Name | Version | 33 | |------|---------| 34 | | [aws](#provider\_aws) | >= 6.0 | 35 | 36 | ## Modules 37 | 38 | | Name | Source | Version | 39 | |------|--------|---------| 40 | | [batch](#module\_batch) | ../.. | n/a | 41 | | [batch\_disabled](#module\_batch\_disabled) | ../.. | n/a | 42 | | [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 6.0 | 43 | | [vpc\_endpoints](#module\_vpc\_endpoints) | terraform-aws-modules/vpc/aws//modules/vpc-endpoints | ~> 6.0 | 44 | 45 | ## Resources 46 | 47 | | Name | Type | 48 | |------|------| 49 | | [aws_cloudwatch_log_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | 50 | | [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | 51 | 52 | ## Inputs 53 | 54 | No inputs. 55 | 56 | ## Outputs 57 | 58 | | Name | Description | 59 | |------|-------------| 60 | | [compute\_environments](#output\_compute\_environments) | Map of compute environments created and their associated attributes | 61 | | [instance\_iam\_instance\_profile\_arn](#output\_instance\_iam\_instance\_profile\_arn) | ARN assigned by AWS to the instance profile | 62 | | [instance\_iam\_instance\_profile\_id](#output\_instance\_iam\_instance\_profile\_id) | Instance profile's ID | 63 | | [instance\_iam\_instance\_profile\_unique](#output\_instance\_iam\_instance\_profile\_unique) | Stable and unique string identifying the IAM instance profile | 64 | | [instance\_iam\_role\_arn](#output\_instance\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role | 65 | | [instance\_iam\_role\_name](#output\_instance\_iam\_role\_name) | The name of the IAM role | 66 | | [instance\_iam\_role\_unique\_id](#output\_instance\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | 67 | | [job\_definitions](#output\_job\_definitions) | Map of job defintions created and their associated attributes | 68 | | [job\_queues](#output\_job\_queues) | Map of job queues created and their associated attributes | 69 | | [scheduling\_policies](#output\_scheduling\_policies) | Map of scheduling policies created and their associated attributes | 70 | | [service\_iam\_role\_arn](#output\_service\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role | 71 | | [service\_iam\_role\_name](#output\_service\_iam\_role\_name) | The name of the IAM role | 72 | | [service\_iam\_role\_unique\_id](#output\_service\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | 73 | | [spot\_fleet\_iam\_role\_arn](#output\_spot\_fleet\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role | 74 | | [spot\_fleet\_iam\_role\_name](#output\_spot\_fleet\_iam\_role\_name) | The name of the IAM role | 75 | | [spot\_fleet\_iam\_role\_unique\_id](#output\_spot\_fleet\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | 76 | 77 | 78 | Apache-2.0 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-batch/blob/master/LICENSE). 79 | -------------------------------------------------------------------------------- /examples/fargate/README.md: -------------------------------------------------------------------------------- 1 | # AWS Batch Example - Fargate 2 | 3 | Configuration in this directory creates: 4 | 5 | - AWS Batch compute environments using Fargate and Fargate Spot 6 | - AWS Batch job queue for high priority tasks with scheduling policy 7 | - AWS Batch job queue for low priority tasks 8 | - AWS Batch job definition using busybox container image 9 | 10 | ## Usage 11 | 12 | To run this example you need to execute: 13 | 14 | ```bash 15 | $ terraform init 16 | $ terraform plan 17 | $ terraform apply 18 | ``` 19 | 20 | Note that this example may create resources which will incur monetary charges on your AWS bill. Run `terraform destroy` when you no longer need these resources. 21 | 22 | 23 | ## Requirements 24 | 25 | | Name | Version | 26 | |------|---------| 27 | | [terraform](#requirement\_terraform) | >= 1.5.7 | 28 | | [aws](#requirement\_aws) | >= 6.0 | 29 | 30 | ## Providers 31 | 32 | | Name | Version | 33 | |------|---------| 34 | | [aws](#provider\_aws) | >= 6.0 | 35 | 36 | ## Modules 37 | 38 | | Name | Source | Version | 39 | |------|--------|---------| 40 | | [batch](#module\_batch) | ../.. | n/a | 41 | | [batch\_disabled](#module\_batch\_disabled) | ../.. | n/a | 42 | | [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 6.0 | 43 | | [vpc\_endpoints](#module\_vpc\_endpoints) | terraform-aws-modules/vpc/aws//modules/vpc-endpoints | ~> 6.0 | 44 | 45 | ## Resources 46 | 47 | | Name | Type | 48 | |------|------| 49 | | [aws_cloudwatch_log_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | 50 | | [aws_iam_role.ecs_task_execution_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | 51 | | [aws_iam_role_policy_attachment.ecs_task_execution_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 52 | | [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | 53 | | [aws_iam_policy_document.ecs_task_execution_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 54 | 55 | ## Inputs 56 | 57 | No inputs. 58 | 59 | ## Outputs 60 | 61 | | Name | Description | 62 | |------|-------------| 63 | | [compute\_environments](#output\_compute\_environments) | Map of compute environments created and their associated attributes | 64 | | [instance\_iam\_instance\_profile\_arn](#output\_instance\_iam\_instance\_profile\_arn) | ARN assigned by AWS to the instance profile | 65 | | [instance\_iam\_instance\_profile\_id](#output\_instance\_iam\_instance\_profile\_id) | Instance profile's ID | 66 | | [instance\_iam\_instance\_profile\_unique](#output\_instance\_iam\_instance\_profile\_unique) | Stable and unique string identifying the IAM instance profile | 67 | | [instance\_iam\_role\_arn](#output\_instance\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role | 68 | | [instance\_iam\_role\_name](#output\_instance\_iam\_role\_name) | The name of the IAM role | 69 | | [instance\_iam\_role\_unique\_id](#output\_instance\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | 70 | | [job\_definitions](#output\_job\_definitions) | Map of job defintions created and their associated attributes | 71 | | [job\_queues](#output\_job\_queues) | Map of job queues created and their associated attributes | 72 | | [scheduling\_policies](#output\_scheduling\_policies) | Map of scheduling policies created and their associated attributes | 73 | | [service\_iam\_role\_arn](#output\_service\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role | 74 | | [service\_iam\_role\_name](#output\_service\_iam\_role\_name) | The name of the IAM role | 75 | | [service\_iam\_role\_unique\_id](#output\_service\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | 76 | | [spot\_fleet\_iam\_role\_arn](#output\_spot\_fleet\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role | 77 | | [spot\_fleet\_iam\_role\_name](#output\_spot\_fleet\_iam\_role\_name) | The name of the IAM role | 78 | | [spot\_fleet\_iam\_role\_unique\_id](#output\_spot\_fleet\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | 79 | 80 | 81 | Apache-2.0 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-batch/blob/master/LICENSE). 82 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml: -------------------------------------------------------------------------------- 1 | name: Pre-Commit 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | - master 8 | 9 | env: 10 | TERRAFORM_DOCS_VERSION: v0.20.0 11 | TFLINT_VERSION: v0.59.1 12 | 13 | jobs: 14 | collectInputs: 15 | name: Collect workflow inputs 16 | runs-on: ubuntu-latest 17 | outputs: 18 | directories: ${{ steps.dirs.outputs.directories }} 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v5 22 | 23 | - name: Get root directories 24 | id: dirs 25 | uses: clowdhaus/terraform-composite-actions/directories@v1.14.0 26 | 27 | preCommitMinVersions: 28 | name: Min TF pre-commit 29 | needs: collectInputs 30 | runs-on: ubuntu-latest 31 | strategy: 32 | matrix: 33 | directory: ${{ fromJson(needs.collectInputs.outputs.directories) }} 34 | steps: 35 | - name: Install rmz 36 | uses: jaxxstorm/action-install-gh-release@v2.1.0 37 | with: 38 | repo: SUPERCILEX/fuc 39 | asset-name: x86_64-unknown-linux-gnu-rmz 40 | rename-to: rmz 41 | chmod: 0755 42 | extension-matching: disable 43 | 44 | # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449 45 | - name: Delete unnecessary files 46 | run: | 47 | formatByteCount() { echo $(numfmt --to=iec-i --suffix=B --padding=7 $1'000'); } 48 | getAvailableSpace() { echo $(df -a $1 | awk 'NR > 1 {avail+=$4} END {print avail}'); } 49 | 50 | BEFORE=$(getAvailableSpace) 51 | 52 | ln -s /opt/hostedtoolcache/SUPERCILEX/x86_64-unknown-linux-gnu-rmz/latest/linux-x64/rmz /usr/local/bin/rmz 53 | rmz -f /opt/hostedtoolcache/CodeQL & 54 | rmz -f /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk & 55 | rmz -f /opt/hostedtoolcache/PyPy & 56 | rmz -f /opt/hostedtoolcache/Ruby & 57 | rmz -f /opt/hostedtoolcache/go & 58 | 59 | wait 60 | 61 | AFTER=$(getAvailableSpace) 62 | SAVED=$((AFTER-BEFORE)) 63 | echo "=> Saved $(formatByteCount $SAVED)" 64 | 65 | - name: Checkout 66 | uses: actions/checkout@v5 67 | 68 | - name: Terraform min/max versions 69 | id: minMax 70 | uses: clowdhaus/terraform-min-max@v2.1.0 71 | with: 72 | directory: ${{ matrix.directory }} 73 | 74 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.minVersion }} 75 | # Run only validate pre-commit check on min version supported 76 | if: ${{ matrix.directory != '.' }} 77 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.14.0 78 | with: 79 | terraform-version: ${{ steps.minMax.outputs.minVersion }} 80 | tflint-version: ${{ env.TFLINT_VERSION }} 81 | args: 'terraform_validate --color=always --show-diff-on-failure --files ${{ matrix.directory }}/*' 82 | 83 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.minVersion }} 84 | # Run only validate pre-commit check on min version supported 85 | if: ${{ matrix.directory == '.' }} 86 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.14.0 87 | with: 88 | terraform-version: ${{ steps.minMax.outputs.minVersion }} 89 | tflint-version: ${{ env.TFLINT_VERSION }} 90 | args: 'terraform_validate --color=always --show-diff-on-failure --files $(ls *.tf)' 91 | 92 | preCommitMaxVersion: 93 | name: Max TF pre-commit 94 | runs-on: ubuntu-latest 95 | needs: collectInputs 96 | steps: 97 | - name: Install rmz 98 | uses: jaxxstorm/action-install-gh-release@v2.1.0 99 | with: 100 | repo: SUPERCILEX/fuc 101 | asset-name: x86_64-unknown-linux-gnu-rmz 102 | rename-to: rmz 103 | chmod: 0755 104 | extension-matching: disable 105 | 106 | # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449 107 | - name: Delete unnecessary files 108 | run: | 109 | formatByteCount() { echo $(numfmt --to=iec-i --suffix=B --padding=7 $1'000'); } 110 | getAvailableSpace() { echo $(df -a $1 | awk 'NR > 1 {avail+=$4} END {print avail}'); } 111 | 112 | BEFORE=$(getAvailableSpace) 113 | 114 | ln -s /opt/hostedtoolcache/SUPERCILEX/x86_64-unknown-linux-gnu-rmz/latest/linux-x64/rmz /usr/local/bin/rmz 115 | rmz -f /opt/hostedtoolcache/CodeQL & 116 | rmz -f /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk & 117 | rmz -f /opt/hostedtoolcache/PyPy & 118 | rmz -f /opt/hostedtoolcache/Ruby & 119 | rmz -f /opt/hostedtoolcache/go & 120 | sudo rmz -f /usr/local/lib/android & 121 | 122 | if [[ ${{ github.repository }} == terraform-aws-modules/terraform-aws-security-group ]]; then 123 | sudo rmz -f /usr/share/dotnet & 124 | sudo rmz -f /usr/local/.ghcup & 125 | sudo apt-get -qq remove -y 'azure-.*' 126 | sudo apt-get -qq remove -y 'cpp-.*' 127 | sudo apt-get -qq remove -y 'dotnet-runtime-.*' 128 | sudo apt-get -qq remove -y 'google-.*' 129 | sudo apt-get -qq remove -y 'libclang-.*' 130 | sudo apt-get -qq remove -y 'libllvm.*' 131 | sudo apt-get -qq remove -y 'llvm-.*' 132 | sudo apt-get -qq remove -y 'mysql-.*' 133 | sudo apt-get -qq remove -y 'postgresql-.*' 134 | sudo apt-get -qq remove -y 'php.*' 135 | sudo apt-get -qq remove -y 'temurin-.*' 136 | sudo apt-get -qq remove -y kubectl firefox mono-devel 137 | sudo apt-get -qq autoremove -y 138 | sudo apt-get -qq clean 139 | fi 140 | 141 | wait 142 | 143 | AFTER=$(getAvailableSpace) 144 | SAVED=$((AFTER-BEFORE)) 145 | echo "=> Saved $(formatByteCount $SAVED)" 146 | 147 | - name: Checkout 148 | uses: actions/checkout@v5 149 | with: 150 | ref: ${{ github.event.pull_request.head.ref }} 151 | repository: ${{github.event.pull_request.head.repo.full_name}} 152 | 153 | - name: Terraform min/max versions 154 | id: minMax 155 | uses: clowdhaus/terraform-min-max@v2.1.0 156 | 157 | - name: Hide template dir 158 | # Special to this repo, we don't want to check this dir 159 | if: ${{ github.repository == 'terraform-aws-modules/terraform-aws-security-group' }} 160 | run: rm -rf modules/_templates 161 | 162 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.maxVersion }} 163 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.14.0 164 | with: 165 | terraform-version: ${{ steps.minMax.outputs.maxVersion }} 166 | tflint-version: ${{ env.TFLINT_VERSION }} 167 | terraform-docs-version: ${{ env.TERRAFORM_DOCS_VERSION }} 168 | install-hcledit: true 169 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [3.0.5](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v3.0.4...v3.0.5) (2025-10-21) 6 | 7 | ### Bug Fixes 8 | 9 | * Update CI workflow versions to latest ([#50](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/50)) ([71b03c6](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/71b03c6a0d023cfb8b0d2ebdc5ca59b34ae3d6fc)) 10 | 11 | ## [3.0.4](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v3.0.3...v3.0.4) (2025-08-25) 12 | 13 | 14 | ### Bug Fixes 15 | 16 | * Correct attribute name for external spot IAM role ([#49](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/49)) ([44828cb](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/44828cbe2e18e57b2be54ddb6be98e886d97a4b9)) 17 | 18 | ## [3.0.3](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v3.0.2...v3.0.3) (2025-07-05) 19 | 20 | 21 | ### Bug Fixes 22 | 23 | * Ensure a list of attributes can be used on `ec2_configuration` ([#47](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/47)) ([67d405f](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/67d405f14892f314512ff09119513e9bcf81da91)) 24 | 25 | ## [3.0.2](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v3.0.1...v3.0.2) (2025-07-01) 26 | 27 | 28 | ### Bug Fixes 29 | 30 | * Remove erroneous `pod_properties` scoping from job definition variable attribute structure ([#45](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/45)) ([7c8becf](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/7c8becf486af35d9b14aa71299bc3c8f3b4fbe85)) 31 | 32 | ## [3.0.1](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v3.0.0...v3.0.1) (2025-06-27) 33 | 34 | 35 | ### Bug Fixes 36 | 37 | * Correct launch template attribute values to match variable/API definition ([#43](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/43)) ([3a07ad9](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/3a07ad9f7cbe90011c36ba75c209a81ee1d8b1c4)) 38 | 39 | ## [3.0.0](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v2.1.0...v3.0.0) (2025-06-25) 40 | 41 | 42 | ### ⚠ BREAKING CHANGES 43 | 44 | * Upgrade AWS provider and min required Terraform version to `6.0` and `1.5.7` respectively (#38) 45 | 46 | ### Features 47 | 48 | * Upgrade AWS provider and min required Terraform version to `6.0` and `1.5.7` respectively ([#38](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/38)) ([7781147](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/778114769cb5b1b8096ccb701fc2db3ffee83362)) 49 | 50 | 51 | ### Bug Fixes 52 | 53 | * Update CI workflow versions to latest ([#36](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/36)) ([c478369](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/c478369fdc5a73bbe334b6159fbce7e9a0937198)) 54 | 55 | ## [2.1.0](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v2.0.3...v2.1.0) (2024-08-19) 56 | 57 | 58 | ### Features 59 | 60 | * Add support for `eks_configuration` ([#32](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/32)) ([b6aa7e1](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/b6aa7e107d1da94afb6453f787bc4d8898b2063e)) 61 | 62 | ## [2.0.3](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v2.0.2...v2.0.3) (2024-03-07) 63 | 64 | 65 | ### Bug Fixes 66 | 67 | * Update CI workflow versions to remove deprecated runtime warnings ([#27](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/27)) ([64b1ba1](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/64b1ba12df6c677b682f665f9a0a3c8c9dd8c750)) 68 | 69 | ### [2.0.2](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v2.0.1...v2.0.2) (2023-12-11) 70 | 71 | 72 | ### Bug Fixes 73 | 74 | * Rename launch template parameters ([#25](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/25)) ([3e370d0](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/3e370d06bf4a7303a2bde56c0344b2e092fb6b0e)) 75 | 76 | ### [2.0.1](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v2.0.0...v2.0.1) (2023-05-03) 77 | 78 | 79 | ### Bug Fixes 80 | 81 | * Change `instance_iam_role_use_name_prefix` to use correct data type ([#20](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/20)) ([08a13f1](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/08a13f1a2d7722fb89daf16f25398c4be205f3a9)) 82 | 83 | ## [2.0.0](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v1.2.3...v2.0.0) (2023-04-28) 84 | 85 | 86 | ### ⚠ BREAKING CHANGES 87 | 88 | * Bump Terraform version to 1.0, and allow specifying compute environments for queue (#19) 89 | 90 | ### Features 91 | 92 | * Bump Terraform version to 1.0, and allow specifying compute environments for queue ([#19](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/19)) ([8cec4e7](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/8cec4e7ed047bc20e317b007abf67f4027532dc1)) 93 | 94 | ### [1.2.3](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v1.2.2...v1.2.3) (2023-04-27) 95 | 96 | 97 | ### Bug Fixes 98 | 99 | * Add `create_before_destroy` lifecycle hook to `aws_batch_compute_environment` ([#18](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/18)) ([614fc14](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/614fc14f1be07a21a5de7a8dc0f477bf001a3519)) 100 | 101 | ### [1.2.2](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v1.2.1...v1.2.2) (2023-01-24) 102 | 103 | 104 | ### Bug Fixes 105 | 106 | * Use a version for to avoid GitHub API rate limiting on CI workflows ([#10](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/10)) ([8205095](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/8205095e4888aea3238d4f62c9a042839ccae39b)) 107 | 108 | ### [1.2.1](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v1.2.0...v1.2.1) (2022-10-27) 109 | 110 | 111 | ### Bug Fixes 112 | 113 | * Update CI configuration files to use latest version ([#8](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/8)) ([5d739d0](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/5d739d077ad5940b140cd071f7948f0c0b5d9623)) 114 | 115 | ## [1.2.0](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v1.1.2...v1.2.0) (2022-07-19) 116 | 117 | 118 | ### Features 119 | 120 | * Add create_scheduling_policy option to job_queue ([#3](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/3)) ([86546af](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/86546af08a5791149693374e9206fb5166914b37)) 121 | 122 | ### [1.1.2](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v1.1.1...v1.1.2) (2022-07-04) 123 | 124 | 125 | ### Bug Fixes 126 | 127 | * Add default for tag lookup in job queue resources. ([#2](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/2)) ([edb1b75](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/edb1b751913f612aa9e93891976ff677a3fee4fc)) 128 | 129 | ### [1.1.1](https://github.com/terraform-aws-modules/terraform-aws-batch/compare/v1.1.0...v1.1.1) (2022-04-21) 130 | 131 | 132 | ### Bug Fixes 133 | 134 | * Update documentation to remove prior notice and deprecated workflow ([#1](https://github.com/terraform-aws-modules/terraform-aws-batch/issues/1)) ([0240a55](https://github.com/terraform-aws-modules/terraform-aws-batch/commit/0240a554cb3be716339facc3e8d6f9e3711815d0)) 135 | 136 | ## [1.1.0](https://github.com/clowdhaus/terraform-aws-batch/compare/v1.0.1...v1.1.0) (2022-04-20) 137 | 138 | 139 | ### Features 140 | 141 | * Repo has moved to [terraform-aws-modules](https://github.com/terraform-aws-modules/terraform-aws-batch) organization ([0a06907](https://github.com/clowdhaus/terraform-aws-batch/commit/0a069071da5cc744cae2fbc3b335a9c918dd6357)) 142 | -------------------------------------------------------------------------------- /examples/fargate/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = local.region 3 | } 4 | 5 | data "aws_availability_zones" "available" {} 6 | 7 | locals { 8 | region = "us-east-1" 9 | name = "batch-ex-${basename(path.cwd)}" 10 | 11 | vpc_cidr = "10.0.0.0/16" 12 | azs = slice(data.aws_availability_zones.available.names, 0, 3) 13 | 14 | tags = { 15 | Name = local.name 16 | Example = local.name 17 | Repository = "https://github.com/terraform-aws-modules/terraform-aws-batch" 18 | } 19 | } 20 | 21 | ################################################################################ 22 | # Batch Module 23 | ################################################################################ 24 | 25 | module "batch_disabled" { 26 | source = "../.." 27 | 28 | create = false 29 | } 30 | 31 | module "batch" { 32 | source = "../.." 33 | 34 | instance_iam_role_name = "${local.name}-ecs-instance" 35 | instance_iam_role_path = "/batch/" 36 | instance_iam_role_description = "IAM instance role/profile for AWS Batch ECS instance(s)" 37 | instance_iam_role_tags = { 38 | ModuleCreatedRole = "Yes" 39 | } 40 | 41 | service_iam_role_name = "${local.name}-batch" 42 | service_iam_role_path = "/batch/" 43 | service_iam_role_description = "IAM service role for AWS Batch" 44 | service_iam_role_tags = { 45 | ModuleCreatedRole = "Yes" 46 | } 47 | 48 | create_spot_fleet_iam_role = true 49 | spot_fleet_iam_role_name = "${local.name}-spot" 50 | spot_fleet_iam_role_path = "/batch/" 51 | spot_fleet_iam_role_description = "IAM spot fleet role for AWS Batch" 52 | spot_fleet_iam_role_tags = { 53 | ModuleCreatedRole = "Yes" 54 | } 55 | 56 | compute_environments = { 57 | a_fargate = { 58 | name_prefix = "fargate" 59 | 60 | compute_resources = { 61 | type = "FARGATE" 62 | max_vcpus = 4 63 | 64 | security_group_ids = [module.vpc_endpoints.security_group_id] 65 | subnets = module.vpc.private_subnets 66 | 67 | # `tags = {}` here is not applicable for spot 68 | } 69 | } 70 | 71 | b_fargate_spot = { 72 | name_prefix = "fargate_spot" 73 | 74 | compute_resources = { 75 | type = "FARGATE_SPOT" 76 | max_vcpus = 4 77 | 78 | security_group_ids = [module.vpc_endpoints.security_group_id] 79 | subnets = module.vpc.private_subnets 80 | 81 | # `tags = {}` here is not applicable for spot 82 | } 83 | } 84 | } 85 | 86 | # Job queus and scheduling policies 87 | job_queues = { 88 | low_priority = { 89 | name = "LowPriorityFargate" 90 | state = "ENABLED" 91 | priority = 1 92 | 93 | compute_environment_order = { 94 | 0 = { 95 | compute_environment_key = "b_fargate_spot" 96 | } 97 | 1 = { 98 | compute_environment_key = "a_fargate" 99 | } 100 | } 101 | 102 | tags = { 103 | JobQueue = "Low priority job queue" 104 | } 105 | } 106 | 107 | high_priority = { 108 | name = "HighPriorityFargate" 109 | state = "ENABLED" 110 | priority = 99 111 | 112 | compute_environment_order = { 113 | 0 = { 114 | compute_environment_key = "a_fargate" 115 | } 116 | } 117 | 118 | fair_share_policy = { 119 | compute_reservation = 1 120 | share_decay_seconds = 3600 121 | 122 | share_distribution = [{ 123 | share_identifier = "A1*" 124 | weight_factor = 0.1 125 | }, { 126 | share_identifier = "A2" 127 | weight_factor = 0.2 128 | }] 129 | } 130 | 131 | tags = { 132 | JobQueue = "High priority job queue" 133 | } 134 | } 135 | } 136 | 137 | job_definitions = { 138 | example = { 139 | name = local.name 140 | propagate_tags = true 141 | platform_capabilities = ["FARGATE"] 142 | 143 | container_properties = jsonencode({ 144 | command = ["ls", "-la"] 145 | image = "public.ecr.aws/runecast/busybox:1.33.1" 146 | fargatePlatformConfiguration = { 147 | platformVersion = "LATEST" 148 | }, 149 | resourceRequirements = [ 150 | { type = "VCPU", value = "1" }, 151 | { type = "MEMORY", value = "2048" } 152 | ], 153 | executionRoleArn = aws_iam_role.ecs_task_execution_role.arn 154 | logConfiguration = { 155 | logDriver = "awslogs" 156 | options = { 157 | awslogs-group = aws_cloudwatch_log_group.this.id 158 | awslogs-region = local.region 159 | awslogs-stream-prefix = local.name 160 | } 161 | } 162 | }) 163 | 164 | attempt_duration_seconds = 60 165 | retry_strategy = { 166 | attempts = 3 167 | evaluate_on_exit = { 168 | retry_error = { 169 | action = "RETRY" 170 | on_exit_code = 1 171 | } 172 | exit_success = { 173 | action = "EXIT" 174 | on_exit_code = 0 175 | } 176 | } 177 | } 178 | 179 | tags = { 180 | JobDefinition = "Example" 181 | } 182 | } 183 | } 184 | 185 | tags = local.tags 186 | } 187 | 188 | ################################################################################ 189 | # Supporting Resources 190 | ################################################################################ 191 | 192 | module "vpc" { 193 | source = "terraform-aws-modules/vpc/aws" 194 | version = "~> 6.0" 195 | 196 | name = local.name 197 | cidr = local.vpc_cidr 198 | 199 | azs = local.azs 200 | private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)] 201 | public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)] 202 | 203 | enable_nat_gateway = true 204 | single_nat_gateway = true 205 | 206 | tags = local.tags 207 | } 208 | 209 | module "vpc_endpoints" { 210 | source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints" 211 | version = "~> 6.0" 212 | 213 | vpc_id = module.vpc.vpc_id 214 | 215 | # Security group 216 | create_security_group = true 217 | security_group_name_prefix = "${local.name}-vpc-endpoints-" 218 | security_group_description = "VPC endpoint security group" 219 | security_group_rules = { 220 | ingress_https = { 221 | description = "HTTPS from VPC" 222 | cidr_blocks = [module.vpc.vpc_cidr_block] 223 | } 224 | } 225 | 226 | endpoints = merge( 227 | { 228 | s3 = { 229 | service = "s3" 230 | service_type = "Gateway" 231 | route_table_ids = module.vpc.private_route_table_ids 232 | tags = { 233 | Name = "${local.name}-s3" 234 | } 235 | } 236 | }, 237 | { 238 | for service in toset(["ecr.api", "ecr.dkr", "ecs"]) : 239 | replace(service, ".", "_") => 240 | { 241 | service = service 242 | subnet_ids = module.vpc.private_subnets 243 | private_dns_enabled = true 244 | tags = { Name = "${local.name}-${service}" } 245 | } 246 | } 247 | ) 248 | 249 | tags = local.tags 250 | } 251 | 252 | resource "aws_iam_role" "ecs_task_execution_role" { 253 | name = "${local.name}-ecs-task-exec" 254 | assume_role_policy = data.aws_iam_policy_document.ecs_task_execution_role.json 255 | } 256 | 257 | data "aws_iam_policy_document" "ecs_task_execution_role" { 258 | statement { 259 | actions = ["sts:AssumeRole"] 260 | 261 | principals { 262 | type = "Service" 263 | identifiers = ["ecs-tasks.amazonaws.com"] 264 | } 265 | } 266 | } 267 | 268 | resource "aws_iam_role_policy_attachment" "ecs_task_execution_role" { 269 | role = aws_iam_role.ecs_task_execution_role.name 270 | policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" 271 | } 272 | 273 | resource "aws_cloudwatch_log_group" "this" { 274 | name = "/aws/batch/${local.name}" 275 | retention_in_days = 1 276 | 277 | tags = local.tags 278 | } 279 | -------------------------------------------------------------------------------- /examples/ec2/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = local.region 3 | } 4 | 5 | data "aws_availability_zones" "available" {} 6 | 7 | locals { 8 | region = "us-east-1" 9 | name = "batch-ex-${basename(path.cwd)}" 10 | 11 | vpc_cidr = "10.0.0.0/16" 12 | azs = slice(data.aws_availability_zones.available.names, 0, 3) 13 | 14 | tags = { 15 | Name = local.name 16 | Example = local.name 17 | Repository = "https://github.com/terraform-aws-modules/terraform-aws-batch" 18 | } 19 | } 20 | 21 | ################################################################################ 22 | # Batch Module 23 | ################################################################################ 24 | 25 | module "batch_disabled" { 26 | source = "../.." 27 | 28 | create = false 29 | } 30 | 31 | module "batch" { 32 | source = "../.." 33 | 34 | instance_iam_role_name = "${local.name}-ecs-instance" 35 | instance_iam_role_path = "/batch/" 36 | instance_iam_role_description = "IAM instance role/profile for AWS Batch ECS instance(s)" 37 | instance_iam_role_additional_policies = { 38 | AmazonSSMManagedInstanceCore = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" 39 | } 40 | instance_iam_role_tags = { 41 | ModuleCreatedRole = "Yes" 42 | } 43 | 44 | service_iam_role_name = "${local.name}-batch" 45 | service_iam_role_path = "/batch/" 46 | service_iam_role_description = "IAM service role for AWS Batch" 47 | service_iam_role_tags = { 48 | ModuleCreatedRole = "Yes" 49 | } 50 | 51 | create_spot_fleet_iam_role = true 52 | spot_fleet_iam_role_name = "${local.name}-spot" 53 | spot_fleet_iam_role_path = "/batch/" 54 | spot_fleet_iam_role_description = "IAM spot fleet role for AWS Batch" 55 | spot_fleet_iam_role_tags = { 56 | ModuleCreatedRole = "Yes" 57 | } 58 | 59 | compute_environments = { 60 | a_ec2 = { 61 | name_prefix = "ec2" 62 | 63 | compute_resources = { 64 | type = "EC2" 65 | min_vcpus = 4 66 | max_vcpus = 16 67 | desired_vcpus = 4 68 | instance_types = ["m5.large", "r5.large"] 69 | 70 | security_group_ids = [module.vpc_endpoints.security_group_id] 71 | subnets = module.vpc.private_subnets 72 | 73 | # Note - any tag changes here will force compute environment replacement 74 | # which can lead to job queue conflicts. Only specify tags that will be static 75 | # for the lifetime of the compute environment 76 | tags = { 77 | # This will set the name on the Ec2 instances launched by this compute environment 78 | Name = local.name 79 | Type = "Ec2" 80 | } 81 | } 82 | } 83 | 84 | b_ec2_spot = { 85 | name_prefix = "ec2_spot" 86 | 87 | compute_resources = { 88 | type = "SPOT" 89 | allocation_strategy = "SPOT_CAPACITY_OPTIMIZED" 90 | bid_percentage = 20 91 | 92 | min_vcpus = 4 93 | max_vcpus = 16 94 | desired_vcpus = 4 95 | instance_types = ["m4.large", "m3.large", "r4.large", "r3.large"] 96 | 97 | security_group_ids = [module.vpc_endpoints.security_group_id] 98 | subnets = module.vpc.private_subnets 99 | 100 | # Note - any tag changes here will force compute environment replacement 101 | # which can lead to job queue conflicts. Only specify tags that will be static 102 | # for the lifetime of the compute environment 103 | tags = { 104 | # This will set the name on the Ec2 instances launched by this compute environment 105 | Name = "${local.name}-spot" 106 | Type = "Ec2Spot" 107 | } 108 | } 109 | } 110 | 111 | c_unmanaged = { 112 | name_prefix = "ec2_unmanaged" 113 | type = "UNMANAGED" 114 | } 115 | } 116 | 117 | # Job queus and scheduling policies 118 | job_queues = { 119 | low_priority = { 120 | name = "LowPriorityEc2" 121 | state = "ENABLED" 122 | priority = 1 123 | 124 | compute_environment_order = { 125 | 0 = { 126 | compute_environment_key = "b_ec2_spot" 127 | } 128 | 1 = { 129 | compute_environment_key = "a_ec2" 130 | } 131 | } 132 | 133 | tags = { 134 | JobQueue = "Low priority job queue" 135 | } 136 | } 137 | 138 | high_priority = { 139 | name = "HighPriorityEc2" 140 | state = "ENABLED" 141 | priority = 99 142 | 143 | compute_environment_order = { 144 | 0 = { 145 | compute_environment_key = "a_ec2" 146 | } 147 | } 148 | 149 | fair_share_policy = { 150 | compute_reservation = 1 151 | share_decay_seconds = 3600 152 | 153 | share_distribution = [{ 154 | share_identifier = "A1*" 155 | weight_factor = 0.1 156 | }, { 157 | share_identifier = "A2" 158 | weight_factor = 0.2 159 | }] 160 | } 161 | 162 | tags = { 163 | JobQueue = "High priority job queue" 164 | } 165 | } 166 | } 167 | 168 | job_definitions = { 169 | example = { 170 | name = local.name 171 | propagate_tags = true 172 | 173 | container_properties = jsonencode({ 174 | command = ["ls", "-la"] 175 | image = "public.ecr.aws/runecast/busybox:1.33.1" 176 | resourceRequirements = [ 177 | { type = "VCPU", value = "1" }, 178 | { type = "MEMORY", value = "1024" } 179 | ] 180 | logConfiguration = { 181 | logDriver = "awslogs" 182 | options = { 183 | awslogs-group = aws_cloudwatch_log_group.this.id 184 | awslogs-region = local.region 185 | awslogs-stream-prefix = local.name 186 | } 187 | } 188 | }) 189 | 190 | attempt_duration_seconds = 60 191 | retry_strategy = { 192 | attempts = 3 193 | evaluate_on_exit = { 194 | retry_error = { 195 | action = "RETRY" 196 | on_exit_code = 1 197 | } 198 | exit_success = { 199 | action = "EXIT" 200 | on_exit_code = 0 201 | } 202 | } 203 | } 204 | 205 | tags = { 206 | JobDefinition = "Example" 207 | } 208 | } 209 | } 210 | 211 | tags = local.tags 212 | } 213 | 214 | ################################################################################ 215 | # Supporting Resources 216 | ################################################################################ 217 | 218 | module "vpc" { 219 | source = "terraform-aws-modules/vpc/aws" 220 | version = "~> 6.0" 221 | 222 | name = local.name 223 | cidr = local.vpc_cidr 224 | 225 | azs = local.azs 226 | private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)] 227 | public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)] 228 | 229 | enable_nat_gateway = true 230 | single_nat_gateway = true 231 | 232 | tags = local.tags 233 | } 234 | 235 | module "vpc_endpoints" { 236 | source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints" 237 | version = "~> 6.0" 238 | 239 | vpc_id = module.vpc.vpc_id 240 | 241 | # Security group 242 | create_security_group = true 243 | security_group_name_prefix = "${local.name}-vpc-endpoints-" 244 | security_group_description = "VPC endpoint security group" 245 | security_group_rules = { 246 | ingress_https = { 247 | description = "HTTPS from VPC" 248 | cidr_blocks = [module.vpc.vpc_cidr_block] 249 | } 250 | } 251 | 252 | endpoints = merge( 253 | { 254 | s3 = { 255 | service = "s3" 256 | service_type = "Gateway" 257 | route_table_ids = module.vpc.private_route_table_ids 258 | tags = { 259 | Name = "${local.name}-s3" 260 | } 261 | } 262 | }, 263 | { 264 | for service in toset(["ecr.api", "ecr.dkr", "ecs", "ssm"]) : 265 | replace(service, ".", "_") => 266 | { 267 | service = service 268 | subnet_ids = module.vpc.private_subnets 269 | private_dns_enabled = true 270 | tags = { Name = "${local.name}-${service}" } 271 | } 272 | } 273 | ) 274 | 275 | tags = local.tags 276 | } 277 | 278 | resource "aws_cloudwatch_log_group" "this" { 279 | name = "/aws/batch/${local.name}" 280 | retention_in_days = 1 281 | 282 | tags = local.tags 283 | } 284 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "create" { 2 | description = "Controls if resources should be created (affects nearly all resources)" 3 | type = bool 4 | default = true 5 | } 6 | 7 | variable "region" { 8 | description = "Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration" 9 | type = string 10 | default = null 11 | } 12 | 13 | variable "tags" { 14 | description = "A map of tags to add to all resources" 15 | type = map(string) 16 | default = {} 17 | } 18 | 19 | ################################################################################ 20 | # Compute Environment(s) 21 | ################################################################################ 22 | 23 | variable "compute_environments" { 24 | description = "Map of compute environment definitions to create" 25 | type = map(object({ 26 | name = optional(string) 27 | name_prefix = optional(string) 28 | compute_resources = optional(object({ 29 | allocation_strategy = optional(string) 30 | bid_percentage = optional(number) 31 | desired_vcpus = optional(number) 32 | ec2_configuration = optional(list(object({ 33 | image_id_override = optional(string) 34 | image_type = optional(string) 35 | }))) 36 | ec2_key_pair = optional(string) 37 | instance_role = optional(string) 38 | instance_types = optional(list(string)) 39 | launch_template = optional(object({ 40 | launch_template_id = optional(string) 41 | launch_template_name = optional(string) 42 | version = optional(string) 43 | })) 44 | max_vcpus = number 45 | min_vcpus = optional(number) 46 | placement_group = optional(string) 47 | security_group_ids = optional(list(string)) 48 | spot_iam_fleet_role = optional(string) 49 | subnets = list(string) 50 | tags = optional(map(string), {}) 51 | type = string 52 | })) 53 | eks_configuration = optional(object({ 54 | eks_cluster_arn = string 55 | kubernetes_namespace = string 56 | })) 57 | service_role = optional(string) 58 | state = optional(string) 59 | tags = optional(map(string), {}) 60 | type = optional(string, "MANAGED") 61 | update_policy = optional(object({ 62 | job_execution_timeout_minutes = number 63 | terminate_jobs_on_update = optional(bool, false) 64 | })) 65 | })) 66 | default = null 67 | } 68 | 69 | ################################################################################ 70 | # Compute Environment - Instance Role 71 | ################################################################################ 72 | 73 | variable "create_instance_iam_role" { 74 | description = "Determines whether a an IAM role is created or to use an existing IAM role" 75 | type = bool 76 | default = true 77 | } 78 | 79 | variable "instance_iam_role_name" { 80 | description = "Cluster instance IAM role name" 81 | type = string 82 | default = null 83 | } 84 | 85 | variable "instance_iam_role_use_name_prefix" { 86 | description = "Determines whether the IAM role name (`instance_iam_role_name`) is used as a prefix" 87 | type = string 88 | default = true 89 | } 90 | 91 | variable "instance_iam_role_path" { 92 | description = "Cluster instance IAM role path" 93 | type = string 94 | default = null 95 | } 96 | 97 | variable "instance_iam_role_description" { 98 | description = "Cluster instance IAM role description" 99 | type = string 100 | default = null 101 | } 102 | 103 | variable "instance_iam_role_permissions_boundary" { 104 | description = "ARN of the policy that is used to set the permissions boundary for the IAM role" 105 | type = string 106 | default = null 107 | } 108 | 109 | variable "instance_iam_role_additional_policies" { 110 | description = "Additional policies to be added to the IAM role" 111 | type = map(string) 112 | default = {} 113 | } 114 | 115 | variable "instance_iam_role_tags" { 116 | description = "A map of additional tags to add to the IAM role created" 117 | type = map(string) 118 | default = {} 119 | } 120 | 121 | ################################################################################ 122 | # Compute Environment - Service Role 123 | ################################################################################ 124 | 125 | variable "create_service_iam_role" { 126 | description = "Determines whether a an IAM role is created or to use an existing IAM role" 127 | type = bool 128 | default = true 129 | } 130 | 131 | variable "service_iam_role_name" { 132 | description = "Batch service IAM role name" 133 | type = string 134 | default = null 135 | } 136 | 137 | variable "service_iam_role_use_name_prefix" { 138 | description = "Determines whether the IAM role name (`service_iam_role_name`) is used as a prefix" 139 | type = bool 140 | default = true 141 | } 142 | 143 | variable "service_iam_role_path" { 144 | description = "Batch service IAM role path" 145 | type = string 146 | default = null 147 | } 148 | 149 | variable "service_iam_role_description" { 150 | description = "Batch service IAM role description" 151 | type = string 152 | default = null 153 | } 154 | 155 | variable "service_iam_role_permissions_boundary" { 156 | description = "ARN of the policy that is used to set the permissions boundary for the IAM role" 157 | type = string 158 | default = null 159 | } 160 | 161 | variable "service_iam_role_additional_policies" { 162 | description = "Additional policies to be added to the IAM role" 163 | type = map(string) 164 | default = {} 165 | } 166 | 167 | variable "service_iam_role_tags" { 168 | description = "A map of additional tags to add to the IAM role created" 169 | type = map(string) 170 | default = {} 171 | } 172 | 173 | ################################################################################ 174 | # Compute Environment - Spot Fleet Role 175 | ################################################################################ 176 | 177 | variable "create_spot_fleet_iam_role" { 178 | description = "Determines whether a an IAM role is created or to use an existing IAM role" 179 | type = bool 180 | default = false 181 | } 182 | 183 | variable "spot_fleet_iam_role_name" { 184 | description = "Spot fleet IAM role name" 185 | type = string 186 | default = null 187 | } 188 | 189 | variable "spot_fleet_iam_role_use_name_prefix" { 190 | description = "Determines whether the IAM role name (`spot_fleet_iam_role_name`) is used as a prefix" 191 | type = string 192 | default = true 193 | } 194 | 195 | variable "spot_fleet_iam_role_path" { 196 | description = "Spot fleet IAM role path" 197 | type = string 198 | default = null 199 | } 200 | 201 | variable "spot_fleet_iam_role_description" { 202 | description = "Spot fleet IAM role description" 203 | type = string 204 | default = null 205 | } 206 | 207 | variable "spot_fleet_iam_role_permissions_boundary" { 208 | description = "ARN of the policy that is used to set the permissions boundary for the IAM role" 209 | type = string 210 | default = null 211 | } 212 | 213 | variable "spot_fleet_iam_role_additional_policies" { 214 | description = "Additional policies to be added to the IAM role" 215 | type = map(string) 216 | default = {} 217 | } 218 | 219 | variable "spot_fleet_iam_role_tags" { 220 | description = "A map of additional tags to add to the IAM role created" 221 | type = map(string) 222 | default = {} 223 | } 224 | 225 | ################################################################################ 226 | # Job Queue 227 | ################################################################################ 228 | 229 | variable "create_job_queues" { 230 | description = "Determines whether to create job queues" 231 | type = bool 232 | default = true 233 | } 234 | 235 | variable "job_queues" { 236 | description = "Map of job queue and scheduling policy defintions to create" 237 | type = map(object({ 238 | compute_environment_order = map(object({ 239 | compute_environment_key = string 240 | order = optional(number) # Will fall back to use map key as order 241 | })) 242 | job_state_time_limit_action = optional(map(object({ 243 | action = optional(string, "CANCEL") 244 | max_time_seconds = number 245 | reason = optional(string) 246 | state = optional(string, "RUNNABLE") 247 | }))) 248 | name = optional(string) # Will fall back to use map key as queue name 249 | priority = number 250 | scheduling_policy_arn = optional(string) 251 | state = optional(string, "ENABLED") 252 | tags = optional(map(string), {}) 253 | timeouts = optional(object({ 254 | create = optional(string, "10m") 255 | update = optional(string, "10m") 256 | delete = optional(string, "10m") 257 | })) 258 | 259 | # Scheduling policy 260 | create_scheduling_policy = optional(bool, true) 261 | fair_share_policy = optional(object({ 262 | compute_reservation = optional(number) 263 | share_decay_seconds = optional(number) 264 | share_distribution = optional(list(object({ 265 | share_identifier = string 266 | weight_factor = optional(number) 267 | }))) 268 | })) 269 | })) 270 | default = null 271 | } 272 | 273 | ################################################################################ 274 | # Scheduling Policy 275 | ################################################################################ 276 | 277 | # Scheduling policy is nested under job queue definition 278 | 279 | ################################################################################ 280 | # Job Definitions 281 | ################################################################################ 282 | 283 | variable "job_definitions" { 284 | description = "Map of job definitions to create" 285 | type = map(object({ 286 | container_properties = optional(string) 287 | deregister_on_new_revision = optional(bool) 288 | ecs_properties = optional(string) 289 | eks_properties = optional(object({ 290 | pod_properties = object({ 291 | containers = map(object({ 292 | args = optional(list(string)) 293 | command = optional(list(string)) 294 | env = optional(map(string)) 295 | image = string 296 | image_pull_policy = optional(string) 297 | name = optional(string) # Will fall back to use map key as container name 298 | resources = object({ 299 | limits = optional(map(string)) 300 | requests = optional(map(string)) 301 | }) 302 | security_context = optional(object({ 303 | privileged = optional(bool) 304 | read_only_root_file_system = optional(bool) 305 | run_as_group = optional(number) 306 | run_as_non_root = optional(bool) 307 | run_as_user = optional(number) 308 | })) 309 | volume_mounts = optional(map(object({ 310 | mount_path = string 311 | name = optional(string) # Will fall back to use map key as volume mount name 312 | read_only = optional(bool) 313 | }))) 314 | })) 315 | }) 316 | dns_policy = optional(string) 317 | host_network = optional(bool) 318 | image_pull_secrets = optional(list(object({ 319 | name = string 320 | }))) 321 | init_containers = optional(map(object({ 322 | args = optional(list(string)) 323 | command = optional(list(string)) 324 | env = optional(map(string)) 325 | image = string 326 | image_pull_policy = optional(string) 327 | name = optional(string) # Will fall back to use map key as init container name 328 | resources = object({ 329 | limits = optional(map(string)) 330 | requests = optional(map(string)) 331 | }) 332 | security_context = optional(object({ 333 | privileged = optional(bool) 334 | read_only_root_file_system = optional(bool) 335 | run_as_group = optional(number) 336 | run_as_non_root = optional(bool) 337 | run_as_user = optional(number) 338 | })) 339 | volume_mounts = optional(map(object({ 340 | mount_path = string 341 | name = optional(string) # Will fall back to use map key as volume mount name 342 | read_only = optional(bool) 343 | }))) 344 | }))) 345 | metadata = optional(object({ 346 | labels = optional(map(string)) 347 | })) 348 | service_account_name = optional(string) 349 | share_process_namespace = optional(bool) 350 | volumes = optional(map(object({ 351 | empty_dir = optional(object({ 352 | medium = optional(string) 353 | size_limit = optional(string) 354 | })) 355 | host_path = optional(object({ 356 | path = string 357 | })) 358 | name = optional(string) # Will fall back to use map key as volume name 359 | secret = optional(object({ 360 | optional = optional(bool) 361 | secret_name = string 362 | })) 363 | }))) 364 | })) 365 | name = optional(string) # Will fall back to use map key as job definition name 366 | node_properties = optional(string) 367 | parameters = optional(map(string)) 368 | platform_capabilities = optional(list(string)) 369 | propagate_tags = optional(bool) 370 | retry_strategy = optional(object({ 371 | attempts = optional(number) 372 | evaluate_on_exit = optional(map(object({ 373 | action = string 374 | on_exit_code = optional(string) 375 | on_reason = optional(string) 376 | on_status_reason = optional(string) 377 | }))) 378 | })) 379 | scheduling_priority = optional(number) 380 | tags = optional(map(string), {}) 381 | timeout = optional(object({ 382 | attempt_duration_seconds = optional(number) 383 | })) 384 | type = optional(string, "container") 385 | })) 386 | default = null 387 | } 388 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | data "aws_partition" "current" { 2 | count = var.create ? 1 : 0 3 | } 4 | 5 | locals { 6 | partition = try(data.aws_partition.current[0].partition, "") 7 | dns_suffix = try(data.aws_partition.current[0].dns_suffix, "") 8 | } 9 | 10 | ################################################################################ 11 | # Compute Environment(s) 12 | ################################################################################ 13 | 14 | resource "aws_batch_compute_environment" "this" { 15 | for_each = var.create && var.compute_environments != null ? var.compute_environments : {} 16 | 17 | region = var.region 18 | 19 | name = each.value.name 20 | name_prefix = each.value.name_prefix != null ? "${each.value.name_prefix}-" : null 21 | 22 | dynamic "compute_resources" { 23 | for_each = each.value.compute_resources != null ? [each.value.compute_resources] : [] 24 | 25 | content { 26 | allocation_strategy = contains(["FARGATE", "FARGATE_SPOT"], compute_resources.value.type) ? null : compute_resources.value.allocation_strategy 27 | bid_percentage = contains(["FARGATE", "FARGATE_SPOT"], compute_resources.value.type) ? null : compute_resources.value.bid_percentage 28 | desired_vcpus = contains(["FARGATE", "FARGATE_SPOT"], compute_resources.value.type) ? null : compute_resources.value.desired_vcpus 29 | 30 | dynamic "ec2_configuration" { 31 | for_each = !contains(["FARGATE", "FARGATE_SPOT"], compute_resources.value.type) && compute_resources.value.ec2_configuration != null ? compute_resources.value.ec2_configuration : [] 32 | 33 | content { 34 | image_id_override = ec2_configuration.value.image_id_override 35 | image_type = ec2_configuration.value.image_type 36 | } 37 | } 38 | 39 | ec2_key_pair = contains(["FARGATE", "FARGATE_SPOT"], compute_resources.value.type) ? null : compute_resources.value.ec2_key_pair 40 | instance_role = contains(["FARGATE", "FARGATE_SPOT"], compute_resources.value.type) ? null : try(aws_iam_instance_profile.instance[0].arn, compute_resources.value.instance_role) 41 | instance_type = contains(["FARGATE", "FARGATE_SPOT"], compute_resources.value.type) ? null : compute_resources.value.instance_types 42 | 43 | dynamic "launch_template" { 44 | for_each = !contains(["FARGATE", "FARGATE_SPOT"], compute_resources.value.type) && compute_resources.value.launch_template != null ? [compute_resources.value.launch_template] : [] 45 | 46 | content { 47 | launch_template_id = launch_template.value.launch_template_id 48 | launch_template_name = launch_template.value.launch_template_name 49 | version = launch_template.value.version 50 | } 51 | } 52 | 53 | max_vcpus = compute_resources.value.max_vcpus 54 | min_vcpus = contains(["FARGATE", "FARGATE_SPOT"], compute_resources.value.type) ? null : compute_resources.value.min_vcpus 55 | placement_group = compute_resources.value.placement_group 56 | security_group_ids = compute_resources.value.security_group_ids 57 | spot_iam_fleet_role = compute_resources.value.type == "SPOT" ? try(aws_iam_role.spot_fleet[0].arn, compute_resources.value.spot_iam_fleet_role) : null 58 | subnets = compute_resources.value.subnets 59 | # We do not merge with default `var.tags` here because tag changes cause compute environment replacement 60 | tags = contains(["FARGATE", "FARGATE_SPOT"], compute_resources.value.type) ? null : compute_resources.value.tags 61 | type = compute_resources.value.type 62 | } 63 | } 64 | 65 | dynamic "eks_configuration" { 66 | for_each = each.value.eks_configuration != null ? [each.value.eks_configuration] : [] 67 | 68 | content { 69 | eks_cluster_arn = eks_configuration.value.eks_cluster_arn 70 | kubernetes_namespace = eks_configuration.value.kubernetes_namespace 71 | } 72 | } 73 | 74 | service_role = var.create_service_iam_role ? aws_iam_role.service[0].arn : each.value.service_role 75 | state = each.value.state 76 | 77 | tags = merge( 78 | { terraform-aws-modules = "batch" }, 79 | var.tags, 80 | each.value.tags, 81 | ) 82 | 83 | type = each.value.type 84 | 85 | dynamic "update_policy" { 86 | for_each = each.value.update_policy != null ? [each.value.update_policy] : [] 87 | 88 | content { 89 | job_execution_timeout_minutes = update_policy.value.job_execution_timeout_minutes 90 | terminate_jobs_on_update = update_policy.value.terminate_jobs_on_update 91 | } 92 | } 93 | 94 | # Prevent a race condition during environment deletion, otherwise the policy may be destroyed 95 | # too soon and the compute environment will then get stuck in the `DELETING` state 96 | depends_on = [ 97 | aws_iam_role_policy_attachment.instance, 98 | aws_iam_role_policy_attachment.service, 99 | aws_iam_role_policy_attachment.spot_fleet, 100 | ] 101 | 102 | lifecycle { 103 | create_before_destroy = true 104 | } 105 | } 106 | 107 | ################################################################################ 108 | # Compute Environment - Instance Role 109 | ################################################################################ 110 | 111 | locals { 112 | create_instance_iam_role = var.create && var.create_instance_iam_role 113 | } 114 | 115 | data "aws_iam_policy_document" "instance" { 116 | count = local.create_instance_iam_role ? 1 : 0 117 | 118 | statement { 119 | sid = "EC2AssumeRole" 120 | actions = ["sts:AssumeRole"] 121 | 122 | principals { 123 | type = "Service" 124 | identifiers = ["ec2.${local.dns_suffix}"] 125 | } 126 | } 127 | } 128 | 129 | resource "aws_iam_role" "instance" { 130 | count = local.create_instance_iam_role ? 1 : 0 131 | 132 | name = var.instance_iam_role_use_name_prefix ? null : var.instance_iam_role_name 133 | name_prefix = var.instance_iam_role_use_name_prefix ? "${var.instance_iam_role_name}-" : null 134 | path = var.instance_iam_role_path 135 | description = var.instance_iam_role_description 136 | 137 | assume_role_policy = data.aws_iam_policy_document.instance[0].json 138 | permissions_boundary = var.instance_iam_role_permissions_boundary 139 | force_detach_policies = true 140 | 141 | tags = merge( 142 | var.tags, 143 | var.instance_iam_role_tags, 144 | ) 145 | 146 | lifecycle { 147 | create_before_destroy = true 148 | } 149 | } 150 | 151 | resource "aws_iam_role_policy_attachment" "instance" { 152 | for_each = { for k, v in merge( 153 | { 154 | AmazonEC2ContainerServiceforEC2Role = "arn:${local.partition}:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role" 155 | }, 156 | var.instance_iam_role_additional_policies) : k => v if local.create_instance_iam_role } 157 | 158 | policy_arn = each.value 159 | role = aws_iam_role.instance[0].name 160 | } 161 | 162 | resource "aws_iam_instance_profile" "instance" { 163 | count = local.create_instance_iam_role ? 1 : 0 164 | 165 | name = var.instance_iam_role_use_name_prefix ? null : var.instance_iam_role_name 166 | name_prefix = var.instance_iam_role_use_name_prefix ? "${var.instance_iam_role_name}-" : null 167 | path = var.instance_iam_role_path 168 | role = aws_iam_role.instance[0].name 169 | 170 | tags = merge( 171 | var.tags, 172 | var.instance_iam_role_tags, 173 | ) 174 | 175 | lifecycle { 176 | create_before_destroy = true 177 | } 178 | } 179 | 180 | ################################################################################ 181 | # Compute Environment - Service Role 182 | ################################################################################ 183 | 184 | locals { 185 | create_service_iam_role = var.create && var.create_service_iam_role 186 | } 187 | 188 | data "aws_iam_policy_document" "service" { 189 | count = local.create_service_iam_role ? 1 : 0 190 | 191 | statement { 192 | sid = "BatchAssumeRole" 193 | actions = ["sts:AssumeRole"] 194 | 195 | principals { 196 | type = "Service" 197 | identifiers = ["batch.${local.dns_suffix}"] 198 | } 199 | } 200 | } 201 | 202 | resource "aws_iam_role" "service" { 203 | count = local.create_service_iam_role ? 1 : 0 204 | 205 | name = var.service_iam_role_use_name_prefix ? null : var.service_iam_role_name 206 | name_prefix = var.service_iam_role_use_name_prefix ? "${var.service_iam_role_name}-" : null 207 | path = var.service_iam_role_path 208 | description = var.service_iam_role_description 209 | 210 | assume_role_policy = data.aws_iam_policy_document.service[0].json 211 | permissions_boundary = var.service_iam_role_permissions_boundary 212 | force_detach_policies = true 213 | 214 | tags = merge( 215 | var.tags, 216 | var.service_iam_role_tags, 217 | ) 218 | 219 | lifecycle { 220 | create_before_destroy = true 221 | } 222 | } 223 | 224 | resource "aws_iam_role_policy_attachment" "service" { 225 | for_each = { for k, v in merge( 226 | { 227 | AWSBatchServiceRole = "arn:${local.partition}:iam::aws:policy/service-role/AWSBatchServiceRole" 228 | }, 229 | var.service_iam_role_additional_policies) : k => v if local.create_service_iam_role } 230 | 231 | policy_arn = each.value 232 | role = aws_iam_role.service[0].name 233 | } 234 | 235 | ################################################################################ 236 | # Compute Environment - Spot Fleet Role 237 | ################################################################################ 238 | 239 | locals { 240 | create_spot_fleet_iam_role = var.create && var.create_spot_fleet_iam_role 241 | } 242 | 243 | data "aws_iam_policy_document" "spot_fleet" { 244 | count = local.create_spot_fleet_iam_role ? 1 : 0 245 | 246 | statement { 247 | sid = "SpotFleetAssumeRole" 248 | actions = ["sts:AssumeRole"] 249 | 250 | principals { 251 | type = "Service" 252 | identifiers = ["spotfleet.${local.dns_suffix}"] 253 | } 254 | } 255 | } 256 | 257 | resource "aws_iam_role" "spot_fleet" { 258 | count = local.create_spot_fleet_iam_role ? 1 : 0 259 | 260 | name = var.spot_fleet_iam_role_use_name_prefix ? null : var.spot_fleet_iam_role_name 261 | name_prefix = var.spot_fleet_iam_role_use_name_prefix ? "${var.spot_fleet_iam_role_name}-" : null 262 | path = var.spot_fleet_iam_role_path 263 | description = var.spot_fleet_iam_role_description 264 | 265 | assume_role_policy = data.aws_iam_policy_document.spot_fleet[0].json 266 | permissions_boundary = var.spot_fleet_iam_role_permissions_boundary 267 | force_detach_policies = true 268 | 269 | tags = merge( 270 | var.tags, 271 | var.spot_fleet_iam_role_tags, 272 | ) 273 | 274 | lifecycle { 275 | create_before_destroy = true 276 | } 277 | } 278 | 279 | resource "aws_iam_role_policy_attachment" "spot_fleet" { 280 | for_each = { for k, v in merge( 281 | { 282 | AmazonEC2SpotFleetTaggingRole = "arn:${local.partition}:iam::aws:policy/service-role/AmazonEC2SpotFleetTaggingRole" 283 | }, 284 | var.spot_fleet_iam_role_additional_policies) : k => v if local.create_spot_fleet_iam_role } 285 | 286 | policy_arn = each.value 287 | role = aws_iam_role.spot_fleet[0].name 288 | } 289 | 290 | ################################################################################ 291 | # Job Queue 292 | ################################################################################ 293 | 294 | locals { 295 | create_job_queues = var.create && var.create_job_queues 296 | } 297 | 298 | resource "aws_batch_job_queue" "this" { 299 | for_each = local.create_job_queues && var.job_queues != null ? var.job_queues : {} 300 | 301 | region = var.region 302 | 303 | dynamic "compute_environment_order" { 304 | for_each = each.value.compute_environment_order != null ? each.value.compute_environment_order : {} 305 | 306 | content { 307 | # Refer to compute environment created above by the user provided configuration definition key 308 | compute_environment = aws_batch_compute_environment.this[compute_environment_order.value.compute_environment_key].arn 309 | order = try(coalesce(compute_environment_order.value.order, compute_environment_order.key), null) 310 | } 311 | } 312 | 313 | dynamic "job_state_time_limit_action" { 314 | for_each = each.value.job_state_time_limit_action != null ? each.value.job_state_time_limit_action : {} 315 | 316 | content { 317 | action = job_state_time_limit_action.value.action 318 | max_time_seconds = job_state_time_limit_action.value.max_time_seconds 319 | reason = job_state_time_limit_action.value.reason 320 | state = job_state_time_limit_action.value.state 321 | } 322 | } 323 | 324 | name = try(coalesce(each.value.name, each.key), null) 325 | priority = each.value.priority 326 | scheduling_policy_arn = each.value.create_scheduling_policy ? aws_batch_scheduling_policy.this[each.key].arn : each.value.scheduling_policy_arn 327 | state = each.value.state 328 | 329 | dynamic "timeouts" { 330 | for_each = each.value.timeouts != null ? [each.value.timeouts] : [] 331 | 332 | content { 333 | create = timeouts.value.create 334 | update = timeouts.value.update 335 | delete = timeouts.value.delete 336 | } 337 | } 338 | 339 | tags = merge( 340 | var.tags, 341 | each.value.tags, 342 | ) 343 | 344 | depends_on = [ 345 | aws_batch_compute_environment.this, 346 | ] 347 | } 348 | 349 | ################################################################################ 350 | # Scheduling Policy 351 | ################################################################################ 352 | 353 | resource "aws_batch_scheduling_policy" "this" { 354 | for_each = local.create_job_queues && var.job_queues != null ? { for k, v in var.job_queues : k => v if v.create_scheduling_policy } : {} 355 | 356 | region = var.region 357 | 358 | dynamic "fair_share_policy" { 359 | for_each = each.value.fair_share_policy != null ? [each.value.fair_share_policy] : [] 360 | 361 | content { 362 | compute_reservation = fair_share_policy.value.compute_reservation 363 | share_decay_seconds = fair_share_policy.value.share_decay_seconds 364 | 365 | dynamic "share_distribution" { 366 | for_each = fair_share_policy.value.share_distribution != null ? fair_share_policy.value.share_distribution : [] 367 | 368 | content { 369 | share_identifier = share_distribution.value.share_identifier 370 | weight_factor = share_distribution.value.weight_factor 371 | } 372 | } 373 | } 374 | } 375 | 376 | name = each.value.name 377 | 378 | tags = merge( 379 | var.tags, 380 | each.value.tags, 381 | ) 382 | } 383 | 384 | ################################################################################ 385 | # Job Definitions 386 | ################################################################################ 387 | 388 | resource "aws_batch_job_definition" "this" { 389 | for_each = var.create && var.job_definitions != null ? var.job_definitions : {} 390 | 391 | region = var.region 392 | 393 | container_properties = each.value.container_properties 394 | deregister_on_new_revision = each.value.deregister_on_new_revision 395 | ecs_properties = each.value.ecs_properties 396 | 397 | dynamic "eks_properties" { 398 | for_each = each.value.eks_properties != null ? [each.value.eks_properties] : [] 399 | 400 | content { 401 | pod_properties { 402 | dynamic "containers" { 403 | for_each = eks_properties.value.pod_properties.containers 404 | 405 | content { 406 | args = containers.value.args 407 | command = containers.value.command 408 | 409 | dynamic "env" { 410 | for_each = containers.value.env != null ? containers.value.env : {} 411 | 412 | content { 413 | name = env.key 414 | value = env.value 415 | } 416 | } 417 | 418 | image = containers.value.image 419 | image_pull_policy = containers.value.image_pull_policy 420 | name = try(coalesce(containers.value.name, containers.key), null) 421 | 422 | dynamic "resources" { 423 | for_each = containers.value.resources != null ? [containers.value.resources] : [] 424 | 425 | content { 426 | limits = resources.value.limits 427 | requests = resources.value.requests 428 | } 429 | } 430 | 431 | dynamic "security_context" { 432 | for_each = containers.value.security_context != null ? [containers.value.security_context] : [] 433 | 434 | content { 435 | privileged = security_context.value.privileged 436 | read_only_root_file_system = security_context.value.read_only_root_file_system 437 | run_as_group = security_context.value.run_as_group 438 | run_as_non_root = security_context.value.run_as_non_root 439 | run_as_user = security_context.value.run_as_user 440 | } 441 | } 442 | 443 | dynamic "volume_mounts" { 444 | for_each = containers.value.volume_mounts != null ? containers.value.volume_mounts : {} 445 | 446 | content { 447 | mount_path = volume_mounts.value.mount_path 448 | name = try(coalesce(volume_mounts.value.name, volume_mounts.key), null) 449 | read_only = volume_mounts.value.read_only 450 | } 451 | } 452 | } 453 | } 454 | 455 | dns_policy = eks_properties.value.dns_policy 456 | host_network = eks_properties.value.host_network 457 | 458 | dynamic "image_pull_secret" { 459 | for_each = eks_properties.value.image_pull_secrets != null ? eks_properties.value.image_pull_secrets : [] 460 | 461 | content { 462 | name = image_pull_secret.value.name 463 | } 464 | } 465 | 466 | dynamic "init_containers" { 467 | for_each = eks_properties.value.init_containers != null ? eks_properties.value.init_containers : {} 468 | 469 | content { 470 | args = init_containers.value.args 471 | command = init_containers.value.command 472 | 473 | dynamic "env" { 474 | for_each = init_containers.value.env != null ? init_containers.value.env : {} 475 | 476 | content { 477 | name = env.key 478 | value = env.value 479 | } 480 | } 481 | 482 | image = init_containers.value.image 483 | image_pull_policy = init_containers.value.image_pull_policy 484 | name = try(coalesce(init_containers.value.name, init_containers.key), null) 485 | 486 | dynamic "resources" { 487 | for_each = init_containers.value.resources != null ? [init_containers.value.resources] : [] 488 | 489 | content { 490 | limits = resources.value.limits 491 | requests = resources.value.requests 492 | } 493 | } 494 | 495 | dynamic "security_context" { 496 | for_each = init_containers.value.security_context != null ? [init_containers.value.security_context] : [] 497 | 498 | content { 499 | privileged = security_context.value.privileged 500 | read_only_root_file_system = security_context.value.read_only_root_file_system 501 | run_as_group = security_context.value.run_as_group 502 | run_as_non_root = security_context.value.run_as_non_root 503 | run_as_user = security_context.value.run_as_user 504 | } 505 | } 506 | 507 | dynamic "volume_mounts" { 508 | for_each = init_containers.value.volume_mounts != null ? init_containers.value.volume_mounts : {} 509 | 510 | content { 511 | mount_path = volume_mounts.value.mount_path 512 | name = try(coalesce(volume_mounts.value.name, volume_mounts.key), null) 513 | read_only = volume_mounts.value.read_only 514 | } 515 | } 516 | } 517 | } 518 | 519 | dynamic "metadata" { 520 | for_each = eks_properties.value.metadata != null ? [eks_properties.value.metadata] : [] 521 | 522 | content { 523 | labels = metadata.value.labels 524 | } 525 | } 526 | 527 | service_account_name = eks_properties.value.service_account_name 528 | share_process_namespace = eks_properties.value.share_process_namespace 529 | 530 | dynamic "volumes" { 531 | for_each = eks_properties.value.volumes != null ? eks_properties.value.volumes : {} 532 | 533 | content { 534 | dynamic "empty_dir" { 535 | for_each = volumes.value.empty_dir != null ? [volumes.value.empty_dir] : [] 536 | 537 | content { 538 | medium = empty_dir.value.medium 539 | size_limit = empty_dir.value.size_limit 540 | } 541 | } 542 | 543 | dynamic "host_path" { 544 | for_each = volumes.value.host_path != null ? [volumes.value.host_path] : [] 545 | 546 | content { 547 | path = host_path.value.path 548 | } 549 | } 550 | 551 | name = try(coalesce(volumes.value.name, volumes.key), null) 552 | 553 | dynamic "secret" { 554 | for_each = volumes.value.secret != null ? [volumes.value.secret] : [] 555 | 556 | content { 557 | optional = secret.value.optional 558 | secret_name = secret.value.secret_name 559 | } 560 | } 561 | } 562 | } 563 | } 564 | } 565 | } 566 | 567 | name = try(coalesce(each.value.name, each.key), null) 568 | node_properties = each.value.node_properties 569 | parameters = each.value.parameters 570 | platform_capabilities = each.value.platform_capabilities 571 | propagate_tags = each.value.propagate_tags 572 | 573 | dynamic "retry_strategy" { 574 | for_each = each.value.retry_strategy != null ? [each.value.retry_strategy] : [] 575 | 576 | content { 577 | attempts = retry_strategy.value.attempts 578 | 579 | dynamic "evaluate_on_exit" { 580 | for_each = retry_strategy.value.evaluate_on_exit != null ? retry_strategy.value.evaluate_on_exit : {} 581 | 582 | content { 583 | action = evaluate_on_exit.value.action 584 | on_exit_code = evaluate_on_exit.value.on_exit_code 585 | on_reason = evaluate_on_exit.value.on_reason 586 | on_status_reason = evaluate_on_exit.value.on_status_reason 587 | } 588 | } 589 | } 590 | } 591 | 592 | scheduling_priority = each.value.scheduling_priority 593 | tags = merge( 594 | var.tags, 595 | each.value.tags, 596 | ) 597 | 598 | dynamic "timeout" { 599 | for_each = each.value.timeout != null ? [each.value.timeout] : [] 600 | 601 | content { 602 | attempt_duration_seconds = timeout.value.attempt_duration_seconds 603 | } 604 | } 605 | 606 | type = each.value.type 607 | } 608 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS Batch Terraform module 2 | 3 | Terraform module which creates AWS Batch resources. 4 | 5 | ## Usage 6 | 7 | See [`examples`](https://github.com/terraform-aws-modules/terraform-aws-batch/tree/master/examples) directory for working examples to reference: 8 | 9 | ```hcl 10 | module "batch" { 11 | source = "terraform-aws-modules/batch/aws" 12 | 13 | compute_environments = { 14 | a_ec2 = { 15 | name_prefix = "ec2" 16 | 17 | compute_resources = { 18 | type = "EC2" 19 | min_vcpus = 4 20 | max_vcpus = 16 21 | desired_vcpus = 4 22 | instance_types = ["m5.large", "r5.large"] 23 | 24 | security_group_ids = ["sg-f1d03a88"] 25 | subnets = ["subnet-30ef7b3c", "subnet-1ecda77b", "subnet-ca09ddbc"] 26 | 27 | tags = { 28 | # This will set the name on the Ec2 instances launched by this compute environment 29 | Name = "example" 30 | Type = "Ec2" 31 | } 32 | } 33 | } 34 | 35 | b_ec2_spot = { 36 | name_prefix = "ec2_spot" 37 | 38 | compute_resources = { 39 | type = "SPOT" 40 | allocation_strategy = "SPOT_CAPACITY_OPTIMIZED" 41 | bid_percentage = 20 42 | 43 | min_vcpus = 4 44 | max_vcpus = 16 45 | desired_vcpus = 4 46 | instance_types = ["m4.large", "m3.large", "r4.large", "r3.large"] 47 | 48 | security_group_ids = ["sg-f1d03a88"] 49 | subnets = ["subnet-30ef7b3c", "subnet-1ecda77b", "subnet-ca09ddbc"] 50 | 51 | tags = { 52 | # This will set the name on the Ec2 instances launched by this compute environment 53 | Name = "example-spot" 54 | Type = "Ec2Spot" 55 | } 56 | } 57 | } 58 | } 59 | 60 | # Job queus and scheduling policies 61 | job_queues = { 62 | low_priority = { 63 | name = "LowPriorityEc2" 64 | state = "ENABLED" 65 | priority = 1 66 | 67 | compute_environment_order = { 68 | 0 = { 69 | compute_environment_key = "b_ec2_spot" 70 | } 71 | 1 = { 72 | compute_environment_key = "a_ec2" 73 | } 74 | } 75 | 76 | tags = { 77 | JobQueue = "Low priority job queue" 78 | } 79 | } 80 | 81 | high_priority = { 82 | name = "HighPriorityEc2" 83 | state = "ENABLED" 84 | priority = 99 85 | 86 | compute_environment_order = { 87 | 0 = { 88 | compute_environment_key = "a_ec2" 89 | } 90 | } 91 | 92 | fair_share_policy = { 93 | compute_reservation = 1 94 | share_decay_seconds = 3600 95 | 96 | share_distribution = [{ 97 | share_identifier = "A1*" 98 | weight_factor = 0.1 99 | }, { 100 | share_identifier = "A2" 101 | weight_factor = 0.2 102 | }] 103 | } 104 | 105 | tags = { 106 | JobQueue = "High priority job queue" 107 | } 108 | } 109 | } 110 | 111 | job_definitions = { 112 | example = { 113 | name = "example" 114 | propagate_tags = true 115 | 116 | container_properties = jsonencode({ 117 | command = ["ls", "-la"] 118 | image = "public.ecr.aws/runecast/busybox:1.33.1" 119 | resourceRequirements = [ 120 | { type = "VCPU", value = "1" }, 121 | { type = "MEMORY", value = "1024" } 122 | ] 123 | logConfiguration = { 124 | logDriver = "awslogs" 125 | options = { 126 | awslogs-group = "/aws/batch/example" 127 | awslogs-region = "us-east-1" 128 | awslogs-stream-prefix = "ec2" 129 | } 130 | } 131 | }) 132 | 133 | attempt_duration_seconds = 60 134 | retry_strategy = { 135 | attempts = 3 136 | evaluate_on_exit = { 137 | retry_error = { 138 | action = "RETRY" 139 | on_exit_code = 1 140 | } 141 | exit_success = { 142 | action = "EXIT" 143 | on_exit_code = 0 144 | } 145 | } 146 | } 147 | 148 | tags = { 149 | JobDefinition = "Example" 150 | } 151 | } 152 | } 153 | 154 | tags = { 155 | Terraform = "true" 156 | Environment = "dev" 157 | } 158 | } 159 | ``` 160 | 161 | ## Examples 162 | 163 | Examples codified under the [`examples`](https://github.com/terraform-aws-modules/terraform-aws-batch/tree/master/examples) are intended to give users references for how to use the module(s) as well as testing/validating changes to the source code of the module. If contributing to the project, please be sure to make any appropriate updates to the relevant examples to allow maintainers to test your changes and to keep the examples up to date for users. Thank you! 164 | 165 | - [EC2](https://github.com/terraform-aws-modules/terraform-aws-batch/tree/master/examples/ec2) 166 | - [Fargate](https://github.com/terraform-aws-modules/terraform-aws-batch/tree/master/examples/fargate) 167 | 168 | 169 | ## Requirements 170 | 171 | | Name | Version | 172 | |------|---------| 173 | | [terraform](#requirement\_terraform) | >= 1.5.7 | 174 | | [aws](#requirement\_aws) | >= 6.0 | 175 | 176 | ## Providers 177 | 178 | | Name | Version | 179 | |------|---------| 180 | | [aws](#provider\_aws) | >= 6.0 | 181 | 182 | ## Modules 183 | 184 | No modules. 185 | 186 | ## Resources 187 | 188 | | Name | Type | 189 | |------|------| 190 | | [aws_batch_compute_environment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/batch_compute_environment) | resource | 191 | | [aws_batch_job_definition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/batch_job_definition) | resource | 192 | | [aws_batch_job_queue.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/batch_job_queue) | resource | 193 | | [aws_batch_scheduling_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/batch_scheduling_policy) | resource | 194 | | [aws_iam_instance_profile.instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_instance_profile) | resource | 195 | | [aws_iam_role.instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | 196 | | [aws_iam_role.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | 197 | | [aws_iam_role.spot_fleet](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | 198 | | [aws_iam_role_policy_attachment.instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 199 | | [aws_iam_role_policy_attachment.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 200 | | [aws_iam_role_policy_attachment.spot_fleet](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 201 | | [aws_iam_policy_document.instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 202 | | [aws_iam_policy_document.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 203 | | [aws_iam_policy_document.spot_fleet](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 204 | | [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | 205 | 206 | ## Inputs 207 | 208 | | Name | Description | Type | Default | Required | 209 | |------|-------------|------|---------|:--------:| 210 | | [compute\_environments](#input\_compute\_environments) | Map of compute environment definitions to create |
map(object({
name = optional(string)
name_prefix = optional(string)
compute_resources = optional(object({
allocation_strategy = optional(string)
bid_percentage = optional(number)
desired_vcpus = optional(number)
ec2_configuration = optional(list(object({
image_id_override = optional(string)
image_type = optional(string)
})))
ec2_key_pair = optional(string)
instance_role = optional(string)
instance_types = optional(list(string))
launch_template = optional(object({
launch_template_id = optional(string)
launch_template_name = optional(string)
version = optional(string)
}))
max_vcpus = number
min_vcpus = optional(number)
placement_group = optional(string)
security_group_ids = optional(list(string))
spot_iam_fleet_role = optional(string)
subnets = list(string)
tags = optional(map(string), {})
type = string
}))
eks_configuration = optional(object({
eks_cluster_arn = string
kubernetes_namespace = string
}))
service_role = optional(string)
state = optional(string)
tags = optional(map(string), {})
type = optional(string, "MANAGED")
update_policy = optional(object({
job_execution_timeout_minutes = number
terminate_jobs_on_update = optional(bool, false)
}))
}))
| `null` | no | 211 | | [create](#input\_create) | Controls if resources should be created (affects nearly all resources) | `bool` | `true` | no | 212 | | [create\_instance\_iam\_role](#input\_create\_instance\_iam\_role) | Determines whether a an IAM role is created or to use an existing IAM role | `bool` | `true` | no | 213 | | [create\_job\_queues](#input\_create\_job\_queues) | Determines whether to create job queues | `bool` | `true` | no | 214 | | [create\_service\_iam\_role](#input\_create\_service\_iam\_role) | Determines whether a an IAM role is created or to use an existing IAM role | `bool` | `true` | no | 215 | | [create\_spot\_fleet\_iam\_role](#input\_create\_spot\_fleet\_iam\_role) | Determines whether a an IAM role is created or to use an existing IAM role | `bool` | `false` | no | 216 | | [instance\_iam\_role\_additional\_policies](#input\_instance\_iam\_role\_additional\_policies) | Additional policies to be added to the IAM role | `map(string)` | `{}` | no | 217 | | [instance\_iam\_role\_description](#input\_instance\_iam\_role\_description) | Cluster instance IAM role description | `string` | `null` | no | 218 | | [instance\_iam\_role\_name](#input\_instance\_iam\_role\_name) | Cluster instance IAM role name | `string` | `null` | no | 219 | | [instance\_iam\_role\_path](#input\_instance\_iam\_role\_path) | Cluster instance IAM role path | `string` | `null` | no | 220 | | [instance\_iam\_role\_permissions\_boundary](#input\_instance\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no | 221 | | [instance\_iam\_role\_tags](#input\_instance\_iam\_role\_tags) | A map of additional tags to add to the IAM role created | `map(string)` | `{}` | no | 222 | | [instance\_iam\_role\_use\_name\_prefix](#input\_instance\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`instance_iam_role_name`) is used as a prefix | `string` | `true` | no | 223 | | [job\_definitions](#input\_job\_definitions) | Map of job definitions to create |
map(object({
container_properties = optional(string)
deregister_on_new_revision = optional(bool)
ecs_properties = optional(string)
eks_properties = optional(object({
pod_properties = object({
containers = map(object({
args = optional(list(string))
command = optional(list(string))
env = optional(map(string))
image = string
image_pull_policy = optional(string)
name = optional(string) # Will fall back to use map key as container name
resources = object({
limits = optional(map(string))
requests = optional(map(string))
})
security_context = optional(object({
privileged = optional(bool)
read_only_root_file_system = optional(bool)
run_as_group = optional(number)
run_as_non_root = optional(bool)
run_as_user = optional(number)
}))
volume_mounts = optional(map(object({
mount_path = string
name = optional(string) # Will fall back to use map key as volume mount name
read_only = optional(bool)
})))
}))
})
dns_policy = optional(string)
host_network = optional(bool)
image_pull_secrets = optional(list(object({
name = string
})))
init_containers = optional(map(object({
args = optional(list(string))
command = optional(list(string))
env = optional(map(string))
image = string
image_pull_policy = optional(string)
name = optional(string) # Will fall back to use map key as init container name
resources = object({
limits = optional(map(string))
requests = optional(map(string))
})
security_context = optional(object({
privileged = optional(bool)
read_only_root_file_system = optional(bool)
run_as_group = optional(number)
run_as_non_root = optional(bool)
run_as_user = optional(number)
}))
volume_mounts = optional(map(object({
mount_path = string
name = optional(string) # Will fall back to use map key as volume mount name
read_only = optional(bool)
})))
})))
metadata = optional(object({
labels = optional(map(string))
}))
service_account_name = optional(string)
share_process_namespace = optional(bool)
volumes = optional(map(object({
empty_dir = optional(object({
medium = optional(string)
size_limit = optional(string)
}))
host_path = optional(object({
path = string
}))
name = optional(string) # Will fall back to use map key as volume name
secret = optional(object({
optional = optional(bool)
secret_name = string
}))
})))
}))
name = optional(string) # Will fall back to use map key as job definition name
node_properties = optional(string)
parameters = optional(map(string))
platform_capabilities = optional(list(string))
propagate_tags = optional(bool)
retry_strategy = optional(object({
attempts = optional(number)
evaluate_on_exit = optional(map(object({
action = string
on_exit_code = optional(string)
on_reason = optional(string)
on_status_reason = optional(string)
})))
}))
scheduling_priority = optional(number)
tags = optional(map(string), {})
timeout = optional(object({
attempt_duration_seconds = optional(number)
}))
type = optional(string, "container")
}))
| `null` | no | 224 | | [job\_queues](#input\_job\_queues) | Map of job queue and scheduling policy defintions to create |
map(object({
compute_environment_order = map(object({
compute_environment_key = string
order = optional(number) # Will fall back to use map key as order
}))
job_state_time_limit_action = optional(map(object({
action = optional(string, "CANCEL")
max_time_seconds = number
reason = optional(string)
state = optional(string, "RUNNABLE")
})))
name = optional(string) # Will fall back to use map key as queue name
priority = number
scheduling_policy_arn = optional(string)
state = optional(string, "ENABLED")
tags = optional(map(string), {})
timeouts = optional(object({
create = optional(string, "10m")
update = optional(string, "10m")
delete = optional(string, "10m")
}))

# Scheduling policy
create_scheduling_policy = optional(bool, true)
fair_share_policy = optional(object({
compute_reservation = optional(number)
share_decay_seconds = optional(number)
share_distribution = optional(list(object({
share_identifier = string
weight_factor = optional(number)
})))
}))
}))
| `null` | no | 225 | | [region](#input\_region) | Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration | `string` | `null` | no | 226 | | [service\_iam\_role\_additional\_policies](#input\_service\_iam\_role\_additional\_policies) | Additional policies to be added to the IAM role | `map(string)` | `{}` | no | 227 | | [service\_iam\_role\_description](#input\_service\_iam\_role\_description) | Batch service IAM role description | `string` | `null` | no | 228 | | [service\_iam\_role\_name](#input\_service\_iam\_role\_name) | Batch service IAM role name | `string` | `null` | no | 229 | | [service\_iam\_role\_path](#input\_service\_iam\_role\_path) | Batch service IAM role path | `string` | `null` | no | 230 | | [service\_iam\_role\_permissions\_boundary](#input\_service\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no | 231 | | [service\_iam\_role\_tags](#input\_service\_iam\_role\_tags) | A map of additional tags to add to the IAM role created | `map(string)` | `{}` | no | 232 | | [service\_iam\_role\_use\_name\_prefix](#input\_service\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`service_iam_role_name`) is used as a prefix | `bool` | `true` | no | 233 | | [spot\_fleet\_iam\_role\_additional\_policies](#input\_spot\_fleet\_iam\_role\_additional\_policies) | Additional policies to be added to the IAM role | `map(string)` | `{}` | no | 234 | | [spot\_fleet\_iam\_role\_description](#input\_spot\_fleet\_iam\_role\_description) | Spot fleet IAM role description | `string` | `null` | no | 235 | | [spot\_fleet\_iam\_role\_name](#input\_spot\_fleet\_iam\_role\_name) | Spot fleet IAM role name | `string` | `null` | no | 236 | | [spot\_fleet\_iam\_role\_path](#input\_spot\_fleet\_iam\_role\_path) | Spot fleet IAM role path | `string` | `null` | no | 237 | | [spot\_fleet\_iam\_role\_permissions\_boundary](#input\_spot\_fleet\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no | 238 | | [spot\_fleet\_iam\_role\_tags](#input\_spot\_fleet\_iam\_role\_tags) | A map of additional tags to add to the IAM role created | `map(string)` | `{}` | no | 239 | | [spot\_fleet\_iam\_role\_use\_name\_prefix](#input\_spot\_fleet\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`spot_fleet_iam_role_name`) is used as a prefix | `string` | `true` | no | 240 | | [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no | 241 | 242 | ## Outputs 243 | 244 | | Name | Description | 245 | |------|-------------| 246 | | [compute\_environments](#output\_compute\_environments) | Map of compute environments created and their associated attributes | 247 | | [instance\_iam\_instance\_profile\_arn](#output\_instance\_iam\_instance\_profile\_arn) | ARN assigned by AWS to the instance profile | 248 | | [instance\_iam\_instance\_profile\_id](#output\_instance\_iam\_instance\_profile\_id) | Instance profile's ID | 249 | | [instance\_iam\_instance\_profile\_unique](#output\_instance\_iam\_instance\_profile\_unique) | Stable and unique string identifying the IAM instance profile | 250 | | [instance\_iam\_role\_arn](#output\_instance\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role | 251 | | [instance\_iam\_role\_name](#output\_instance\_iam\_role\_name) | The name of the IAM role | 252 | | [instance\_iam\_role\_unique\_id](#output\_instance\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | 253 | | [job\_definitions](#output\_job\_definitions) | Map of job defintions created and their associated attributes | 254 | | [job\_queues](#output\_job\_queues) | Map of job queues created and their associated attributes | 255 | | [scheduling\_policies](#output\_scheduling\_policies) | Map of scheduling policies created and their associated attributes | 256 | | [service\_iam\_role\_arn](#output\_service\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role | 257 | | [service\_iam\_role\_name](#output\_service\_iam\_role\_name) | The name of the IAM role | 258 | | [service\_iam\_role\_unique\_id](#output\_service\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | 259 | | [spot\_fleet\_iam\_role\_arn](#output\_spot\_fleet\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role | 260 | | [spot\_fleet\_iam\_role\_name](#output\_spot\_fleet\_iam\_role\_name) | The name of the IAM role | 261 | | [spot\_fleet\_iam\_role\_unique\_id](#output\_spot\_fleet\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | 262 | 263 | 264 | ## License 265 | 266 | Apache-2.0 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-batch/blob/master/LICENSE). 267 | --------------------------------------------------------------------------------