Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@lusis
Created February 4, 2016 01:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lusis/ea554210ad3f0637700a to your computer and use it in GitHub Desktop.
Save lusis/ea554210ad3f0637700a to your computer and use it in GitHub Desktop.
RDS terraform stuffs
module "rds" {
	source = "<module-source containing with ref>"
	multi_az = "${var.rds_multi_az}"
	spath_db_instance_class = "${var.rds_instance_type}"
	spath_orgname = "${var.orgname}"
	iam_rds_user = "${var.iam_rds_user}"
	iam_rds_password = "${var.iam_rds_password}"
	spath_rds_sg_id = "${module.vpc.default_sg_id}"
	spath_rds_private_subnet_a_id = "${module.vpc.private_subnet_a_id}"
	spath_rds_private_subnet_b_id = "${module.vpc.private_subnet_b_id}"
	spath_rds_private_subnet_c_id = "${module.vpc.private_subnet_c_id}"
	aws_region = "${var.aws_region}"
}

A few notes spath_orgname is an internal nomenclature that we prefix to ALL resources for identification purposes. It can be staging or testcase1 whatever

We have modules for everything and usually combine them to form an environment of some kind. For instance this usage references the vpc module that we're also using in the same wrapper project:

module "vpc" {
	source = "<module source path with ref>"
	spath_orgname = "${var.orgname}"
	spath_nat_instance_role_name = "${module.s3_instance_role.instance_profile.name}"
	spath_nat_ami = "${module.ami.ami_id}"
	spath_nat_a_private_ip = "${var.nat_a_private_ip}"
	spath_nat_b_private_ip = "${var.nat_b_private_ip}"
	spath_nat_c_private_ip = "${var.nat_c_private_ip}"
	spath_public_subnet_a_cidr = "${var.public_subnet_a_cidr}"
	spath_public_subnet_b_cidr = "${var.public_subnet_b_cidr}"
	spath_public_subnet_c_cidr = "${var.public_subnet_c_cidr}"
	spath_private_subnet_a_cidr = "${var.private_subnet_a_cidr}"
	spath_private_subnet_b_cidr = "${var.private_subnet_b_cidr}"
	spath_private_subnet_c_cidr = "${var.private_subnet_c_cidr}"
	spath_vpc_cidr = "${var.vpc_cidr}"
	spath_keyname = "${var.orgname}-key"
	aws_region = "${var.aws_region}"
}

All of our wrapper projects typically have a Makefile that populates terraform.tfvars

i.e.

orgname = "@@ORGNAME@@"
bucketname = "@@ORGNAME@@-testbucket"
consul_encryption_key = "@@CONSULKEY@@"
ssl_pemfile = "@@CERTFILE@@"
ssl_keyfile = "@@KEYFILE@@"
aws_region = "@@AWSREGION@@"
instance_type = "@@AWSINSTANCE@@"
rds_instance_type = "@@RDSINSTANCE@@"
rds_multi_az = "@@RDS_MULTI_AZ@@"
iam_rds_user = "@@ORGNAME@@"
iam_rds_password = "@@IAMRDSPASS@@"
vpc_cidr = "10.8.0.0/16"
nat_a_private_ip = "10.8.1.10"
nat_b_private_ip = "10.8.2.10"
nat_c_private_ip = "10.8.3.10"
public_subnet_a_cidr = "10.8.1.0/24"
public_subnet_b_cidr = "10.8.2.0/24"
public_subnet_c_cidr = "10.8.3.0/24"
private_subnet_a_cidr = "10.8.11.0/24"
private_subnet_b_cidr = "10.8.12.0/24"
private_subnet_c_cidr = "10.8.13.0/24"

In our makefile, we might have something like this:

export RDS_MULTI_AZ ?= "true"
# bunches of other conditional exports

build: check-env
	@echo "Building for $(ORGNAME)"
	# lots of other stuff here - ssh-keygen, self-signed cert gen for local dev
	@sed \
		-e "s,@@YAMLPATH@@,$(YAMLPATH),g" \
		-e "s,@@ORGNAME@@,$(ORGNAME),g" \
		-e "s,@@AWSREGION@@,$(AWSREGION),g" \
		-e "s,@@AWSINSTANCE@@,$(AWSINSTANCE),g" \
		-e "s,@@RDSINSTANCE@@,$(RDSINSTANCE),g" \
		-e "s,@@RDS_MULTI_AZ@@,$(RDS_MULTI_AZ),g" \
		-e "s,@@IAMRDSPASS@@,$(IAMDBPASS),g" \
		-e "s,@@CERTFILE@@,$(CERTPATH)/$(ORGNAME)-ssl.pem,g" \
		-e "s,@@KEYFILE@@,$(CERTPATH)/$(ORGNAME)-ssl.key,g" \
		terraform.tfvars.tmpl > terraform.tfvars
  @terraform plan
ifeq ($(TFAPPLY), "true")
	@cd $(ORGNAME); terraform apply -no-color
	@cd $(ORGNAME); terraform output | tr -d ' ' | sed 's/^/export /' > $(ORGNAME).env.sh
endif

What's nice about the makefile approach is that users can keep a local override.mk to manage certain flags. For instance, here's mine right now:

override IS_RUNDECK := false
override ORGNAME := jvorgc
override YAMLPATH := ./
override RDS_MULTI_AZ := false
override TFAPPLY := false
override DOGIT := false
override ENVSIZE := 6

Also fun fact: YAMLPATH is where we have a terraform template resource write out a rundeck node YAML file. We use this file for both local serverspec tests and to make the nodes visible in rundeck.

