diff --git a/examples/single-node-asg-tester/Makefile b/examples/single-node-asg-tester/Makefile new file mode 100644 index 00000000..58f69cd5 --- /dev/null +++ b/examples/single-node-asg-tester/Makefile @@ -0,0 +1,40 @@ +.PHONY: init ssh-key apply destroy clean + +.DEFAULT_GOAL = help + +## Runs terraform get and terraform init for env +init: + @terraform get + @terraform init + +## Create ssh key +ssh-key: + @ssh-keygen -q -N "" -C "SSH key for vpc-scenario-1 example" -f ./id_rsa + +## use 'terraform apply' to apply the setup. +apply: + @terraform apply + +## use 'terraform destroy' to remove all resources from AWS +destroy: + @terraform destroy + +## rm -rf all files and state +clean: + @rm -f id_rsa + @rm -f id_rsa.pub + @rm -f terraform.*.backup + @rm -f terraform.tfstate + +## Show help screen. +help: + @echo "Please use \`make ' where is one of\n\n" + @awk '/^[a-zA-Z\-\_0-9]+:/ { \ + helpMessage = match(lastLine, /^## (.*)/); \ + if (helpMessage) { \ + helpCommand = substr($$1, 0, index($$1, ":")-1); \ + helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \ + printf "%-30s %s\n", helpCommand, helpMessage; \ + } \ + } \ + { lastLine = $$0 }' $(MAKEFILE_LIST) diff --git a/examples/single-node-asg-tester/README.md b/examples/single-node-asg-tester/README.md new file mode 100644 index 00000000..65cff193 --- /dev/null +++ b/examples/single-node-asg-tester/README.md @@ -0,0 +1,5 @@ +# single node asg tester + +This example shows the basic usage of `single-node-asg` module, especially the multiple EBS attachments. + +The module keeps one and only one instance up at all time. And the EBS volumes are reattached when a new instance is up. Hence they are always accessible. diff --git a/examples/single-node-asg-tester/main.tf b/examples/single-node-asg-tester/main.tf new file mode 100644 index 00000000..f790eb1e --- /dev/null +++ b/examples/single-node-asg-tester/main.tf @@ -0,0 +1,55 @@ +locals { + cidr = "192.168.0.0/16" + private_subnet_cidrs = ["192.168.100.0/24", "192.168.101.0/24"] + public_subnet_cidrs = ["192.168.0.0/24", "192.168.1.0/24"] + region = "ap-northeast-1" +} + +data "aws_availability_zones" "azs" { } + +module "vpc" { + source = "fpco/foundation/aws//modules/vpc-scenario-2" + cidr = local.cidr + public_subnet_cidrs = local.public_subnet_cidrs + private_subnet_cidrs = local.private_subnet_cidrs + azs = data.aws_availability_zones.azs.names + name_prefix = "test" + region = local.region +} + +module "ubuntu" { + source = "fpco/foundation/aws//modules/ami-ubuntu" +} + +resource "aws_key_pair" "main" { + public_key = file("./id_rsa.pub") +} + +resource "aws_security_group" "ssh" { + vpc_id = module.vpc.vpc_id + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} + +module "tester" { + source = "../../modules/single-node-asg" + name_prefix = "ebs" + name_suffix = "test" + key_name = aws_key_pair.main.key_name + ami = module.ubuntu.id + instance_type = "t2.micro" + subnet_id = module.vpc.public_subnet_ids[0] + security_group_ids = [aws_security_group.ssh.id] + region = local.region + data_volumes = [{ name = "a", device = "/dev/xvdm", size = 50 }, { name = "b", device = "/dev/xvdn" }] +} diff --git a/modules/alb-default-forward/main.tf b/modules/alb-default-forward/main.tf index c6aa32b1..d51957fd 100644 --- a/modules/alb-default-forward/main.tf +++ b/modules/alb-default-forward/main.tf @@ -11,7 +11,6 @@ resource "aws_lb_listener" "lb-listener" { } resource "aws_lb_target_group" "lb-tg" { - name = "${var.name_prefix}-tg" port = var.service_port protocol = "HTTP" vpc_id = var.vpc_id diff --git a/modules/alb/main.tf b/modules/alb/main.tf index 7cbe17e1..5d4d64b8 100644 --- a/modules/alb/main.tf +++ b/modules/alb/main.tf @@ -1,5 +1,4 @@ resource "aws_lb" "alb" { - name = "${var.name_prefix}-alb" internal = var.internal load_balancer_type = "application" security_groups = [aws_security_group.alb_sg.id] diff --git a/modules/asg/locals.tf b/modules/asg/locals.tf new file mode 100644 index 00000000..7149a819 --- /dev/null +++ b/modules/asg/locals.tf @@ -0,0 +1,7 @@ +locals { + name_prefix_with_suffix = "${var.name_prefix}-${var.name_suffix}" + name_prefix_without_suffix = "${var.name_prefix}" + + name_prefix = "${var.name_suffix != "" ? local.name_prefix_without_suffix : local.name_prefix_with_suffix}" + +} diff --git a/modules/asg/main.tf b/modules/asg/main.tf index 503945c2..e7325369 100644 --- a/modules/asg/main.tf +++ b/modules/asg/main.tf @@ -31,7 +31,7 @@ resource "aws_autoscaling_group" "cluster" { load_balancers = var.elb_names max_size = var.max_nodes min_size = var.min_nodes - name_prefix = "${var.name_prefix}-${var.name_suffix}" + name_prefix = local.name_prefix placement_group = var.placement_group termination_policies = var.termination_policies protect_from_scale_in = var.protect_from_scale_in @@ -71,7 +71,7 @@ resource "aws_autoscaling_group" "cluster" { [ { "key" = "Name" - "value" = "${var.name_prefix}-${var.name_suffix}" + "value" = local.name_prefix "propagate_at_launch" = true }, ], diff --git a/modules/init-snippet-attach-ebs-volume/instance_id.tpl b/modules/init-snippet-attach-ebs-volume/instance_id.tpl new file mode 100644 index 00000000..0e3e8663 --- /dev/null +++ b/modules/init-snippet-attach-ebs-volume/instance_id.tpl @@ -0,0 +1,10 @@ +if which wget; then + INSTANCE_ID="$(wget -O- http://169.254.169.254/latest/meta-data/instance-id)" +elif which curl; then + INSTANCE_ID="$(curl http://169.254.169.254/latest/meta-data/instance-id)" +fi + +if [ "x$${INSTANCE_ID}" == "x" ]; then + echo 'There is no wget or curl tool installed. Hence bootstrap cannot get instance ID.' + exit 1 +fi diff --git a/modules/init-snippet-attach-ebs-volume/main.tf b/modules/init-snippet-attach-ebs-volume/main.tf index 71d16726..c381691d 100644 --- a/modules/init-snippet-attach-ebs-volume/main.tf +++ b/modules/init-snippet-attach-ebs-volume/main.tf @@ -9,70 +9,32 @@ * */ -# variables used by this snippet of init shellcode -variable "device_path" { - default = "/dev/xvdf" - description = "path, to the device's path in /dev/" - type = string -} - -variable "init_prefix" { - default = "" - description = "initial init (shellcode) to prefix this snippet with" - type = string -} - -variable "init_suffix" { - default = "" - description = "init (shellcode) to append to the end of this snippet" - type = string -} - -variable "log_level" { - default = "info" - description = "default log level verbosity for apps that support it" - type = string -} - -variable "log_prefix" { - default = "OPS: " - description = "string to prefix log messages with" - type = string -} - -variable "region" { - description = "AWS region the volume is in" - type = string -} - -variable "wait_interval" { - default = "5" - description = "time (in seconds) to wait when looping to find the device" - type = number -} - -variable "volume_id" { - description = "ID of the EBS volume to attach" - type = string -} - # render init script for a cluster using our generic template data "template_file" "init_snippet" { + count = length(var.volume_ids) + template = file("${path.module}/snippet.tpl") vars = { - device_path = var.device_path - init_prefix = var.init_prefix - init_suffix = var.init_suffix + device_path = var.device_paths[count.index] log_prefix = var.log_prefix log_level = var.log_level region = var.region - volume_id = var.volume_id + volume_id = var.volume_ids[count.index] wait_interval = var.wait_interval } } +data "template_file" "instance_id" { + template = file("${path.module}/instance_id.tpl") +} + output "init_snippet" { - value = data.template_file.init_snippet.rendered + value = < 1 EBS volume max_nodes = 1 @@ -69,8 +77,7 @@ module "server" { public_ip = var.public_ip # the prefix and suffix names are combined in # the `asg` module to create the full name - name_prefix = var.name_prefix - name_suffix = "${var.name_suffix}-${local.az}" + name_prefix = local.name_prefix_with_az root_volume_type = var.root_volume_type root_volume_size = var.root_volume_size @@ -82,8 +89,10 @@ module "server" { user_data = < /tmp/init.log -# exec 2> /tmp/init-err.log +exec 2>&1 # set -x +apt update +${module.install-awscli.init_snippet} ${var.init_prefix} ${module.init-attach-ebs.init_snippet} ${var.init_suffix} @@ -93,7 +102,12 @@ END_INIT # Render init snippet - boxed module to attach the EBS volume to the node module "init-attach-ebs" { - source = "../init-snippet-attach-ebs-volume" - region = var.region - volume_id = module.service-data.volume_id + source = "../init-snippet-attach-ebs-volume" + region = var.region + volume_ids = module.service-data.volume_ids + device_paths = [for x in local.data_volumes_default : x.device] +} + +module "install-awscli" { + source = "../init-snippet-install-awscli" } diff --git a/modules/single-node-asg/outputs.tf b/modules/single-node-asg/outputs.tf index d2bbbbdc..7c222fd4 100644 --- a/modules/single-node-asg/outputs.tf +++ b/modules/single-node-asg/outputs.tf @@ -4,11 +4,11 @@ output "asg_name" { } output "asg_iam_role_name" { - value = module.instance_profile.iam_role_name + value = module.instance-profile.iam_role_name description = "`name` exported from the Service Data `aws_iam_role`" } output "data_volume_name_tag" { - value = "${local.data_volume_name_prefix}-${local.az}" - description = "Name tag value for attached data volume" + value = "${local.name_prefix_with_az}-default" + description = "Name tag value for attached data volume. This is for compatible with old code." } diff --git a/modules/single-node-asg/variables.tf b/modules/single-node-asg/variables.tf index 97de3191..1b534982 100644 --- a/modules/single-node-asg/variables.tf +++ b/modules/single-node-asg/variables.tf @@ -25,7 +25,8 @@ variable "placement_group" { } variable "name_suffix" { - description = "suffix to include when naming the various resources" + description = "suffix to include when naming the various resources, ignored if left as empty string" + default = "" type = string } @@ -42,45 +43,9 @@ variable "root_volume_type" { } variable "root_volume_size" { - default = "8" + default = 8 description = "Size (in GB) of EBS volume to use for the root block device" - type = string -} - -variable "data_volume_type" { - default = "gp2" - description = "Type of EBS volume to use for the EBS volume" - type = string -} - -variable "data_volume_size" { - default = "10" - description = "Size (in GB) of EBS volume to use for the EBS volume" - type = string -} - -variable "data_volume_encrypted" { - default = true - description = "Boolean, whether or not to encrypt the EBS block device" - type = string -} - -variable "data_volume_kms_key_id" { - default = "" - description = "ID of the KMS key to use when encyprting the EBS block device" - type = string -} - -variable "data_volume_snapshot_id" { - default = "" - description = "The ID of the snapshot to base the EBS block device on" - type = string -} - -variable "data_volume_iops" { - default = "" - description = "The amount of IOPS to provision for the EBS block device" - type = string + type = number } variable "init_prefix" { @@ -121,3 +86,8 @@ variable "load_balancers" { description = "The list of load balancers names to pass to the ASG module" type = list(string) } + +variable "data_volumes" { + type = list(map(any)) + description = "Definition of the data volumes. `name` and `device` are required." +}