diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..e8cfa1b --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,59 @@ +version: 2 + +jobs: + build: + working_directory: ~/repo + + docker: + - image: unifio/ci:3.0.411-ruby-2.4 + + environment: + AWS_REGION: 'us-east-2' + TF_PLUGIN_CACHE_DIR: "/root/.terraform.d/plugin-cache" + + steps: + - checkout + + - run: + name: Verify + command: bundle exec rake ci + + - run: + name: Test DMZ only configuration + command: bundle exec rake basic:no-lan:apply + + - run: + name: Test defaults + command: | + bundle exec rake basic:defaults:apply + bundle exec rake basic:defaults:destroy + + - run: + name: Test some base module options and expand to 3 AZs + command: | + bundle exec rake basic:base-options:apply + + - run: + name: Test VPN gateway attachment + command: | + bundle exec rake basic:vpg-attach:apply + bundle exec rake basic:vpg-attach:destroy + + - run: + name: Test more options and overrides + command: | + bundle exec rake complete:overrides:apply + + - run: + name: Test peering connection + command: | + bundle exec rake complete:peer-vpc:apply + bundle exec rake peering:peer-connect:apply + + - run: + name: Clean up + when: always + command: | + bundle exec rake peering:destroy || true + bundle exec rake complete:destroy + bundle exec rake basic:destroy diff --git a/.env.docker b/.env.docker index 3978d06..f3acadd 100644 --- a/.env.docker +++ b/.env.docker @@ -1,7 +1,3 @@ AWS_REGION=us-east-2 -COVALENCE_PACKER_DIR=./ -COVALENCE_TERRAFORM_DIR=./ COVALENCE_TEST_ENVS=basic,complete CHECKPOINT_DISABLE=1 -GODEBUG=netdns=cgo -USER=root diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ff8eec..8e55e59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ #### Consider Implementing: -* ipv6 support +* full ipv6 support +* vpc endpoints + +## 0.3.4 (March 7, 2018) + +#### BACKWARDS INCOMPATIBILITIES / NOTES: +* Terraform versions earlier than 0.11.0 no longer supported. +* The following input variable have been changed: + * az module + * `dmz_cidrs` -> `dmz_cidrs_override` + * `lan_cidrs` -> `lan_cidrs_override` + +#### IMPROVEMENTS / NEW FEATURES: +* Added support for the `enable_classiclink_dns_support` parameter on the vpc resource. +* Added support for the `assign_generated_ipv6_cidr_block` parameter on the vpc resource. Full ipv6 support coming in the next update. +* Introduced local variables into the `az` module to better document formulation for default options. + +#### BUG FIXES: +* Updated DHCP module outputs to suppress warnings in Terraform 0.11.0+ ## 0.3.3 (November 13, 2017) @@ -22,7 +40,7 @@ * The following input variable have been changed: * az module * `stack_item_fullname` now defaults to a value of `VPC Quick Start` - * `stack_item_label` now defaults to a value of `exmpl` + * `stack_item_label` now defaults to a value of `qckstrt` ## 0.3.1 (April 23, 2017) diff --git a/README.md b/README.md index 24b11c3..6e2c337 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This module is well suited to both basic and advanced use cases with very few re ## Requirements ## -- Terraform 0.8.0 or newer +- Terraform 0.11.0 or newer - AWS provider ## Quick Start @@ -16,7 +16,7 @@ The following code will yield a fully functioning VPC environment: ```js module "vpc_base" { - source = "github.com/terraform-aws-vpc?ref=master//base" + source = "github.com/unifio/terraform-aws-vpc?ref=master//base" } module "az" { @@ -88,11 +88,11 @@ Name | Type | Required | Description ```js module "vpc_base" { - source = "github.com/terraform-aws-vpc?ref=master//base" + source = "github.com/unifio/terraform-aws-vpc?ref=master//base" } module "dhcp" { - source = "github.com/terraform-aws-vpc?ref=master//dhcp" + source = "github.com/unifio/terraform-aws-vpc?ref=master//dhcp" domain_name = "mydomain.com" name_servers = ["172.16.0.2"] @@ -128,11 +128,11 @@ Name | Type | Required | Description ```js module "vpc_base" { - source = "github.com/terraform-aws-vpc?ref=master//base" + source = "github.com/unifio/terraform-aws-vpc?ref=master//base" } module "vpg" { - source = "github.com/terraform-aws-vpc?ref=master//vpg" + source = "github.com/unifio/terraform-aws-vpc?ref=master//vpg" stack_item_fullname = "My Stack" stack_item_label = "mystack" @@ -157,9 +157,9 @@ Name | Type | Required | Description --- | --- | --- | --- `azs_provisioned` | string | Default: `2` | The number of availability zones to be provisioned. Either this or **azs\_provisioned\_override** must be specified. Auto-provisioning will support up to 4 AZs without the need for overrides. `azs_provisioned_override` | list | | List of availability zone letters to be provisioned. Useful in regions where not all AZs are VPC ready. Either this or **azs_provisioned** must be specified. -`dmz_cidrs` | list | | The CIDR block(s) you want the public subnet(s) to cover. +`dmz_cidrs_override` | list | | The CIDR block(s) you want the public subnet(s) to cover. `enable_dmz_public_ips` | string | | Specify true to indicate that instances launched into the DMZ subnet should be assigned a public IP address. -`lan_cidrs` | list | | The CIDR block(s) you want the LAN subnet(s) to cover. +`lan_cidrs_override` | list | | The CIDR block(s) you want the LAN subnet(s) to cover. `lans_per_az` | string | Default: `1` | The number of private subnets to be provisioned per AZ. Auto-provisioning will support up to 2 private subnets per AZ without the need for overrides. `nat_ami_override` | string | | Custom NAT Amazon Machine Image (AMI). `nat_eips_enabled` | string | Default: `false` | Flag for specifying allocation of Elastic IPs to NATs for the purposes of whitelisting. This value is overriden to `true` when utilizing NAT gateways. @@ -176,7 +176,7 @@ Name | Type | Required | Description ```js module "vpc_base" { - source = "github.com/terraform-aws-vpc?ref=master//base" + source = "github.com/unifio/terraform-aws-vpc?ref=master//base" } module "az" { @@ -232,7 +232,7 @@ Name | Type | Required | Description ```js module "vpc_peer" { - source = "github.com/terraform-aws-vpc?ref=master//peer" + source = "github.com/unifio/terraform-aws-vpc?ref=master//peer" accepter_allow_remote_dns = "false" accepter_owner_id = "${var.peer_owner_id}" diff --git a/az/main.tf b/az/main.tf index 32dbe1e..6aef848 100644 --- a/az/main.tf +++ b/az/main.tf @@ -2,27 +2,62 @@ ## Set Terraform version constraint terraform { - required_version = "> 0.8.0" + required_version = "> 0.11.0" } -## Provisions DMZ resources +## Variables +data "aws_region" "current" {} -### Provisions subnets -data "aws_region" "current" { - current = true +data "aws_availability_zones" "available" {} + +locals { + # Calculates the number of AZs to be provisioned based on various possible inputs + azs_provisioned_count = "${local.azs_provisioned_override_enabled == "true" ? length(var.azs_provisioned_override) : var.azs_provisioned}" + + # Check to see if availability zones are being overridden. Some AWS regions do not support VPC in all AZs and it can vary by account. + azs_provisioned_override_enabled = "${length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? "true" : "false"}" + + # Check to see if DMZ CIDRs are being overridden. An empty list causes problems in some of the downstream formualtion. + dmz_cidrs_override_enabled = "${length(var.dmz_cidrs_override) > 0 && var.dmz_cidrs_override[0] != "non_empty_list" ? "true" : "false"}" + + # Check to see if elastic IPs are to be provisioned. NAT gateways require EIPs. + eips_enabled_check = "${var.nat_eips_enabled == "true" || var.nat_gateways_enabled == "true" ? 1 : 0}" + + # Check to see if private LAN subnets are to be provisioned. + lans_enabled_check = "${local.lans_per_az_checked > 0 ? 1 : 0}" + + # Check to see if LAN CIDRs are being overridden. An empty list causes problems in some of the downstream formualtion. + lan_cidrs_override_enabled = "${length(var.lan_cidrs_override) > 0 && var.lan_cidrs_override[0] != "non_empty_list" ? "true" : "false"}" + + # Multiplier to be used in downstream calculation based on the number of LAN subnets per AZ. + lans_multiplier = "${local.lans_per_az_checked > 0 ? local.lans_per_az_checked : 1}" + + # Handles scenario where an emptry string is passed in for lans_per_az + lans_per_az_checked = "${var.lans_per_az != "" ? var.lans_per_az : "1"}" + + # Check to see if NAT gateways are to be provisioned + nat_gateways_enabled_check = "${var.nat_gateways_enabled == "true" ? 1 : 0}" + + # Check to see if NAT gateways are NOT to be provisioned + nat_gateways_not_enabled_check = "${var.nat_gateways_enabled != "true" ? 1 : 0}" } -data "aws_availability_zones" "available" {} +## Provisions DMZ resources + +### Provisions subnets data "aws_vpc" "base" { id = "${var.vpc_id}" } resource "aws_subnet" "dmz" { - count = "${length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? length(var.azs_provisioned_override) : var.azs_provisioned}" + count = "${local.azs_provisioned_count}" - availability_zone = "${length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? "${data.aws_region.current.name}${element(var.azs_provisioned_override,count.index)}" : element(data.aws_availability_zones.available.names,count.index)}" - cidr_block = "${length(var.dmz_cidrs) > 0 && var.dmz_cidrs[0] != "non_empty_list" ? element(var.dmz_cidrs,count.index) : cidrsubnet(data.aws_vpc.base.cidr_block,lookup(var.az_cidrsubnet_newbits, length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? length(var.azs_provisioned_override) : var.azs_provisioned),count.index)}" + # Selects the first N number of AZs available for VPC use in the given region, where N is the requested number of AZs to provision. This order can be overidden by passing in an explicit list of AZ letters to be used. + availability_zone = "${local.azs_provisioned_override_enabled == "true" ? "${data.aws_region.current.name}${element(var.azs_provisioned_override,count.index)}" : element(data.aws_availability_zones.available.names,count.index)}" + + # Provisions N number of evenly allocated address spaces from the overall VPC CIDR block, where N is the requested number of AZs to provision. Address space per subnet can be overidden by passing in an explicit list of CIDRs to be used. + cidr_block = "${local.dmz_cidrs_override_enabled == "true" ? element(var.dmz_cidrs_override,count.index) : cidrsubnet(data.aws_vpc.base.cidr_block,lookup(var.az_cidrsubnet_newbits, local.azs_provisioned_count),count.index)}" map_public_ip_on_launch = "${var.enable_dmz_public_ips}" vpc_id = "${var.vpc_id}" @@ -35,7 +70,7 @@ resource "aws_subnet" "dmz" { ### Associates subnet with routing table resource "aws_route_table_association" "rta_dmz" { - count = "${length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? length(var.azs_provisioned_override) : var.azs_provisioned}" + count = "${local.azs_provisioned_count}" route_table_id = "${var.rt_dmz_id}" subnet_id = "${element(aws_subnet.dmz.*.id,count.index)}" @@ -72,20 +107,20 @@ data "aws_ami" "nat_ami" { } resource "aws_eip" "eip_nat" { - count = "${(length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? length(var.azs_provisioned_override) : var.azs_provisioned) * signum(length(var.lans_per_az) > 0 ? var.lans_per_az : "1") * signum(var.nat_eips_enabled == "true" || var.nat_gateways_enabled == "true" ? "1" : "0")}" + count = "${local.azs_provisioned_count * local.lans_enabled_check * local.eips_enabled_check}" vpc = true } resource "aws_eip_association" "eip_nat_assoc" { - count = "${(length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? length(var.azs_provisioned_override) : var.azs_provisioned) * signum(length(var.lans_per_az) > 0 ? var.lans_per_az : "1") * signum(var.nat_eips_enabled == "true" && var.nat_gateways_enabled != "true" ? "1" : "0")}" + count = "${local.azs_provisioned_count * local.lans_enabled_check * local.eips_enabled_check * local.nat_gateways_not_enabled_check}" allocation_id = "${element(aws_eip.eip_nat.*.id,count.index)}" instance_id = "${element(aws_instance.nat.*.id,count.index)}" } resource "aws_instance" "nat" { - count = "${(length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? length(var.azs_provisioned_override) : var.azs_provisioned) * signum(length(var.lans_per_az) > 0 ? var.lans_per_az : "1") * signum(var.nat_gateways_enabled != "true" ? "1" : "0")}" + count = "${local.azs_provisioned_count * local.lans_enabled_check * local.nat_gateways_not_enabled_check}" ami = "${coalesce(var.nat_ami_override,data.aws_ami.nat_ami.id)}" associate_public_ip_address = true @@ -103,7 +138,7 @@ resource "aws_instance" "nat" { } resource "aws_security_group" "sg_nat" { - count = "${(length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? length(var.azs_provisioned_override) : var.azs_provisioned) * signum(length(var.lans_per_az) > 0 ? var.lans_per_az : "1") * signum(var.nat_gateways_enabled != "true" ? "1" : "0")}" + count = "${local.azs_provisioned_count * local.lans_enabled_check * local.nat_gateways_not_enabled_check}" description = "${var.stack_item_fullname} NAT security group" name_prefix = "${var.stack_item_label}-nat-" @@ -117,7 +152,7 @@ resource "aws_security_group" "sg_nat" { } ingress { - cidr_blocks = ["${length(var.lan_cidrs) > 0 && var.lan_cidrs[0] != "non_empty_list" ? element(var.lan_cidrs,count.index) : cidrsubnet(data.aws_vpc.base.cidr_block,lookup(var.az_cidrsubnet_newbits, (length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? length(var.azs_provisioned_override) : var.azs_provisioned) * (length(var.lans_per_az) > 0 ? var.lans_per_az : "1")),count.index + lookup(var.az_cidrsubnet_offset, length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? length(var.azs_provisioned_override) : var.azs_provisioned))}"] + cidr_blocks = ["${local.lan_cidrs_override_enabled == "true" ? element(var.lan_cidrs_override,count.index) : cidrsubnet(data.aws_vpc.base.cidr_block,lookup(var.az_cidrsubnet_newbits, local.azs_provisioned_count * local.lans_multiplier),count.index + lookup(var.az_cidrsubnet_offset, local.azs_provisioned_count))}"] from_port = 0 protocol = "-1" to_port = 0 @@ -131,7 +166,7 @@ resource "aws_security_group" "sg_nat" { } resource "aws_nat_gateway" "nat" { - count = "${(length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? length(var.azs_provisioned_override) : var.azs_provisioned) * signum(length(var.lans_per_az) > 0 ? var.lans_per_az : "1") * signum(var.nat_gateways_enabled == "true" ? "1" : "0")}" + count = "${local.azs_provisioned_count * local.lans_enabled_check * local.nat_gateways_enabled_check}" allocation_id = "${element(aws_eip.eip_nat.*.id,count.index)}" subnet_id = "${element(aws_subnet.dmz.*.id,count.index)}" @@ -143,11 +178,14 @@ resource "aws_nat_gateway" "nat" { ### Provisions subnet resource "aws_subnet" "lan" { - count = "${(length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? length(var.azs_provisioned_override) : var.azs_provisioned) * (length(var.lans_per_az) > 0 ? var.lans_per_az : "1")}" + count = "${local.azs_provisioned_count * local.lans_multiplier}" + + # Selects the first N number of AZs available for VPC use in the given region, where N is the requested number of AZs to provision. This order can be overidden by passing in an explicit list of AZ letters to be used. + availability_zone = "${local.azs_provisioned_override_enabled == "true" ? "${data.aws_region.current.name}${element(var.azs_provisioned_override,count.index)}" : element(data.aws_availability_zones.available.names,count.index)}" - availability_zone = "${length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? "${data.aws_region.current.name}${element(var.azs_provisioned_override,count.index)}" : element(data.aws_availability_zones.available.names,count.index)}" - cidr_block = "${length(var.lan_cidrs) > 0 && var.lan_cidrs[0] != "non_empty_list" ? element(var.lan_cidrs,count.index) : cidrsubnet(data.aws_vpc.base.cidr_block,lookup(var.az_cidrsubnet_newbits, (length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? length(var.azs_provisioned_override) : var.azs_provisioned) * (length(var.lans_per_az) > 0 ? var.lans_per_az : "1")),count.index + (lookup(var.az_cidrsubnet_offset, length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? length(var.azs_provisioned_override) : var.azs_provisioned) * (length(var.lans_per_az) > 0 ? var.lans_per_az : "1")))}" - vpc_id = "${var.vpc_id}" + # Provisions N number of evenly allocated address spaces from the overall VPC CIDR block, where N is the requested number of AZs to provision multiplied by the number of LAN subnets to provision per AZ. Address space per subnet can be overidden by passing in an explicit list of CIDRs to be used. + cidr_block = "${local.lan_cidrs_override_enabled == "true" ? element(var.lan_cidrs_override,count.index) : cidrsubnet(data.aws_vpc.base.cidr_block,lookup(var.az_cidrsubnet_newbits, local.azs_provisioned_count * local.lans_multiplier),count.index + lookup(var.az_cidrsubnet_offset, local.azs_provisioned_count))}" + vpc_id = "${var.vpc_id}" tags { application = "${var.stack_item_fullname}" @@ -158,7 +196,7 @@ resource "aws_subnet" "lan" { ### Provisions routing table resource "aws_route_table" "rt_lan" { - count = "${(length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? length(var.azs_provisioned_override) : var.azs_provisioned) * (length(var.lans_per_az) > 0 ? var.lans_per_az : "1")}" + count = "${local.azs_provisioned_count * local.lans_multiplier}" propagating_vgws = ["${compact(var.vgw_ids)}"] vpc_id = "${var.vpc_id}" @@ -172,7 +210,7 @@ resource "aws_route_table" "rt_lan" { ### Associates subnet with routing table resource "aws_route_table_association" "rta_lan" { - count = "${(length(var.azs_provisioned_override) > 0 && var.azs_provisioned_override[0] != "non_empty_list" ? length(var.azs_provisioned_override) : var.azs_provisioned) * (length(var.lans_per_az) > 0 ? var.lans_per_az : "1")}" + count = "${local.azs_provisioned_count * local.lans_multiplier}" route_table_id = "${element(aws_route_table.rt_lan.*.id,count.index)}" subnet_id = "${element(aws_subnet.lan.*.id,count.index)}" diff --git a/az/variables.tf b/az/variables.tf index 8a191f2..2a752da 100644 --- a/az/variables.tf +++ b/az/variables.tf @@ -52,7 +52,7 @@ variable "azs_provisioned_override" { default = ["non_empty_list"] } -variable "dmz_cidrs" { +variable "dmz_cidrs_override" { type = "list" description = "The CIDR block(s) you want the DMZ subnet(s) to cover." default = ["non_empty_list"] @@ -64,7 +64,7 @@ variable "enable_dmz_public_ips" { default = "" } -variable "lan_cidrs" { +variable "lan_cidrs_override" { type = "list" description = "The CIDR block(s) you want the LAN subnet(s) to cover." default = ["non_empty_list"] diff --git a/base/main.tf b/base/main.tf index f544873..4ab3417 100644 --- a/base/main.tf +++ b/base/main.tf @@ -2,16 +2,18 @@ ## Set Terraform version constraint terraform { - required_version = "> 0.8.0" + required_version = "> 0.11.0" } ## Provisions Virtual Private Cloud (VPC) resource "aws_vpc" "vpc" { - cidr_block = "${var.vpc_cidr}" - instance_tenancy = "${var.instance_tenancy}" - enable_dns_support = "${var.enable_dns}" - enable_dns_hostnames = "${var.enable_hostnames}" - enable_classiclink = "${var.enable_classiclink}" + cidr_block = "${var.vpc_cidr}" + instance_tenancy = "${var.instance_tenancy}" + enable_dns_support = "${var.enable_dns}" + enable_dns_hostnames = "${var.enable_hostnames}" + enable_classiclink = "${var.enable_classiclink}" + enable_classiclink_dns_support = "${var.enable_classiclink_dns_support}" + assign_generated_ipv6_cidr_block = "${var.assign_generated_ipv6_cidr_block}" tags { application = "${var.stack_item_fullname}" @@ -20,7 +22,7 @@ resource "aws_vpc" "vpc" { } } -## Provisions Internet gateway +## Provisions Internet gateways resource "aws_internet_gateway" "igw" { vpc_id = "${aws_vpc.vpc.id}" @@ -48,43 +50,40 @@ resource "aws_cloudwatch_log_group" "flow_log_group" { name = "${var.stack_item_label}-vpc-flow-logs" } -resource "aws_iam_role" "flow_log_role" { - name = "${var.stack_item_label}-vpc-flow-logs" +data "aws_iam_policy_document" "flow_log_role" { + statement { + actions = ["sts:AssumeRole"] - assume_role_policy = </dev/null) + if [[ ${GET_DOCKER_HOST_IP} ]];then + CONSUL_TEST_IP=${GET_DOCKER_HOST_IP} + add_arg_simple "--add-host" "${TEST_HOST_LOCAL}:${CONSUL_TEST_IP}" + fi + fi +} +# add a volume host:docker mount. +add_host_volume(){ + local host_vol="${1%:*}" + local dkr_vol="${1##*:}" + add_arg "-v" "${host_vol}:${dkr_vol}" +} + +# add envfiles for docker if they exist in working directory +add_docker_envfiles(){ + local envfiles="${1}" + IFS=':' read -r -a arrenvs <<< "$envfiles" + for i in "${arrenvs[@]}" + do + if [[ -r "${i}" ]];then + add_arg "--env-file" "$(pwd)/${i}" + fi + done +} +usage () { + echo "" + echo "Usage : $0 [OPTIONS] [COMMANDS|task]" + echo "Options:" + echo " -l List available rake tasks " + echo " -e FILE:FILE Envfiles for docker : separated " + echo " -s FILE Local env file to source " + echo " -d DNS Docker DNS " + echo " -u USER Run Docker as user " + echo " -O Use Wrapper without Covalence " + echo " -T URL URL for Consul overload " + echo " -R Leave intermediary containers " + echo " -v VOL:MNT Add a volume mount to container " + echo " -c AWS_DIR AWS credentials path " + echo " -w DIR Host workspace to mount " + echo " -E ENTRYPOINT Override entrypoint command " + echo " -i DKR_IMG_NAME Docker container Image name " + echo " -h View help. " + echo " -r RAKEFILE Specify separate rakefile " + echo " -D Turn on debug " + echo " -H Environment dump " +} +# require at lest a task or -l to run +if [ $# -lt 1 ]; then + usage + exit 1 +fi + +# Load local env file if provided/available +# That way explicit options will overwrite +# any env vars sourced in .env.covalence +if [[ -r "${LOCAL_ENVFILE}" ]]; then + . ./"${LOCAL_ENVFILE}" +fi + +# Parse arguments and populate ENV vars respectively +# See Environment Variable section or .env.covalence for +# option details. +while getopts ":le:s:d:OIT:Rv:c:w:E:i:hr:DH" opt; do + case $opt in + l) + LIST_RAKE_TASKS=1 + ;; + e) + LOAD_ENVFILE="$OPTARG" + ;; + s) + LOCAL_ENVFILE="$OPTARG" + ;; + d) + DOCKER_DNS="$OPTARG" + ;; + u) + CONTAINER_USER_ID="$OPTARG" + ;; + O) + DOCKER_WRAPPER=1 + ;; + T) + TEST_HOST_LOCAL="$OPTARG" + ;; + R) + DOCKER_RUN_TYPE="--it" + ;; + v) + ADD_VOLUMES="$OPTARG" + ;; + c) + AWS_CREDENTIAL_PATH="$OPTARG" + ;; + w) + DOCKER_WORKSPACE="$OPTARG" + ;; + E) + ENTRYPOINT="$OPTARG" + ;; + i) + DOCKER_IMAGE_NAME="$OPTARG" + ;; + h) + usage + exit 0 + ;; + D) + S_DEBUG=1 + ;; + H) + DUMP_ENV=1 + ;; + I) + INTSHELL=1 + ;; + r) + COVALENCE_RAKEFILE="$OPTARG" + ;; + \?) + set +x + echo "Invalid option: -$OPTARG" >&2 + usage + exit 1 + ;; + :) + set +x + echo "Option -$OPTARG requires an argument." >&2 + usage + exit 1 + ;; + esac +done + +# Get rid of processed options from Array +shift "$((OPTIND-1))" +USER_ARGS=("${@}") + +if [[ "${COVALENCE_CONFIG}" ]]; then + add_arg_simple "-e" "COVALENCE_CONFIG=${COVALENCE_CONFIG}" +fi + +if [[ "${COVALENCE_TEST_ENVS}" ]]; then + add_arg_simple "-e" "COVALENCE_TEST_ENVS=${COVALENCE_TEST_ENVS}" +fi + +# Add the --rm or --it argument to the docker command array. +if [[ "${DOCKER_RUN_TYPE}" ]]; then + DOCKER_BASE_COMMANDS[3]="${DOCKER_RUN_TYPE}" +fi + +if [[ "${DOCKER_DNS}" ]]; then + add_arg "--dns" "${DOCKER_DNS}" +fi + +if [[ "${CONTAINER_USER_ID}" ]]; then + DOCKER_HOMEDIR="" + add_arg_simple "-e" "AWS_CONFIG_FILE=${DOCKER_HOMEDIR}/.aws/config" + add_arg_simple "-e" "AWS_SHARED_CREDENTIALS_FILE=${DOCKER_HOMEDIR}/.aws/credentials" + add_arg_simple "-e" "USER=user" + add_arg_simple "-e" "LOCAL_USER_ID=${CONTAINER_USER_ID}" +else + add_arg_simple "-e" "USER=root" +fi + +get_docker_host "$TEST_HOST_LOCAL" + +if [[ "$ADD_VOLUMES" ]];then + add_host_volume "${ADD_VOLUMES}" +fi + +if [[ -d "$AWS_CREDENTIAL_PATH" ]];then + add_arg_simple "-v" "${AWS_CREDENTIAL_PATH}:${DOCKER_HOMEDIR}/.aws" +fi + +if [[ -d "${SRC_ROOT}" ]];then + add_arg_simple "-v" "${SRC_ROOT}:${DOCKER_WORKSPACE}" + add_arg "-w" "${DOCKER_WORKSPACE}" +fi + +if [[ "${LOAD_ENVFILE}" ]]; then + add_docker_envfiles "${LOAD_ENVFILE}" +fi + +if [[ "${ENTRYPOINT}" ]]; then + ARGS+=("--entrypoint=${ENTRYPOINT}") +fi +if [[ $INTSHELL && ! $ENTRYPOINT ]]; then + ARGS+=("--entrypoint=/bin/sh") +fi +# All options should be completed +# Only image and task remain. + +if [[ $DOCKER_IMAGE_NAME ]];then + if [[ $INTSHELL && $DOCKER_WRAPPER ]]; then + ARGS+=("-it") + fi + ARGS+=("$DOCKER_IMAGE_NAME") +fi + +#Check whether docker wrapper or covalence +if [[ ! $DOCKER_WRAPPER ]]; then + ARGS+=("bundle exec rake") +fi + +if [[ -r "${COVALENCE_RAKEFILE}" && ! $DOCKER_WRAPPER ]];then + add_arg "-f" "${COVALENCE_RAKEFILE}" +fi + +if [[ $LIST_RAKE_TASKS && ! $DOCKER_WRAPPER ]];then + ARGS+=("-T") +fi +# Merged Commands for execution +DOCKER_BASE_COMMANDS=(${DOCKER_BASE_COMMANDS[@]} ${ARGS[@]} ${USER_ARGS[@]}) + +if [[ $DUMP_ENV ]]; then + echo "DOCKER_BASE_COMMANDS that would have been executed without -H" + echo "${DOCKER_BASE_COMMANDS[@]}" + # echo "ARGS array" + # echo "${ARGS[@]}" + # echo "USER_ARGS array" + # echo "${USER_ARGS[@]}" + # echo "" +else + # Execute the commands + # If we are listing, remove the rake as user won't pass that in. + if [[ $LIST_RAKE_TASKS && ! $DOCKER_WRAPPER ]];then + "${DOCKER_BASE_COMMANDS[@]}" | sed -e "s/^rake //" + else + "${DOCKER_BASE_COMMANDS[@]}" + fi +fi diff --git a/bin/covalence b/bin/covalence index 8eca25b..71687a7 100755 --- a/bin/covalence +++ b/bin/covalence @@ -1,321 +1,13 @@ #!/usr/bin/env bash -# Run from the source tree root -cd `dirname $0` -cd .. -### Environment Variables -# Variables are used for determining CI settings -# Variable precedence is as follows with the last taking -# the highest precedence -# -# 1. Default values -# 2. Exported environment variables -# 3. .env.covalence loaded values -# 4. bin/covalence argument switches -# -# source local .env.covalence file if present -LOCAL_ENVFILE=${LOCAL_ENVFILE:-".env.covalence"} - -# If set to true will no use old docker-wrapper behavior -# omitting the `rake` command -DOCKER_WRAPPER=${DOCKER_WRAPPER:-} -# The docker environment variable file passed to the container -# Can contain multiple envfiles separated by : env1:env2:env3 -LOAD_ENVFILE=${LOAD_ENVFILE:-".env.docker:.env.secrets"} -# AWS Credentials path to mount (defaults to data/secure/.aws) -AWS_CREDENTIAL_PATH=${AWS_CREDENTIAL_PATH:-"${HOME}/.aws"} -# The Container home directory -DOCKER_HOMEDIR=${DOCKER_HOMEDIR:-"/root"} -# The docker DNS defaults to Google -DOCKER_DNS=${DOCKER_DNS:-8.8.8.8} -# If you want docker to run as specific user -CONTAINER_USER=${CONTAINER_USER:-} -# Alternative Covalence Rakefile can be specified -# will add `-f Rakefile`` -COVALENCE_RAKEFILE=${COVALENCE_RAKEFILE:-} -# Alternative Covalence configuration can be specified -COVALENCE_CONFIG=${COVALENCE_CONFIG:-"covalence.yaml"} -# Environments to be included in CI -COVALENCE_TEST_ENVS=${COVALENCE_TEST_ENVS:-} -# The Container image to use for the ci defaults to unifio/ci latest -DOCKER_IMAGE_NAME=${DOCKER_IMAGE_NAME:-"unifio/ci"} -# Enable debugging of script -S_DEBUG=${S_DEBUG:-} -# Dump verbose information about commands without executing them. -DUMP_ENV=${DUMP_ENV:-} -# Causes covalence rake -T -LIST_RAKE_TASKS=${LIST_RAKE_TASKS:-} -# Adds volume to docker container HOST_MNT:CONTAINER_MNT -ADD_VOLUMES=${ADD_VOLUMES:-} -# Can be used to change docker run behavior ie -it vs --rm -DOCKER_RUN_TYPE=${DOCKER_RUN_TYPE:-"--rm"} -# TEST_HOST_LOCAL is used for specifying a domain to overload -# and point to the Docker host IP in the container /etc/host file -# --add-host CONSUL_TEST_IP will be set automatically -TEST_HOST_LOCAL=${TEST_HOST_LOCAL:-} -CONSUL_TEST_IP=${CONSUL_TEST_IP:-} -# Allows specifying --entrypoint= command -ENTRYPOINT=${ENTRYPOINT:-} -# Sets the Docker workspace to mount and set as working directory -w -DOCKER_WORKSPACE=${DOCKER_WORKSPACE:-"/workspace"} -# The project root directory to mount in docker workspace -SRC_ROOT=${SRC_ROOT:-"$(pwd)"} -# Atlas and AWS tokens if needed but defaults to .aws -# For possible future use currently should be set in .env.docker -#ATLAS_TOKEN=${AWS_SECRET_ACCESS_KEY:-} -#AWS_ACCESS_KEY_ID=${AWS_SECRET_ACCESS_KEY:-} -#AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-} - -# Create initial Docker Base Command -DOCKER_BASE_COMMANDS[0]="docker run" -ARGS=() -# Check for debug statements -if [[ $S_DEBUG ]]; then - set -x -fi - -# Checks if ARGS already contains the given value -has_arg() { - local element - for element in "${@:2}"; do - [ "${element}" == "${1}" ] && return 0 - done - return 1 -} -# Adds the given argument if not specified -add_arg() { - local arg="${1}" - [ $# -ge 1 ] && local val="${2}" - if ! has_arg "${arg}" "${DOCKER_BASE_COMMANDS[@]}"; then - ARGS+=("${arg}") - [ $# -ge 1 ] && ARGS+=("${val}") - fi -} -# Adds the given argument duplicates ok. -add_arg_simple() { - local arg="${1}" - [ $# -ge 1 ] && local val="${2}" - ARGS+=("${arg}") - [ $# -ge 1 ] && ARGS+=("${val}") -} -# get the docker host ip address. and add it to container /etc/host -# for TEST_HOST_LOCAL URL provided. -get_docker_host(){ - if [[ $TEST_HOST_LOCAL ]]; then - GET_DOCKER_HOST_IP=$(docker inspect --format '{{ .NetworkSettings.Gateway }}' $(docker ps -q | grep -m 1 "") 2>/dev/null) - if [[ ${GET_DOCKER_HOST_IP} ]];then - CONSUL_TEST_IP=${GET_DOCKER_HOST_IP} - add_arg_simple "--add-host" "${TEST_HOST_LOCAL}:${CONSUL_TEST_IP}" - fi - fi -} -# add a volume host:docker mount. -add_host_volume(){ - local host_vol="${1%:*}" - local dkr_vol="${1##*:}" - add_arg "-v" "${host_vol}:${dkr_vol}" -} - -# add envfiles for docker if they exist in working directory -add_docker_envfiles(){ - local envfiles="${1}" - IFS=':' read -r -a arrenvs <<< "$envfiles" - for i in "${arrenvs[@]}" - do - if [[ -r "${i}" ]];then - add_arg "--env-file" "$(pwd)/${i}" - fi - done -} -usage () { - echo "" - echo "Usage : $0 [OPTIONS] [COMMANDS|task]" - echo "Options:" - echo " -l List available rake tasks " - echo " -e FILE:FILE Envfiles for docker : separated " - echo " -s FILE Local env file to source " - echo " -d DNS Docker DNS " - echo " -u USER Run Docker as user " - echo " -O Use Wrapper without Covalence " - echo " -T URL URL for Consul overload " - echo " -R Leave intermediary containers " - echo " -v VOL:MNT Add a volume mount to container " - echo " -c AWS_DIR AWS credentials path " - echo " -w DIR Host workspace to mount " - echo " -E ENTRYPOINT Override entrypoint command " - echo " -i DKR_IMG_NAME Docker container Image name " - echo " -h View help. " - echo " -r RAKEFILE Specify separate rakefile " - echo " -D Turn on debug " - echo " -H Environment dump " -} -# require at lest a task or -l to run -if [ $# -lt 1 ]; then - usage - exit 1 -fi - -# Load local env file if provided/available -# That way explicit options will overwrite -# any env vars sourced in .env.covalence -if [[ -r "${LOCAL_ENVFILE}" ]]; then - . ./"${LOCAL_ENVFILE}" -fi - -# Parse arguments and populate ENV vars respectively -# See Environment Variable section or .env.covalence for -# option details. -while getopts ":le:s:d:OT:Rv:c:w:E:i:hr:DH" opt; do - case $opt in - l) - LIST_RAKE_TASKS=1 - ;; - e) - LOAD_ENVFILE="$OPTARG" - ;; - s) - LOCAL_ENVFILE="$OPTARG" - ;; - d) - DOCKER_DNS="$OPTARG" - ;; - u) - CONTAINER_USER="$OPTARG" - ;; - O) - DOCKER_WRAPPER=1 - ;; - T) - TEST_HOST_LOCAL="$OPTARG" - ;; - R) - DOCKER_RUN_TYPE="--it" - ;; - v) - ADD_VOLUMES="$OPTARG" - ;; - c) - AWS_CREDENTIAL_PATH="$OPTARG" - ;; - w) - DOCKER_WORKSPACE="$OPTARG" - ;; - E) - ENTRYPOINT="$OPTARG" - ;; - i) - DOCKER_IMAGE_NAME="$OPTARG" - ;; - h) - usage - exit 0 - ;; - D) - S_DEBUG=1 - ;; - H) - DUMP_ENV=1 - ;; - r) - COVALENCE_RAKEFILE="$OPTARG" - ;; - \?) - set +x - echo "Invalid option: -$OPTARG" >&2 - usage - exit 1 - ;; - :) - set +x - echo "Option -$OPTARG requires an argument." >&2 - usage - exit 1 - ;; - esac -done - -# Get rid of processed options from Array -shift "$((OPTIND-1))" -USER_ARGS=("${@}") - -if [[ "${COVALENCE_CONFIG}" ]]; then - add_arg_simple "-e" "COVALENCE_CONFIG=${COVALENCE_CONFIG}" -fi - -if [[ "${COVALENCE_TEST_ENVS}" ]]; then - add_arg_simple "-e" "COVALENCE_TEST_ENVS=${COVALENCE_TEST_ENVS}" -fi - -# Add the --rm or --it argument to the docker command array. -if [[ "${DOCKER_RUN_TYPE}" ]]; then - DOCKER_BASE_COMMANDS[3]="${DOCKER_RUN_TYPE}" -fi - -if [[ "${DOCKER_DNS}" ]]; then - add_arg "--dns" "${DOCKER_DNS}" -fi -if [[ "${CONTAINER_USER}" ]]; then - add_arg "--user" "${CONTAINER_USER}" -fi - -get_docker_host "$TEST_HOST_LOCAL" - -if [[ "$ADD_VOLUMES" ]];then - add_host_volume "${ADD_VOLUMES}" -fi - -if [[ -d "$AWS_CREDENTIAL_PATH" ]];then - add_arg_simple "-v" "${AWS_CREDENTIAL_PATH}:${DOCKER_HOMEDIR}/.aws" -fi - -if [[ -d "${SRC_ROOT}" ]];then - add_arg_simple "-v" "${SRC_ROOT}:${DOCKER_WORKSPACE}" - add_arg "-w" "${DOCKER_WORKSPACE}" -fi - -if [[ "${LOAD_ENVFILE}" ]]; then - add_docker_envfiles "${LOAD_ENVFILE}" -fi +COVALENCE_SCRIPT="https://s3.amazonaws.com/unifio-covalence/covalence?versionId=k_MRX2uIWItAsCR1YFrJWZOaDIB9FFAR" -if [[ "${ENTRYPOINT}" ]]; then - ARGS+=("--entrypoint=${ENTRYPOINT}") -fi -# All options should be completed -# Only image and task remain. - -if [[ $DOCKER_IMAGE_NAME ]];then - ARGS+=("$DOCKER_IMAGE_NAME") -fi - -#Check whether docker wrapper or covalence -if [[ ! $DOCKER_WRAPPER ]]; then - ARGS+=("rake") -fi - -if [[ -r "${COVALENCE_RAKEFILE}" && ! $DOCKER_WRAPPER ]];then - add_arg "-f" "${COVALENCE_RAKEFILE}" -fi +cd `dirname $0` -if [[ $LIST_RAKE_TASKS && ! $DOCKER_WRAPPER ]];then - ARGS+=("-T") +if [[ ! -e ./.covalence/launcher ]]; then + mkdir -p .covalence + curl -o .covalence/launcher -s $COVALENCE_SCRIPT + chmod 0755 .covalence/launcher fi -# Merged Commands for execution -DOCKER_BASE_COMMANDS=(${DOCKER_BASE_COMMANDS[@]} ${ARGS[@]} ${USER_ARGS[@]}) -if [[ $DUMP_ENV ]]; then - echo "DOCKER_BASE_COMMANDS that would have been executed without -H" - echo "${DOCKER_BASE_COMMANDS[@]}" - # echo "ARGS array" - # echo "${ARGS[@]}" - # echo "USER_ARGS array" - # echo "${USER_ARGS[@]}" - # echo "" -else - # Execute the commands - # If we are listing, remove the rake as user won't pass that in. - if [[ $LIST_RAKE_TASKS && ! $DOCKER_WRAPPER ]];then - "${DOCKER_BASE_COMMANDS[@]}" | sed -e "s/^rake //" - else - "${DOCKER_BASE_COMMANDS[@]}" - fi -fi +bash .covalence/launcher "$@" diff --git a/circle.yml b/circle.yml deleted file mode 100644 index b973931..0000000 --- a/circle.yml +++ /dev/null @@ -1,26 +0,0 @@ -machine: - services: - - docker - -test: - override: - # Verify - - bin/covalence ci - # UAT - ## Test DMZ only configuration - - bin/covalence basic:no-lan:apply - ## Test defaults - - bin/covalence basic:defaults:apply - - bin/covalence basic:defaults:destroy - ## Test some base module options and expand to 3 AZs - - bin/covalence basic:base-options:apply - ## Test VPN gateway attachment - - bin/covalence basic:vpg-attach:apply - - bin/covalence basic:vpg-attach:destroy - ## Test more options and overrides - - bin/covalence complete:overrides:apply - ## Test peering connection - - bin/covalence complete:peer-vpc:apply - - bin/covalence peering:peer-connect:apply - - bin/covalence peering:destroy - - bin/covalence complete:destroy diff --git a/data/stacks/overrides.yaml b/data/stacks/overrides.yaml index 2cdd1c9..30b15cf 100644 --- a/data/stacks/overrides.yaml +++ b/data/stacks/overrides.yaml @@ -15,7 +15,8 @@ overrides::state: examples::complete::vars: domain_name: 'complete.example' enable_classiclink: 'true' - instance_tenancy: 'dedicated' + # TODO: Cannot be paired with Classiclink. Update test for this. + #instance_tenancy: 'dedicated' lans_per_az: '2' name_servers: - '172.16.0.2' diff --git a/dhcp/main.tf b/dhcp/main.tf index d68af4d..384ea94 100644 --- a/dhcp/main.tf +++ b/dhcp/main.tf @@ -2,7 +2,7 @@ ## Set Terraform version constraint terraform { - required_version = "> 0.8.0" + required_version = "> 0.11.0" } ## Provisions DHCP options diff --git a/dhcp/outputs.tf b/dhcp/outputs.tf index 751e001..76da62d 100644 --- a/dhcp/outputs.tf +++ b/dhcp/outputs.tf @@ -1,5 +1,5 @@ # Output variables output "dhcp_id" { - value = "${aws_vpc_dhcp_options.dhcp.id}" + value = "${join(",",compact(aws_vpc_dhcp_options.dhcp.*.id))}" } diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 3050afb..b710805 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -66,13 +66,13 @@ module "vpc_az" { azs_provisioned_override = "${var.azs_provisioned_override}" - dmz_cidrs = ["${cidrsubnet(var.vpc_cidr,3,0)}", + dmz_cidrs_override = ["${cidrsubnet(var.vpc_cidr,3,0)}", "${cidrsubnet(var.vpc_cidr,3,1)}", "${cidrsubnet(var.vpc_cidr,3,2)}", "${cidrsubnet(var.vpc_cidr,3,3)}", ] - lan_cidrs = ["${cidrsubnet(var.vpc_cidr,4,8)}", + lan_cidrs_override = ["${cidrsubnet(var.vpc_cidr,4,8)}", "${cidrsubnet(var.vpc_cidr,4,9)}", "${cidrsubnet(var.vpc_cidr,4,10)}", "${cidrsubnet(var.vpc_cidr,4,11)}", diff --git a/peer/main.tf b/peer/main.tf index 8f99e7d..82a978c 100644 --- a/peer/main.tf +++ b/peer/main.tf @@ -2,15 +2,16 @@ ## Set Terraform version constraint terraform { - required_version = "> 0.8.0" + required_version = "> 0.11.0" } ## Provisions VPC peering resource "aws_vpc_peering_connection" "peer" { count = "${length(var.vpc_peering_connection_id) > 0 ? "0" : "1"}" - auto_accept = "${length(var.accepter_owner_id) > 0 ? "false" : "true"}" + auto_accept = "${var.accepter_region != "" ? "false" : var.auto_accept}" peer_owner_id = "${var.accepter_owner_id}" + peer_region = "${var.accepter_region}" peer_vpc_id = "${var.accepter_vpc_id}" vpc_id = "${var.requester_vpc_id}" diff --git a/peer/variables.tf b/peer/variables.tf index 2ab30e3..8c4cd40 100644 --- a/peer/variables.tf +++ b/peer/variables.tf @@ -42,12 +42,24 @@ variable "accepter_owner_id" { default = "" } +variable "accepter_region" { + type = "string" + description = "The region of the accepter VPC of the VPC Peering Connection." + default = "" +} + variable "accepter_vpc_id" { type = "string" description = "The ID of the VPC with which you are creating the VPC Peering Connection." default = "" } +variable "auto_accept" { + type = "string" + description = "Accept the peering (both VPCs need to be in the same AWS account and region)." + default = "true" +} + variable "requester_allow_classic_link_to_remote" { type = "string" description = "Allow a local linked EC2-Classic instance to communicate with instances in a peer VPC. This enables an outbound communication from the local ClassicLink connection to the remote VPC." diff --git a/vpg/main.tf b/vpg/main.tf index 3a59c29..ce65823 100644 --- a/vpg/main.tf +++ b/vpg/main.tf @@ -2,7 +2,7 @@ ## Set Terraform version constraint terraform { - required_version = "> 0.8.0" + required_version = "> 0.11.0" } ## Gateway configuration