resource "template_file" "rundeck-yaml" {
	filename = "templates/rundeck-nodes.yml"
	vars {
		nat_a_public_ip = "${module.vpc.nat_a.public_ip}"
		nat_b_public_ip = "${module.vpc.nat_b.public_ip}"
		nat_c_public_ip = "${module.vpc.nat_c.public_ip}"
		nat_a_private_dns = "${module.vpc.nat_a.private_fqdn}"
		nat_b_private_dns = "${module.vpc.nat_b.private_fqdn}"
		nat_c_private_dns = "${module.vpc.nat_c.private_fqdn}"
		appnode_a_private_ip = "${module.dockernode_subnet_a.dockernode_ip}"
		appnode_a_fqdn = "${module.dockernode_subnet_a.dockernode_fqdn}"
		appnode_a_services = "docker,iam,hazelcast"
		appnode_b_private_ip = "${module.dockernode_subnet_b.dockernode_ip}"
		appnode_b_fqdn = "${module.dockernode_subnet_b.dockernode_fqdn}"
		appnode_b_services = "docker,iam,hazelcast"
		appnode_c_private_ip = "${module.dockernode_subnet_c.dockernode_ip}"
		appnode_c_fqdn = "${module.dockernode_subnet_c.dockernode_fqdn}"
		appnode_c_services = "docker,iam,hazelcast"
		backend_a_private_ip = "${module.backend_subnet_a.dockernode_ip}"
		backend_a_fqdn = "${module.backend_subnet_a.dockernode_fqdn}"
		backend_a_services = "docker,cassandra,amq_private"
		backend_b_private_ip = "${module.backend_subnet_b.dockernode_ip}"
		backend_b_fqdn = "${module.backend_subnet_b.dockernode_fqdn}"
		backend_b_services = "docker,cassandra,amq_private"
		backend_c_private_ip = "${module.backend_subnet_c.dockernode_ip}"
		backend_c_fqdn = "${module.backend_subnet_c.dockernode_fqdn}"
		backend_c_services = "docker,cassandra,amq_private"
		keyfile = "${aws_key_pair.deployer.key_name}"
		domainname = "${module.vpc.private_dns_domain}"
		orgname = "${var.orgname}"
	}
}

resource "null_resource" "write_rundeck_yaml" {
	provisioner "local-exec" {
		command = "printf -- '${template_file.rundeck-yaml.rendered}' > ${var.yaml_output_path}/${var.orgname}.yml"
	}
	depends_on = ["template_file.rundeck-yaml"]
}
provider "aws" {
region = "${var.aws_region}"
}
resource "aws_db_parameter_group" "sp_params" {
name = "custom-iam-dbparams"
family = "mysql5.6"
description = "Custom MySQL DB Params"
parameter {
name = "character_set_client"
value = "utf8"
}
parameter {
name = "character_set_connection"
value = "utf8"
}
parameter {
name = "character_set_database"
value = "utf8"
}
parameter {
name = "character_set_results"
value = "utf8"
}
parameter {
name = "character_set_server"
value = "utf8"
}
parameter {
name = "collation_connection"
value = "utf8_unicode_ci"
}
parameter {
name = "collation_server"
value = "utf8_unicode_ci"
}
parameter {
name = "innodb_large_prefix"
value = "1"
}
}
resource "aws_db_instance" "sp_iam" {
identifier = "${var.spath_orgname}-rds"
allocated_storage = "${var.spath_db_storage_size}"
iops = "${var.spath_db_iops}"
engine = "mysql"
# note that the version here has to line up
# with the one you use in the params
# unfortunately it's not the exact same string
engine_version = "${var.spath_db_engine_version}"
instance_class = "${var.spath_db_instance_class}"
backup_retention_period = "30"
username = "${var.iam_rds_user}"
password = "${var.iam_rds_password}"
db_subnet_group_name = "${aws_db_subnet_group.default.name}"
parameter_group_name = "${aws_db_parameter_group.sp_params.id}"
vpc_security_group_ids = [ "${var.spath_rds_sg_id}" ]
multi_az = "${var.multi_az}"
storage_encrypted = true
# this may help with a termination bug right now?
depends_on = ["aws_db_subnet_group.default"]
}
output "db_ip" {
value = "${aws_db_instance.sp_iam.address}"
}
output "db_username" {
value = "${var.iam_rds_user}"
}
output "db_password" {
value = "${var.iam_rds_password}"
}
resource "aws_db_subnet_group" "default" {
name = "${var.spath_orgname}-db-subnet"
description = "Our main group of subnets"
subnet_ids = ["${var.spath_rds_private_subnet_a_id}", "${var.spath_rds_private_subnet_b_id}", "${var.spath_rds_private_subnet_c_id}"]
}
variable "aws_region" { default = "us-west-2" }
variable "spath_db_engine_version" { default = "5.6.19b" }
variable "spath_db_instance_class" { default = "db.r3.2xlarge" }
variable "spath_db_param_group_name" { default = "default.mysql5.6" }
variable "spath_db_iops" { default = 1000 }
variable "spath_db_storage_size" { default = 100 }
variable "multi_az" { default = true }
# no sane defaults
variable "spath_orgname" {}
variable "iam_rds_user" {}
variable "iam_rds_password" {}
variable "spath_rds_sg_id" {}
variable "spath_rds_private_subnet_a_id" {}
variable "spath_rds_private_subnet_b_id" {}
variable "spath_rds_private_subnet_c_id" {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment