From 70a6ecf82d50b1ba99cc9c4fb4ed0eab3ec06dc5 Mon Sep 17 00:00:00 2001 From: Jamie Nelson Date: Wed, 16 May 2018 02:41:52 +0100 Subject: [PATCH] Add Support for List of Tag Maps (#18) * Updated to not used null_resource so that the null_resource provider isn't required * Updated to unclude the null provider version. Updated to allow for tagging of Autoscaling groups. It was really damn hard guys, really hard to getthat stupid thing expanding as a dynamic list. * updated formatting * Fixed up readme. added better example. Added commends. Added contributor section. fixed copy paste error in table. * Clarified and tested the usage of the tags * Updated the path to the module in the example * fixed formt * made module generic * made module generic * Fixed up the autoscaling group example to be very clear with many comments. * updated example in README * fixed formatting * changed example resource names from 'this' to 'default' * remove provider * Updated for consistency with other modules, fixed typoes * Updated variable description --- README.md | 98 +++++++++++++++++++++++- examples/autoscalinggroup/main.tf | 122 ++++++++++++++++++++++++++++++ main.tf | 43 +++++++---- outputs.tf | 25 +++--- variables.tf | 8 +- 5 files changed, 264 insertions(+), 32 deletions(-) create mode 100644 examples/autoscalinggroup/main.tf diff --git a/README.md b/README.md index 6c2c07f..a53c7e0 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,93 @@ resource "aws_instance" "eg_prod_bastion_xyz" { vpc_security_group_ids = ["${aws_security_group.eg_prod_bastion_xyz.id}"] } ``` +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-jamie + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: examples/autoscalinggroup/main.tf) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = "${data.aws_ami.amazon_linux.id}" + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = ["${data.aws_security_group.default.id}"] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = "${module.label.tags}" + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = ["${data.aws_subnet_ids.all.ids}"] + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "${aws_launch_template.default.id}" + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = ["${module.label.tags_as_list_of_maps}"] +} +``` ## Input @@ -134,6 +221,7 @@ resource "aws_instance" "eg_prod_bastion_xyz" { | namespace |__REQUIRED__ |Namespace, which could be your organization name, e.g. 'cp' or 'cloudposse'| | stage |__REQUIRED__ |Stage, e.g. 'prod', 'staging', 'dev', or 'test'| | tags |{} |Additional tags (e.g. `map('BusinessUnit`,`XYZ`)| +| additional_tag_map | {} | additional tags that get appended to each map in the list of maps, for the output `tags_as_list_of_maps` | **WARNING** Any tags passed as an input to this module will *override* the tags generated by this module. @@ -147,7 +235,8 @@ resource "aws_instance" "eg_prod_bastion_xyz" { | name | Normalized name | | namespace | Normalized namespace | | stage | Normalized stage | -| tags | Merge input tags with our tags. Note: `Name` has a special meaning in AWS and we need to disamgiuate it by using the computed `id` | +| tags | Merged input tags with our tags. Note: `Name` has a special meaning in AWS and we need to disamgiuate it by using the computed `id` | +| tags_as_list_of_maps | Merged input tags and our tags output as list of maps that contain the tags for use on certain resource types. | ## Help @@ -213,8 +302,8 @@ or [hire us][hire] to help build your next cloud-platform. ### Contributors -|[![Erik Osterman][erik_img]][erik_web]
[Erik Osterman][erik_web] |[![Igor Rodionov][igor_img]][igor_web]
[Igor Rodionov][igor_img] |[![Konstantin B][konstantin_img]][konstantin_web]
[Konstantin B][konstantin_web] |[![Andriy Knysh][andriy_img]][andriy_web]
[Andriy Knysh][andriy_web] |[![Sergey Vasilyev][sergey_img]][sergey_web]
[Sergey Vasilyev][sergey_web] | -|---|---|---|---|---| +|[![Erik Osterman][erik_img]][erik_web]
[Erik Osterman][erik_web] |[![Igor Rodionov][igor_img]][igor_web]
[Igor Rodionov][igor_img] |[![Konstantin B][konstantin_img]][konstantin_web]
[Konstantin B][konstantin_web] |[![Andriy Knysh][andriy_img]][andriy_web]
[Andriy Knysh][andriy_web] |[![Sergey Vasilyev][sergey_img]][sergey_web]
[Sergey Vasilyev][sergey_web] | [![Jamie Nelson][bitflight_img]][bitflight_web]
[Jamie Nelson][bitflight_web] | +|---|---|---|---|---|---| [andriy_img]: https://avatars0.githubusercontent.com/u/7356997?v=4&u=ed9ce1c9151d552d985bdf5546772e14ef7ab617&s=144 [andriy_web]: https://github.com/aknysh/ @@ -236,3 +325,6 @@ or [hire us][hire] to help build your next cloud-platform. [vladimir_img]: https://avatars1.githubusercontent.com/u/26582191?v=4&u=ed9ce1c9151d552d985bdf5546772e14ef7ab617&s=144 [vladimir_web]: https://github.com/SweetOps/ + +[bitflight_img]: https://avatars0.githubusercontent.com/u/25075504?s=144&u=ac7e53bda3706cb9d51907808574b6d342703b3e&v=4 +[bitflight_web]: https://github.com/Jamie-BitFlight diff --git a/examples/autoscalinggroup/main.tf b/examples/autoscalinggroup/main.tf new file mode 100644 index 0000000..df9d196 --- /dev/null +++ b/examples/autoscalinggroup/main.tf @@ -0,0 +1,122 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = "${data.aws_ami.amazon_linux.id}" + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = ["${data.aws_security_group.default.id}"] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = "${module.label.tags}" + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = ["${data.aws_subnet_ids.all.ids}"] + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "${aws_launch_template.default.id}" + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = ["${module.label.tags_as_list_of_maps}"] +} + +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = ["${module.label.tags_as_list_of_maps}"] +} + +output "tags" { + value = ["${module.label.tags}"] +} + +################################ +# Provider # +################################ + +provider "aws" { + region = "eu-west-1" + version = "~> 1.17" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = "${data.aws_vpc.default.id}" +} + +data "aws_security_group" "default" { + vpc_id = "${data.aws_vpc.default.id}" + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} diff --git a/main.tf b/main.tf index c609e72..542c8fb 100644 --- a/main.tf +++ b/main.tf @@ -1,15 +1,30 @@ -resource "null_resource" "default" { - count = "${var.enabled == "true" ? 1 : 0}" - - triggers = { - id = "${lower(join(var.delimiter, compact(concat(list(var.namespace, var.stage, var.name), var.attributes))))}" - name = "${lower(format("%v", var.name))}" - namespace = "${lower(format("%v", var.namespace))}" - stage = "${lower(format("%v", var.stage))}" - attributes = "${lower(format("%v", join(var.delimiter, compact(var.attributes))))}" - } - - lifecycle { - create_before_destroy = true - } +locals { + enabled = "${var.enabled == "true" ? true : false }" + id = "${local.enabled ? lower(join(var.delimiter, compact(concat(list(var.namespace, var.stage, var.name), var.attributes)))) : ""}" + name = "${local.enabled ? lower(format("%v", var.name)) : ""}" + namespace = "${local.enabled ? lower(format("%v", var.namespace)) : ""}" + stage = "${local.enabled ? lower(format("%v", var.stage)) : ""}" + attributes = "${local.enabled ? lower(format("%v", join(var.delimiter, compact(var.attributes)))) : ""}" + + tags = "${ + merge( + map( + "Name", "${local.id}", + "Namespace", "${local.namespace}", + "Stage", "${local.stage}" + ), var.tags + ) + }" + + tags_as_list_of_maps = ["${null_resource.tags_as_list_of_maps.*.triggers}"] +} + +resource "null_resource" "tags_as_list_of_maps" { + count = "${length(keys(local.tags))}" + + triggers = "${merge(map( + "key", "${element(keys(local.tags), count.index)}", + "value", "${element(values(local.tags), count.index)}" + ), + var.additional_tag_map)}" } diff --git a/outputs.tf b/outputs.tf index 44c273a..b60ad6b 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,40 +1,37 @@ output "id" { - value = "${join("", null_resource.default.*.triggers.id)}" + value = "${local.id}" description = "Disambiguated ID" } output "name" { - value = "${join("", null_resource.default.*.triggers.name)}" + value = "${local.name}" description = "Normalized name" } output "namespace" { - value = "${join("", null_resource.default.*.triggers.namespace)}" + value = "${local.namespace}" description = "Normalized namespace" } output "stage" { - value = "${join("", null_resource.default.*.triggers.stage)}" + value = "${local.stage}" description = "Normalized stage" } output "attributes" { - value = "${join("", null_resource.default.*.triggers.attributes)}" + value = "${local.attributes}" description = "Normalized attributes" } # Merge input tags with our tags. # Note: `Name` has a special meaning in AWS and we need to disamgiuate it by using the computed `id` output "tags" { - value = "${ - merge( - map( - "Name", "${join("", null_resource.default.*.triggers.id)}", - "Namespace", "${join("", null_resource.default.*.triggers.namespace)}", - "Stage", "${join("", null_resource.default.*.triggers.stage)}" - ), var.tags - ) - }" + value = "${local.tags}" description = "Normalized Tag map" } + +output "tags_as_list_of_maps" { + value = ["${local.tags_as_list_of_maps}"] + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} diff --git a/variables.tf b/variables.tf index 09187d1..eb0ed9c 100644 --- a/variables.tf +++ b/variables.tf @@ -30,5 +30,11 @@ variable "attributes" { variable "tags" { type = "map" default = {} - description = "Additional tags (e.g. `map('BusinessUnit`,`XYZ`)" + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = "map" + default = {} + description = "Additional tags for appending to each tag map." }