diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bed3c96..ceb4644 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,7 +1,7 @@ # Use this file to define individuals or teams that are responsible for code in a repository. # Read more: # -# Order is important: the last matching pattern takes the most precedence +# Order is important: the last matching pattern has the highest precedence # These owners will be the default owners for everything * @cloudposse/engineering @cloudposse/contributors @@ -12,3 +12,13 @@ # Cloud Posse must review any changes to GitHub actions .github/* @cloudposse/engineering + +# Cloud Posse must review any changes to standard context definition, +# but some changes can be rubber-stamped. +**/context.tf @cloudposse/engineering @cloudposse/approvers +README.md @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers +docs/*.md @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers + +# Cloud Posse Admins must review all changes to CODEOWNERS or the mergify configuration +.github/mergify.yml @cloudposse/admins +.github/CODEOWNERS @cloudposse/admins diff --git a/.github/auto-release.yml b/.github/auto-release.yml new file mode 100644 index 0000000..18a1ca6 --- /dev/null +++ b/.github/auto-release.yml @@ -0,0 +1,45 @@ +name-template: 'v$RESOLVED_VERSION' +tag-template: '$RESOLVED_VERSION' +version-template: '$MAJOR.$MINOR.$PATCH' +version-resolver: + major: + labels: + - 'major' + minor: + labels: + - 'minor' + - 'enhancement' + patch: + labels: + - 'auto-update' + - 'patch' + - 'fix' + - 'bugfix' + - 'bug' + - 'hotfix' + default: 'minor' + +categories: +- title: '🚀 Enhancements' + labels: + - 'enhancement' + - 'patch' +- title: '🐛 Bug Fixes' + labels: + - 'fix' + - 'bugfix' + - 'bug' + - 'hotfix' +- title: '🤖 Automatic Updates' + labels: + - 'auto-update' + +change-template: | +
+ $TITLE @$AUTHOR (#$NUMBER) + + $BODY +
+ +template: | + $CHANGES diff --git a/.github/mergify.yml b/.github/mergify.yml new file mode 100644 index 0000000..485982f --- /dev/null +++ b/.github/mergify.yml @@ -0,0 +1,52 @@ +pull_request_rules: +- name: "approve automated PRs that have passed checks" + conditions: + - "check-success~=test/bats" + - "check-success~=test/readme" + - "check-success~=test/terratest" + - "base=master" + - "author=cloudpossebot" + - "head~=auto-update/.*" + actions: + review: + type: "APPROVE" + bot_account: "cloudposse-mergebot" + message: "We've automatically approved this PR because the checks from the automated Pull Request have passed." + +- name: "merge automated PRs when approved and tests pass" + conditions: + - "check-success~=test/bats" + - "check-success~=test/readme" + - "check-success~=test/terratest" + - "base=master" + - "head~=auto-update/.*" + - "#approved-reviews-by>=1" + - "#changes-requested-reviews-by=0" + - "#commented-reviews-by=0" + - "base=master" + - "author=cloudpossebot" + actions: + merge: + method: "squash" + +- name: "delete the head branch after merge" + conditions: + - "merged" + actions: + delete_head_branch: {} + +- name: "ask to resolve conflict" + conditions: + - "conflict" + actions: + comment: + message: "This pull request is now in conflict. Could you fix it @{{author}}? 🙏" + +- name: "remove outdated reviews" + conditions: + - "base=master" + actions: + dismiss_reviews: + changes_requested: true + approved: true + message: "This Pull Request has been updated, so we're dismissing all reviews." diff --git a/.github/workflows/auto-context.yml b/.github/workflows/auto-context.yml new file mode 100644 index 0000000..df1a857 --- /dev/null +++ b/.github/workflows/auto-context.yml @@ -0,0 +1,55 @@ +name: "auto-context" +on: + schedule: + # Update context.tf nightly + - cron: '0 3 * * *' + +jobs: + update: + if: github.event_name == 'schedule' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Update context.tf + shell: bash + id: update + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + run: | + if [[ -f context.tf ]]; then + echo "Discovered existing context.tf! Fetching most recent version to see if there is an update." + curl -o context.tf -fsSL https://raw.githubusercontent.com/cloudposse/terraform-null-label/master/exports/context.tf + if git diff --no-patch --exit-code context.tf; then + echo "No changes detected! Exiting the job..." + else + echo "context.tf file has changed. Update examples and rebuild README.md." + make init + make github/init/context.tf + make readme/build + echo "::set-output name=create_pull_request=true" + fi + else + echo "This module has not yet been updated to support the context.tf pattern! Please update in order to support automatic updates." + fi + + - name: Create Pull Request + if: steps.update.outputs.create_pull_request == 'true' + uses: cloudposse/actions/github/create-pull-request@0.22.0 + with: + token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} + commit-message: Update context.tf from origin source + title: Update context.tf + body: |- + ## what + This is an auto-generated PR that updates the `context.tf` file to the latest version from `cloudposse/terraform-null-label` + + ## why + To support all the features of the `context` interface. + + branch: auto-update/context.tf + base: master + delete-branch: true + labels: | + auto-update + context diff --git a/.github/workflows/auto-readme.yml b/.github/workflows/auto-readme.yml new file mode 100644 index 0000000..6229e60 --- /dev/null +++ b/.github/workflows/auto-readme.yml @@ -0,0 +1,41 @@ +name: "auto-readme" +on: + schedule: + # Update README.md nightly + - cron: '0 4 * * *' + +jobs: + update: + if: github.event_name == 'schedule' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Update readme + shell: bash + id: update + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + run: | + make init + make readme/build + + - name: Create Pull Request + uses: cloudposse/actions/github/create-pull-request@0.20.0 + with: + token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} + commit-message: Update README.md and docs + title: Update README.md and docs + body: |- + ## what + This is an auto-generated PR that updates the README.md and docs + + ## why + To have most recent changes of README.md and doc from origin templates + + branch: auto-update/readme + base: master + delete-branch: true + labels: | + auto-update + readme diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml new file mode 100644 index 0000000..ccc27be --- /dev/null +++ b/.github/workflows/auto-release.yml @@ -0,0 +1,19 @@ +name: auto-release + +on: + push: + branches: + - master + +jobs: + semver: + runs-on: ubuntu-latest + steps: + # Drafts your next Release notes as Pull Requests are merged into "master" + - uses: release-drafter/release-drafter@v5 + with: + publish: true + prerelease: false + config-name: auto-release.yml + env: + GITHUB_TOKEN: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} diff --git a/.github/workflows/chatops.yml b/.github/workflows/chatops.yml index a6bb11b..4ddc067 100644 --- a/.github/workflows/chatops.yml +++ b/.github/workflows/chatops.yml @@ -9,13 +9,13 @@ jobs: steps: - uses: actions/checkout@v2 - name: "Handle common commands" - uses: cloudposse/actions/github/slash-command-dispatch@0.15.0 + uses: cloudposse/actions/github/slash-command-dispatch@0.22.0 with: token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} reaction-token: ${{ secrets.GITHUB_TOKEN }} repository: cloudposse/actions commands: rebuild-readme, terraform-fmt - permission: none + permission: triage issue-type: pull-request test: @@ -24,13 +24,13 @@ jobs: - name: "Checkout commit" uses: actions/checkout@v2 - name: "Run tests" - uses: cloudposse/actions/github/slash-command-dispatch@0.15.0 + uses: cloudposse/actions/github/slash-command-dispatch@0.22.0 with: token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} reaction-token: ${{ secrets.GITHUB_TOKEN }} repository: cloudposse/actions commands: test - permission: none + permission: triage issue-type: pull-request reactions: false diff --git a/.github/workflows/validate-codeowners.yml b/.github/workflows/validate-codeowners.yml new file mode 100644 index 0000000..386eb28 --- /dev/null +++ b/.github/workflows/validate-codeowners.yml @@ -0,0 +1,25 @@ +name: Validate Codeowners +on: + pull_request: + +jobs: + validate-codeowners: + runs-on: ubuntu-latest + steps: + - name: "Checkout source code at current commit" + uses: actions/checkout@v2 + - uses: mszostok/codeowners-validator@v0.5.0 + if: github.event.pull_request.head.repo.full_name == github.repository + name: "Full check of CODEOWNERS" + with: + # For now, remove "files" check to allow CODEOWNERS to specify non-existent + # files so we can use the same CODEOWNERS file for Terraform and non-Terraform repos + # checks: "files,syntax,owners,duppatterns" + checks: "syntax,owners,duppatterns" + # GitHub access token is required only if the `owners` check is enabled + github_access_token: "${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }}" + - uses: mszostok/codeowners-validator@v0.5.0 + if: github.event.pull_request.head.repo.full_name != github.repository + name: "Syntax check of CODEOWNERS" + with: + checks: "syntax,duppatterns" diff --git a/README.md b/README.md index 367bd86..6e5f4e4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ + # terraform-aws-eks-workers [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-aws-eks-workers.svg)](https://github.com/cloudposse/terraform-aws-eks-workers/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + [![README Header][readme_header_img]][readme_header_link] @@ -73,8 +75,15 @@ If you don't want to use the provided functionality, or want to provide your own ## Usage -**IMPORTANT:** The `master` branch is used in `source` just as an example. In your code, do not pin to `master` because there may be breaking changes between releases. -Instead pin to the release tag (e.g. `?ref=tags/x.y.z`) of one of our [latest releases](https://github.com/cloudposse/terraform-aws-eks-workers/releases). +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. @@ -116,7 +125,9 @@ For a complete example, see [examples/complete](examples/complete) } module "eks_workers" { - source = "git::https://github.com/cloudposse/terraform-aws-eks-workers.git?ref=master" + source = "cloudposse/eks-workers/aws" + # Cloud Posse recommends pinning every module to a specific version + # version = "x.x.x" namespace = var.namespace stage = var.stage name = var.name @@ -156,27 +167,29 @@ Available targets: ``` + ## Requirements | Name | Version | |------|---------| -| terraform | >= 0.12.0, < 0.14.0 | -| aws | ~> 2.0 | -| local | ~> 1.3 | -| template | ~> 2.0 | +| terraform | >= 0.12.26 | +| aws | >= 2.0 | +| local | >= 1.3 | +| template | >= 2.0 | ## Providers | Name | Version | |------|---------| -| aws | ~> 2.0 | -| template | ~> 2.0 | +| aws | >= 2.0 | +| template | >= 2.0 | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | additional\_security\_group\_ids | Additional list of security groups that will be attached to the autoscaling group | `list(string)` | `[]` | no | +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | | after\_cluster\_joining\_userdata | Additional commands to execute on each worker node after joining the EKS cluster (after executing the `bootstrap.sh` script). For mot info, see https://kubedex.com/90-days-of-aws-eks-in-production | `string` | `""` | no | | allowed\_cidr\_blocks | List of CIDR blocks to be allowed to connect to the worker nodes | `list(string)` | `[]` | no | | allowed\_security\_groups | List of Security Group IDs to be allowed to connect to the worker nodes | `list(string)` | `[]` | no | @@ -193,6 +206,7 @@ Available targets: | cluster\_name | The name of the EKS cluster | `string` | n/a | yes | | cluster\_security\_group\_id | Security Group ID of the EKS cluster | `string` | n/a | yes | | cluster\_security\_group\_ingress\_enabled | Whether to enable the EKS cluster Security Group as ingress to workers Security Group | `bool` | `true` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. |
object({
enabled = bool
namespace = string
environment = string
stage = string
name = string
delimiter = string
attributes = list(string)
tags = map(string)
additional_tag_map = map(string)
regex_replace_chars = string
label_order = list(string)
id_length_limit = number
})
|
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_order": [],
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | | cpu\_utilization\_high\_evaluation\_periods | The number of periods over which data is compared to the specified threshold | `number` | `2` | no | | cpu\_utilization\_high\_period\_seconds | The period in seconds over which the specified statistic is applied | `number` | `300` | no | | cpu\_utilization\_high\_statistic | The statistic to apply to the alarm's associated metric. Either of the following is supported: `SampleCount`, `Average`, `Sum`, `Minimum`, `Maximum` | `string` | `"Average"` | no | @@ -203,35 +217,39 @@ Available targets: | cpu\_utilization\_low\_threshold\_percent | The value against which the specified statistic is compared | `number` | `10` | no | | credit\_specification | Customize the credit specification of the instances |
object({
cpu_credits = string
})
| `null` | no | | default\_cooldown | The amount of time, in seconds, after a scaling activity completes before another scaling activity can start | `number` | `300` | no | -| delimiter | Delimiter to be used between `namespace`, `stage`, `name` and `attributes` | `string` | `"-"` | no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | | disable\_api\_termination | If `true`, enables EC2 Instance Termination Protection | `bool` | `false` | no | | ebs\_optimized | If true, the launched EC2 instance will be EBS-optimized | `bool` | `false` | no | | eks\_worker\_ami\_name\_filter | AMI name filter to lookup the most recent EKS AMI if `image_id` is not provided | `string` | `"amazon-eks-node-*"` | no | | eks\_worker\_ami\_name\_regex | A regex string to apply to the AMI list returned by AWS | `string` | `"^amazon-eks-node-[1-9,.]+-v[0-9]{8}$"` | no | | elastic\_gpu\_specifications | Specifications of Elastic GPU to attach to the instances |
object({
type = string
})
| `null` | no | | enable\_monitoring | Enable/disable detailed monitoring | `bool` | `true` | no | -| enabled | Whether to create the resources. Set to `false` to prevent the module from creating any resources | `bool` | `true` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | | enabled\_metrics | A list of metrics to collect. The allowed values are `GroupMinSize`, `GroupMaxSize`, `GroupDesiredCapacity`, `GroupInServiceInstances`, `GroupPendingInstances`, `GroupStandbyInstances`, `GroupTerminatingInstances`, `GroupTotalInstances` | `list(string)` |
[
"GroupMinSize",
"GroupMaxSize",
"GroupDesiredCapacity",
"GroupInServiceInstances",
"GroupPendingInstances",
"GroupStandbyInstances",
"GroupTerminatingInstances",
"GroupTotalInstances"
]
| no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | | force\_delete | Allows deleting the autoscaling group without waiting for all instances in the pool to terminate. You can force an autoscaling group to delete even if it's in the process of scaling a resource. Normally, Terraform drains all the instances before deleting the group. This bypasses that behavior and potentially leaves resources dangling | `bool` | `false` | no | | health\_check\_grace\_period | Time (in seconds) after instance comes into service before checking health | `number` | `300` | no | | health\_check\_type | Controls how health checking is done. Valid values are `EC2` or `ELB` | `string` | `"EC2"` | no | +| id\_length\_limit | Limit `id` to this many characters.
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | | image\_id | EC2 image ID to launch. If not provided, the module will lookup the most recent EKS AMI. See https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html for more details on EKS-optimized images | `string` | `""` | no | | instance\_initiated\_shutdown\_behavior | Shutdown behavior for the instances. Can be `stop` or `terminate` | `string` | `"terminate"` | no | | instance\_market\_options | The market (purchasing) option for the instances |
object({
market_type = string
spot_options = object({
block_duration_minutes = number
instance_interruption_behavior = string
max_price = number
spot_instance_type = string
valid_until = string
})
})
| `null` | no | | instance\_type | Instance type to launch | `string` | n/a | yes | | key\_name | SSH key name that should be used for the instance | `string` | `""` | no | | kubelet\_extra\_args | Extra arguments to pass to kubelet, like "--register-with-taints=dedicated=ci-cd:NoSchedule --node-labels=purpose=ci-worker" | `string` | `""` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | | load\_balancers | A list of elastic load balancer names to add to the autoscaling group. Only valid for classic load balancers. For ALBs, use `target_group_arns` instead | `list(string)` | `[]` | no | | max\_size | The maximum size of the autoscale group | `number` | n/a | yes | | metrics\_granularity | The granularity to associate with the metrics to collect. The only valid value is 1Minute | `string` | `"1Minute"` | no | | min\_elb\_capacity | Setting this causes Terraform to wait for this number of instances to show up healthy in the ELB only on creation. Updates will not wait on ELB instance number changes | `number` | `0` | no | | min\_size | The minimum size of the autoscale group | `number` | n/a | yes | | mixed\_instances\_policy | policy to used mixed group of on demand/spot of differing types. Launch template is automatically generated. https://www.terraform.io/docs/providers/aws/r/autoscaling_group.html#mixed_instances_policy-1 |
object({
instances_distribution = object({
on_demand_allocation_strategy = string
on_demand_base_capacity = number
on_demand_percentage_above_base_capacity = number
spot_allocation_strategy = string
spot_instance_pools = number
spot_max_price = string
})
override = list(object({
instance_type = string
weighted_capacity = number
}))
})
| `null` | no | -| name | Solution name, e.g. 'app' or 'cluster' | `string` | `"app"` | no | -| namespace | Namespace, which could be your organization name, e.g. 'eg' or 'cp' | `string` | `""` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | | placement | The placement specifications of the instances |
object({
affinity = string
availability_zone = string
group_name = string
host_id = string
tenancy = string
})
| `null` | no | | placement\_group | The name of the placement group into which you'll launch your instances, if any | `string` | `""` | no | | protect\_from\_scale\_in | Allows setting instance protection. The autoscaling group will not select instances with this setting for terminination during scale in events | `bool` | `false` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | | scale\_down\_adjustment\_type | Specifies whether the adjustment is an absolute number or a percentage of the current capacity. Valid values are `ChangeInCapacity`, `ExactCapacity` and `PercentChangeInCapacity` | `string` | `"ChangeInCapacity"` | no | | scale\_down\_cooldown\_seconds | The amount of time, in seconds, after a scaling activity completes and before the next scaling activity can start | `number` | `300` | no | | scale\_down\_policy\_type | The scalling policy type, either `SimpleScaling`, `StepScaling` or `TargetTrackingScaling` | `string` | `"SimpleScaling"` | no | @@ -241,10 +259,10 @@ Available targets: | scale\_up\_policy\_type | The scalling policy type, either `SimpleScaling`, `StepScaling` or `TargetTrackingScaling` | `string` | `"SimpleScaling"` | no | | scale\_up\_scaling\_adjustment | The number of instances by which to scale. `scale_up_adjustment_type` determines the interpretation of this number (e.g. as an absolute number or as a percentage of the existing Auto Scaling group size). A positive increment adds to the current capacity and a negative value removes from the current capacity | `number` | `1` | no | | service\_linked\_role\_arn | The ARN of the service-linked role that the ASG will use to call other AWS services | `string` | `""` | no | -| stage | Stage, e.g. 'prod', 'staging', 'dev', or 'test' | `string` | `""` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | | subnet\_ids | A list of subnet IDs to launch resources in | `list(string)` | n/a | yes | | suspended\_processes | A list of processes to suspend for the AutoScaling Group. The allowed values are `Launch`, `Terminate`, `HealthCheck`, `ReplaceUnhealthy`, `AZRebalance`, `AlarmNotification`, `ScheduledActions`, `AddToLoadBalancer`. Note that if you suspend either the `Launch` or `Terminate` process types, it can prevent your autoscaling group from functioning properly. | `list(string)` | `[]` | no | -| tags | Additional tags (e.g. `{ BusinessUnit = "XYZ" }` | `map(string)` | `{}` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | | target\_group\_arns | A list of aws\_alb\_target\_group ARNs, for use with Application Load Balancing | `list(string)` | `[]` | no | | termination\_policies | A list of policies to decide how the instances in the auto scale group should be terminated. The allowed values are `OldestInstance`, `NewestInstance`, `OldestLaunchConfiguration`, `ClosestToNextInstanceHour`, `Default` | `list(string)` |
[
"Default"
]
| no | | use\_custom\_image\_id | If set to `true`, will use variable `image_id` for the EKS workers inside autoscaling group | `bool` | `false` | no | @@ -278,6 +296,7 @@ Available targets: | workers\_role\_arn | ARN of the worker nodes IAM role | | workers\_role\_name | Name of the worker nodes IAM role | + @@ -432,8 +451,10 @@ Check out [our other projects][github], [follow us on twitter][twitter], [apply ### Contributors + | [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | |---|---|---| + [osterman_homepage]: https://github.com/osterman [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png diff --git a/README.yaml b/README.yaml index b0131f0..3482536 100644 --- a/README.yaml +++ b/README.yaml @@ -102,7 +102,9 @@ usage: |2- } module "eks_workers" { - source = "git::https://github.com/cloudposse/terraform-aws-eks-workers.git?ref=master" + source = "cloudposse/eks-workers/aws" + # Cloud Posse recommends pinning every module to a specific version + # version = "x.x.x" namespace = var.namespace stage = var.stage name = var.name diff --git a/context.tf b/context.tf new file mode 100644 index 0000000..e5734b7 --- /dev/null +++ b/context.tf @@ -0,0 +1,169 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + + +module "this" { + source = "cloudposse/label/null" + version = "0.22.0" // requires Terraform >= 0.12.26 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/docs/terraform.md b/docs/terraform.md index d1152d5..e0ce08c 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -1,24 +1,26 @@ + ## Requirements | Name | Version | |------|---------| -| terraform | >= 0.12.0, < 0.14.0 | -| aws | ~> 2.0 | -| local | ~> 1.3 | -| template | ~> 2.0 | +| terraform | >= 0.12.26 | +| aws | >= 2.0 | +| local | >= 1.3 | +| template | >= 2.0 | ## Providers | Name | Version | |------|---------| -| aws | ~> 2.0 | -| template | ~> 2.0 | +| aws | >= 2.0 | +| template | >= 2.0 | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | additional\_security\_group\_ids | Additional list of security groups that will be attached to the autoscaling group | `list(string)` | `[]` | no | +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | | after\_cluster\_joining\_userdata | Additional commands to execute on each worker node after joining the EKS cluster (after executing the `bootstrap.sh` script). For mot info, see https://kubedex.com/90-days-of-aws-eks-in-production | `string` | `""` | no | | allowed\_cidr\_blocks | List of CIDR blocks to be allowed to connect to the worker nodes | `list(string)` | `[]` | no | | allowed\_security\_groups | List of Security Group IDs to be allowed to connect to the worker nodes | `list(string)` | `[]` | no | @@ -35,6 +37,7 @@ | cluster\_name | The name of the EKS cluster | `string` | n/a | yes | | cluster\_security\_group\_id | Security Group ID of the EKS cluster | `string` | n/a | yes | | cluster\_security\_group\_ingress\_enabled | Whether to enable the EKS cluster Security Group as ingress to workers Security Group | `bool` | `true` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. |
object({
enabled = bool
namespace = string
environment = string
stage = string
name = string
delimiter = string
attributes = list(string)
tags = map(string)
additional_tag_map = map(string)
regex_replace_chars = string
label_order = list(string)
id_length_limit = number
})
|
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_order": [],
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | | cpu\_utilization\_high\_evaluation\_periods | The number of periods over which data is compared to the specified threshold | `number` | `2` | no | | cpu\_utilization\_high\_period\_seconds | The period in seconds over which the specified statistic is applied | `number` | `300` | no | | cpu\_utilization\_high\_statistic | The statistic to apply to the alarm's associated metric. Either of the following is supported: `SampleCount`, `Average`, `Sum`, `Minimum`, `Maximum` | `string` | `"Average"` | no | @@ -45,35 +48,39 @@ | cpu\_utilization\_low\_threshold\_percent | The value against which the specified statistic is compared | `number` | `10` | no | | credit\_specification | Customize the credit specification of the instances |
object({
cpu_credits = string
})
| `null` | no | | default\_cooldown | The amount of time, in seconds, after a scaling activity completes before another scaling activity can start | `number` | `300` | no | -| delimiter | Delimiter to be used between `namespace`, `stage`, `name` and `attributes` | `string` | `"-"` | no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | | disable\_api\_termination | If `true`, enables EC2 Instance Termination Protection | `bool` | `false` | no | | ebs\_optimized | If true, the launched EC2 instance will be EBS-optimized | `bool` | `false` | no | | eks\_worker\_ami\_name\_filter | AMI name filter to lookup the most recent EKS AMI if `image_id` is not provided | `string` | `"amazon-eks-node-*"` | no | | eks\_worker\_ami\_name\_regex | A regex string to apply to the AMI list returned by AWS | `string` | `"^amazon-eks-node-[1-9,.]+-v[0-9]{8}$"` | no | | elastic\_gpu\_specifications | Specifications of Elastic GPU to attach to the instances |
object({
type = string
})
| `null` | no | | enable\_monitoring | Enable/disable detailed monitoring | `bool` | `true` | no | -| enabled | Whether to create the resources. Set to `false` to prevent the module from creating any resources | `bool` | `true` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | | enabled\_metrics | A list of metrics to collect. The allowed values are `GroupMinSize`, `GroupMaxSize`, `GroupDesiredCapacity`, `GroupInServiceInstances`, `GroupPendingInstances`, `GroupStandbyInstances`, `GroupTerminatingInstances`, `GroupTotalInstances` | `list(string)` |
[
"GroupMinSize",
"GroupMaxSize",
"GroupDesiredCapacity",
"GroupInServiceInstances",
"GroupPendingInstances",
"GroupStandbyInstances",
"GroupTerminatingInstances",
"GroupTotalInstances"
]
| no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | | force\_delete | Allows deleting the autoscaling group without waiting for all instances in the pool to terminate. You can force an autoscaling group to delete even if it's in the process of scaling a resource. Normally, Terraform drains all the instances before deleting the group. This bypasses that behavior and potentially leaves resources dangling | `bool` | `false` | no | | health\_check\_grace\_period | Time (in seconds) after instance comes into service before checking health | `number` | `300` | no | | health\_check\_type | Controls how health checking is done. Valid values are `EC2` or `ELB` | `string` | `"EC2"` | no | +| id\_length\_limit | Limit `id` to this many characters.
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | | image\_id | EC2 image ID to launch. If not provided, the module will lookup the most recent EKS AMI. See https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html for more details on EKS-optimized images | `string` | `""` | no | | instance\_initiated\_shutdown\_behavior | Shutdown behavior for the instances. Can be `stop` or `terminate` | `string` | `"terminate"` | no | | instance\_market\_options | The market (purchasing) option for the instances |
object({
market_type = string
spot_options = object({
block_duration_minutes = number
instance_interruption_behavior = string
max_price = number
spot_instance_type = string
valid_until = string
})
})
| `null` | no | | instance\_type | Instance type to launch | `string` | n/a | yes | | key\_name | SSH key name that should be used for the instance | `string` | `""` | no | | kubelet\_extra\_args | Extra arguments to pass to kubelet, like "--register-with-taints=dedicated=ci-cd:NoSchedule --node-labels=purpose=ci-worker" | `string` | `""` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | | load\_balancers | A list of elastic load balancer names to add to the autoscaling group. Only valid for classic load balancers. For ALBs, use `target_group_arns` instead | `list(string)` | `[]` | no | | max\_size | The maximum size of the autoscale group | `number` | n/a | yes | | metrics\_granularity | The granularity to associate with the metrics to collect. The only valid value is 1Minute | `string` | `"1Minute"` | no | | min\_elb\_capacity | Setting this causes Terraform to wait for this number of instances to show up healthy in the ELB only on creation. Updates will not wait on ELB instance number changes | `number` | `0` | no | | min\_size | The minimum size of the autoscale group | `number` | n/a | yes | | mixed\_instances\_policy | policy to used mixed group of on demand/spot of differing types. Launch template is automatically generated. https://www.terraform.io/docs/providers/aws/r/autoscaling_group.html#mixed_instances_policy-1 |
object({
instances_distribution = object({
on_demand_allocation_strategy = string
on_demand_base_capacity = number
on_demand_percentage_above_base_capacity = number
spot_allocation_strategy = string
spot_instance_pools = number
spot_max_price = string
})
override = list(object({
instance_type = string
weighted_capacity = number
}))
})
| `null` | no | -| name | Solution name, e.g. 'app' or 'cluster' | `string` | `"app"` | no | -| namespace | Namespace, which could be your organization name, e.g. 'eg' or 'cp' | `string` | `""` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | | placement | The placement specifications of the instances |
object({
affinity = string
availability_zone = string
group_name = string
host_id = string
tenancy = string
})
| `null` | no | | placement\_group | The name of the placement group into which you'll launch your instances, if any | `string` | `""` | no | | protect\_from\_scale\_in | Allows setting instance protection. The autoscaling group will not select instances with this setting for terminination during scale in events | `bool` | `false` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | | scale\_down\_adjustment\_type | Specifies whether the adjustment is an absolute number or a percentage of the current capacity. Valid values are `ChangeInCapacity`, `ExactCapacity` and `PercentChangeInCapacity` | `string` | `"ChangeInCapacity"` | no | | scale\_down\_cooldown\_seconds | The amount of time, in seconds, after a scaling activity completes and before the next scaling activity can start | `number` | `300` | no | | scale\_down\_policy\_type | The scalling policy type, either `SimpleScaling`, `StepScaling` or `TargetTrackingScaling` | `string` | `"SimpleScaling"` | no | @@ -83,10 +90,10 @@ | scale\_up\_policy\_type | The scalling policy type, either `SimpleScaling`, `StepScaling` or `TargetTrackingScaling` | `string` | `"SimpleScaling"` | no | | scale\_up\_scaling\_adjustment | The number of instances by which to scale. `scale_up_adjustment_type` determines the interpretation of this number (e.g. as an absolute number or as a percentage of the existing Auto Scaling group size). A positive increment adds to the current capacity and a negative value removes from the current capacity | `number` | `1` | no | | service\_linked\_role\_arn | The ARN of the service-linked role that the ASG will use to call other AWS services | `string` | `""` | no | -| stage | Stage, e.g. 'prod', 'staging', 'dev', or 'test' | `string` | `""` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | | subnet\_ids | A list of subnet IDs to launch resources in | `list(string)` | n/a | yes | | suspended\_processes | A list of processes to suspend for the AutoScaling Group. The allowed values are `Launch`, `Terminate`, `HealthCheck`, `ReplaceUnhealthy`, `AZRebalance`, `AlarmNotification`, `ScheduledActions`, `AddToLoadBalancer`. Note that if you suspend either the `Launch` or `Terminate` process types, it can prevent your autoscaling group from functioning properly. | `list(string)` | `[]` | no | -| tags | Additional tags (e.g. `{ BusinessUnit = "XYZ" }` | `map(string)` | `{}` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | | target\_group\_arns | A list of aws\_alb\_target\_group ARNs, for use with Application Load Balancing | `list(string)` | `[]` | no | | termination\_policies | A list of policies to decide how the instances in the auto scale group should be terminated. The allowed values are `OldestInstance`, `NewestInstance`, `OldestLaunchConfiguration`, `ClosestToNextInstanceHour`, `Default` | `list(string)` |
[
"Default"
]
| no | | use\_custom\_image\_id | If set to `true`, will use variable `image_id` for the EKS workers inside autoscaling group | `bool` | `false` | no | @@ -120,3 +127,4 @@ | workers\_role\_arn | ARN of the worker nodes IAM role | | workers\_role\_name | Name of the worker nodes IAM role | + diff --git a/examples/complete/context.tf b/examples/complete/context.tf new file mode 100644 index 0000000..e5734b7 --- /dev/null +++ b/examples/complete/context.tf @@ -0,0 +1,169 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + + +module "this" { + source = "cloudposse/label/null" + version = "0.22.0" // requires Terraform >= 0.12.26 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 1fd56d0..abe5268 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -6,37 +6,37 @@ locals { # The usage of the specific kubernetes.io/cluster/* resource tags below are required # for EKS and Kubernetes to discover and manage networking resources # https://www.terraform.io/docs/providers/aws/guides/eks-getting-started.html#base-vpc-networking - tags = merge(var.tags, map("kubernetes.io/cluster/${var.cluster_name}", "shared")) + tags = { "kubernetes.io/cluster/${var.cluster_name}" = "shared" } } module "vpc" { - source = "git::https://github.com/cloudposse/terraform-aws-vpc.git?ref=tags/0.8.0" - namespace = var.namespace - stage = var.stage - name = var.name + source = "cloudposse/vpc/aws" + version = "0.18.1" + cidr_block = "172.16.0.0/16" tags = local.tags + + context = module.this.context } module "subnets" { - source = "git::https://github.com/cloudposse/terraform-aws-dynamic-subnets.git?ref=tags/0.16.0" + source = "cloudposse/dynamic-subnets/aws" + version = "0.32.0" + availability_zones = var.availability_zones - namespace = var.namespace - stage = var.stage - name = var.name vpc_id = module.vpc.vpc_id igw_id = module.vpc.igw_id cidr_block = module.vpc.vpc_cidr_block nat_gateway_enabled = false nat_instance_enabled = false tags = local.tags + + context = module.this.context } module "eks_workers" { - source = "../../" - namespace = var.namespace - stage = var.stage - name = var.name + source = "../../" + instance_type = var.instance_type vpc_id = module.vpc.vpc_id subnet_ids = module.subnets.public_subnet_ids @@ -56,4 +56,6 @@ module "eks_workers" { autoscaling_policies_enabled = var.autoscaling_policies_enabled cpu_utilization_high_threshold_percent = var.cpu_utilization_high_threshold_percent cpu_utilization_low_threshold_percent = var.cpu_utilization_low_threshold_percent + + context = module.this.context } diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf index be3316d..d379991 100644 --- a/examples/complete/variables.tf +++ b/examples/complete/variables.tf @@ -8,26 +8,6 @@ variable "availability_zones" { description = "List of availability zones" } -variable "namespace" { - type = string - description = "Namespace, which could be your organization name, e.g. 'eg' or 'cp'" -} - -variable "stage" { - type = string - description = "Stage, e.g. 'prod', 'staging', 'dev', or 'test'" -} - -variable "name" { - type = string - description = "Solution name, e.g. 'app' or 'cluster'" -} - -variable "tags" { - type = map(string) - default = {} - description = "Additional tags (e.g. `{ BusinessUnit = \"XYZ\" }`" -} variable "cluster_name" { type = string diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf index 1db4048..cc861b8 100644 --- a/examples/complete/versions.tf +++ b/examples/complete/versions.tf @@ -1,9 +1,18 @@ terraform { - required_version = "~> 0.12.0" + required_version = ">= 0.12.26" required_providers { - aws = "~> 2.0" - template = "~> 2.0" - local = "~> 1.3" + aws = { + source = "hashicorp/aws" + version = ">= 2.0" + } + template = { + source = "hashicorp/template" + version = ">= 2.0" + } + local = { + source = "hashicorp/local" + version = ">= 1.3" + } } } diff --git a/main.tf b/main.tf index bbe8587..00c4e17 100644 --- a/main.tf +++ b/main.tf @@ -1,28 +1,25 @@ locals { - tags = merge( - var.tags, - { - "kubernetes.io/cluster/${var.cluster_name}" = "owned" - } - ) + enabled = module.this.enabled + tags = { + "kubernetes.io/cluster/${var.cluster_name}" = "owned" + } workers_role_arn = var.use_existing_aws_iam_instance_profile ? join("", data.aws_iam_instance_profile.default.*.role_arn) : join("", aws_iam_role.default.*.arn) workers_role_name = var.use_existing_aws_iam_instance_profile ? join("", data.aws_iam_instance_profile.default.*.role_name) : join("", aws_iam_role.default.*.name) } module "label" { - source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.17.0" - namespace = var.namespace - stage = var.stage - name = var.name - delimiter = var.delimiter + source = "cloudposse/label/null" + version = "0.22.0" + attributes = compact(concat(var.attributes, ["workers"])) tags = local.tags - enabled = var.enabled + + context = module.this.context } data "aws_iam_policy_document" "assume_role" { - count = var.enabled && var.use_existing_aws_iam_instance_profile == false ? 1 : 0 + count = local.enabled && var.use_existing_aws_iam_instance_profile == false ? 1 : 0 statement { effect = "Allow" @@ -36,44 +33,44 @@ data "aws_iam_policy_document" "assume_role" { } resource "aws_iam_role" "default" { - count = var.enabled && var.use_existing_aws_iam_instance_profile == false ? 1 : 0 + count = local.enabled && var.use_existing_aws_iam_instance_profile == false ? 1 : 0 name = module.label.id assume_role_policy = join("", data.aws_iam_policy_document.assume_role.*.json) tags = module.label.tags } resource "aws_iam_role_policy_attachment" "amazon_eks_worker_node_policy" { - count = var.enabled && var.use_existing_aws_iam_instance_profile == false ? 1 : 0 + count = local.enabled && var.use_existing_aws_iam_instance_profile == false ? 1 : 0 policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy" role = join("", aws_iam_role.default.*.name) } resource "aws_iam_role_policy_attachment" "amazon_eks_cni_policy" { - count = var.enabled && var.use_existing_aws_iam_instance_profile == false ? 1 : 0 + count = local.enabled && var.use_existing_aws_iam_instance_profile == false ? 1 : 0 policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy" role = join("", aws_iam_role.default.*.name) } resource "aws_iam_role_policy_attachment" "amazon_ec2_container_registry_read_only" { - count = var.enabled && var.use_existing_aws_iam_instance_profile == false ? 1 : 0 + count = local.enabled && var.use_existing_aws_iam_instance_profile == false ? 1 : 0 policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" role = join("", aws_iam_role.default.*.name) } resource "aws_iam_role_policy_attachment" "existing_policies_attach_to_eks_workers_role" { - count = var.enabled && var.use_existing_aws_iam_instance_profile == false ? var.workers_role_policy_arns_count : 0 + count = local.enabled && var.use_existing_aws_iam_instance_profile == false ? var.workers_role_policy_arns_count : 0 policy_arn = var.workers_role_policy_arns[count.index] role = join("", aws_iam_role.default.*.name) } resource "aws_iam_instance_profile" "default" { - count = var.enabled && var.use_existing_aws_iam_instance_profile == false ? 1 : 0 + count = local.enabled && var.use_existing_aws_iam_instance_profile == false ? 1 : 0 name = module.label.id role = join("", aws_iam_role.default.*.name) } resource "aws_security_group" "default" { - count = var.enabled && var.use_existing_security_group == false ? 1 : 0 + count = local.enabled && var.use_existing_security_group == false ? 1 : 0 name = module.label.id description = "Security Group for EKS worker nodes" vpc_id = var.vpc_id @@ -81,7 +78,7 @@ resource "aws_security_group" "default" { } resource "aws_security_group_rule" "egress" { - count = var.enabled && var.use_existing_security_group == false ? 1 : 0 + count = local.enabled && var.use_existing_security_group == false ? 1 : 0 description = "Allow all egress traffic" from_port = 0 to_port = 0 @@ -92,7 +89,7 @@ resource "aws_security_group_rule" "egress" { } resource "aws_security_group_rule" "ingress_self" { - count = var.enabled && var.use_existing_security_group == false ? 1 : 0 + count = local.enabled && var.use_existing_security_group == false ? 1 : 0 description = "Allow nodes to communicate with each other" from_port = 0 to_port = 65535 @@ -103,7 +100,7 @@ resource "aws_security_group_rule" "ingress_self" { } resource "aws_security_group_rule" "ingress_cluster" { - count = var.enabled && var.cluster_security_group_ingress_enabled && var.use_existing_security_group == false ? 1 : 0 + count = local.enabled && var.cluster_security_group_ingress_enabled && var.use_existing_security_group == false ? 1 : 0 description = "Allow worker kubelets and pods to receive communication from the cluster control plane" from_port = 0 to_port = 65535 @@ -114,7 +111,7 @@ resource "aws_security_group_rule" "ingress_cluster" { } resource "aws_security_group_rule" "ingress_security_groups" { - count = var.enabled && var.use_existing_security_group == false ? length(var.allowed_security_groups) : 0 + count = local.enabled && var.use_existing_security_group == false ? length(var.allowed_security_groups) : 0 description = "Allow inbound traffic from existing Security Groups" from_port = 0 to_port = 65535 @@ -125,7 +122,7 @@ resource "aws_security_group_rule" "ingress_security_groups" { } resource "aws_security_group_rule" "ingress_cidr_blocks" { - count = var.enabled && length(var.allowed_cidr_blocks) > 0 && var.use_existing_security_group == false ? 1 : 0 + count = local.enabled && length(var.allowed_cidr_blocks) > 0 && var.use_existing_security_group == false ? 1 : 0 description = "Allow inbound traffic from CIDR blocks" from_port = 0 to_port = 0 @@ -136,7 +133,7 @@ resource "aws_security_group_rule" "ingress_cidr_blocks" { } data "aws_ami" "eks_worker" { - count = var.enabled && var.use_custom_image_id == false ? 1 : 0 + count = local.enabled && var.use_custom_image_id == false ? 1 : 0 most_recent = true name_regex = var.eks_worker_ami_name_regex @@ -150,7 +147,7 @@ data "aws_ami" "eks_worker" { } data "template_file" "userdata" { - count = var.enabled ? 1 : 0 + count = local.enabled ? 1 : 0 template = file("${path.module}/userdata.tpl") vars = { @@ -165,19 +162,20 @@ data "template_file" "userdata" { } data "aws_iam_instance_profile" "default" { - count = var.enabled && var.use_existing_aws_iam_instance_profile ? 1 : 0 + count = local.enabled && var.use_existing_aws_iam_instance_profile ? 1 : 0 name = var.aws_iam_instance_profile_name } module "autoscale_group" { - source = "git::https://github.com/cloudposse/terraform-aws-ec2-autoscale-group.git?ref=tags/0.7.1" - - enabled = var.enabled - namespace = var.namespace - stage = var.stage - name = var.name - delimiter = var.delimiter - attributes = var.attributes + source = "cloudposse/ec2-autoscale-group/aws" + version = "0.7.2" + + enabled = local.enabled + namespace = module.this.namespace + stage = module.this.stage + name = module.this.name + delimiter = module.this.delimiter + attributes = module.this.attributes tags = merge(module.label.tags, var.autoscaling_group_tags) image_id = var.use_custom_image_id ? var.image_id : join("", data.aws_ami.eks_worker.*.id) diff --git a/test/src/Gopkg.lock b/test/src/Gopkg.lock deleted file mode 100644 index 87bb6bd..0000000 --- a/test/src/Gopkg.lock +++ /dev/null @@ -1,92 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" - name = "github.com/davecgh/go-spew" - packages = ["spew"] - pruneopts = "UT" - revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" - version = "v1.1.1" - -[[projects]] - digest = "1:75d6042fc66aebc974cc49b0c6c7cc3b9adb5f8130fbfa0dbec0820d990afa25" - name = "github.com/gruntwork-io/terratest" - packages = [ - "modules/collections", - "modules/customerrors", - "modules/files", - "modules/logger", - "modules/retry", - "modules/shell", - "modules/ssh", - "modules/terraform", - ] - pruneopts = "UT" - revision = "892abb2c35878d0808101bbfe6559e931dc2d354" - version = "v0.16.0" - -[[projects]] - digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" - name = "github.com/pmezard/go-difflib" - packages = ["difflib"] - pruneopts = "UT" - revision = "792786c7400a136282c1664665ae0a8db921c6c2" - version = "v1.0.0" - -[[projects]] - digest = "1:5da8ce674952566deae4dbc23d07c85caafc6cfa815b0b3e03e41979cedb8750" - name = "github.com/stretchr/testify" - packages = [ - "assert", - "require", - ] - pruneopts = "UT" - revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053" - version = "v1.3.0" - -[[projects]] - branch = "master" - digest = "1:831470c2758c8b733941144f2803a0ccad0632c5a767415b777ebd296b5f463e" - name = "golang.org/x/crypto" - packages = [ - "curve25519", - "ed25519", - "ed25519/internal/edwards25519", - "internal/chacha20", - "internal/subtle", - "poly1305", - "ssh", - "ssh/agent", - ] - pruneopts = "UT" - revision = "22d7a77e9e5f409e934ed268692e56707cd169e5" - -[[projects]] - branch = "master" - digest = "1:76ee51c3f468493aff39dbacc401e8831fbb765104cbf613b89bef01cf4bad70" - name = "golang.org/x/net" - packages = ["context"] - pruneopts = "UT" - revision = "f3200d17e092c607f615320ecaad13d87ad9a2b3" - -[[projects]] - branch = "master" - digest = "1:181f3fd33e620b958b5ab77da177cf775cdcccd7db82963607875fbd09ae995e" - name = "golang.org/x/sys" - packages = [ - "cpu", - "unix", - ] - pruneopts = "UT" - revision = "9cd6430ef91e39e1a0ec0470cf1321a33ef1b887" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - input-imports = [ - "github.com/gruntwork-io/terratest/modules/terraform", - "github.com/stretchr/testify/assert", - ] - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/test/src/Gopkg.toml b/test/src/Gopkg.toml deleted file mode 100644 index 995bac5..0000000 --- a/test/src/Gopkg.toml +++ /dev/null @@ -1,7 +0,0 @@ -[[constraint]] - name = "github.com/stretchr/testify" - version = "1.2.2" - -[prune] - go-tests = true - unused-packages = true diff --git a/test/src/Makefile b/test/src/Makefile index f1920ff..b772822 100644 --- a/test/src/Makefile +++ b/test/src/Makefile @@ -1,50 +1,30 @@ -PACKAGE = terraform-aws-eks-workers -GOEXE ?= /usr/bin/go -GOPATH = $(CURDIR)/.gopath -GOBIN = $(GOPATH)/bin -BASE = $(GOPATH)/src/$(PACKAGE) -PATH := $(PATH):$(GOBIN) - -export TF_DATA_DIR ?= $(CURDIR)/.terraform export TF_CLI_ARGS_init ?= -get-plugins=true -export GOPATH +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) +.DEFAULT_GOAL : all .PHONY: all + ## Default target all: test -ifneq (,$(wildcard /sbin/apk)) -## Install go, if not installed -$(GOEXE): - apk add --update go -endif - -ifeq ($(shell uname -s),Linux) -## Install all `dep`, if not installed -$(GOBIN)/dep: - @mkdir -p $(GOBIN) - @curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh -endif - -## Prepare the GOPATH -$(BASE): $(GOEXE) - @mkdir -p $(dir $@) - @ln -sf $(CURDIR) $@ - -## Download vendor dependencies to vendor/ -$(BASE)/vendor: $(BASE) $(GOBIN)/dep - cd $(BASE) && dep ensure - .PHONY : init ## Initialize tests -init: $(BASE)/vendor +init: + @exit 0 .PHONY : test ## Run tests test: init - cd $(BASE) && go test -v -timeout 30m -run TestExamplesComplete + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -e PATH="/usr/local/terraform/$(TERRAFORM_VERSION)/bin:/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test .PHONY : clean ## Clean up files clean: - rm -rf .gopath/ vendor/ $(TF_DATA_DIR) + rm -rf ../../examples/complete/*.tfstate* diff --git a/test/src/go.mod b/test/src/go.mod new file mode 100644 index 0000000..7b5403e --- /dev/null +++ b/test/src/go.mod @@ -0,0 +1,13 @@ +module github.com/cloudposse/terraform-aws-eks-workers + +go 1.14 + +require ( + github.com/aws/aws-sdk-go v1.36.7 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-sql-driver/mysql v1.5.0 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/gruntwork-io/terratest v0.16.0 + github.com/pquerna/otp v1.3.0 // indirect + github.com/stretchr/testify v1.3.0 +) diff --git a/test/src/go.sum b/test/src/go.sum new file mode 100644 index 0000000..11e0b94 --- /dev/null +++ b/test/src/go.sum @@ -0,0 +1,43 @@ +github.com/aws/aws-sdk-go v1.36.7 h1:XoJPAjKoqvdL531XGWxKYn5eGX/xMoXzMN5fBtoyfSY= +github.com/aws/aws-sdk-go v1.36.7/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gruntwork-io/terratest v0.16.0 h1:8dDdkAzqwVDclmefcy//oBPWs5bVrWuKYCUwG0WFG4c= +github.com/gruntwork-io/terratest v0.16.0/go.mod h1:NjUn6YXA5Skxt8Rs20t3isYx5Rl+EgvGB8/+RRXddqk= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs= +github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/variables.tf b/variables.tf index ceefa09..a310b67 100644 --- a/variables.tf +++ b/variables.tf @@ -1,45 +1,3 @@ -variable "namespace" { - type = string - description = "Namespace, which could be your organization name, e.g. 'eg' or 'cp'" - default = "" -} - -variable "stage" { - type = string - description = "Stage, e.g. 'prod', 'staging', 'dev', or 'test'" - default = "" -} - -variable "name" { - type = string - default = "app" - description = "Solution name, e.g. 'app' or 'cluster'" -} - -variable "delimiter" { - type = string - default = "-" - description = "Delimiter to be used between `namespace`, `stage`, `name` and `attributes`" -} - -variable "attributes" { - type = list(string) - default = [] - description = "Additional attributes (e.g. `1`)" -} - -variable "tags" { - type = map(string) - default = {} - description = "Additional tags (e.g. `{ BusinessUnit = \"XYZ\" }`" -} - -variable "enabled" { - type = bool - description = "Whether to create the resources. Set to `false` to prevent the module from creating any resources" - default = true -} - variable "cluster_name" { type = string description = "The name of the EKS cluster" diff --git a/versions.tf b/versions.tf index dd28587..cc861b8 100644 --- a/versions.tf +++ b/versions.tf @@ -1,9 +1,18 @@ terraform { - required_version = ">= 0.12.0, < 0.14.0" + required_version = ">= 0.12.26" required_providers { - aws = "~> 2.0" - template = "~> 2.0" - local = "~> 1.3" + aws = { + source = "hashicorp/aws" + version = ">= 2.0" + } + template = { + source = "hashicorp/template" + version = ">= 2.0" + } + local = { + source = "hashicorp/local" + version = ">= 1.3" + } } }