SlideShare una empresa de Scribd logo
1 de 191
Descargar para leer sin conexión
Untangling Terraform
Through Refactoring
HashiConf 2016
@nellshamrell
Who Am I?
Nell Shamrell-Harrington
• Software Engineer at Chef
• @nellshamrell
• nshamrell@chef.io
Let’s talk about Terraform!
Why Refactor?
• Add a feature
• Add a feature
• Fix a bug
Why Refactor?
• Add a feature
• Fix a bug
• Improve the design
Why Refactor?
• Add a feature
• Fix a bug
• Improve the design
• Optimize resource usage
Why Refactor?
Let’s go through
an example!
Today, we will refactor supermarket-terraform
http://github.com/nellshamrell/supermarket-terraform
supermarket-terraform
supermarket-cluster.tf
provider	
  “aws”	
  {	
  
	
  	
  access_key	
  =	
  “${var.access_key}”	
  
	
  	
  secret_key	
  =	
  “${var.secret_key}”	
  
}
supermarket-terraform
supermarket-cluster.tf
provider	
  “aws”	
  {	
  
	
  	
  access_key	
  =	
  “${var.access_key}”	
  
	
  	
  secret_key	
  =	
  “${var.secret_key}”	
  
}
supermarket-terraform
supermarket-cluster.tf
variables.tf
provider	
  “aws”	
  {	
  
	
  	
  access_key	
  =	
  “${var.access_key}”	
  
	
  	
  secret_key	
  =	
  “${var.secret_key}”	
  
}
variable	
  “access_key”	
  =	
  {}	
  	
  
variable	
  “secret_key”	
  =	
  {}
supermarket-terraform
supermarket-cluster.tf
variables.tf
terraform.tfvars
provider	
  “aws”	
  {	
  
	
  	
  access_key	
  =	
  “${var.access_key}”	
  
	
  	
  secret_key	
  =	
  “${var.secret_key}”	
  
}
variable	
  “access_key”	
  =	
  {}	
  	
  
variable	
  “secret_key”	
  =	
  {}
access_key	
  =	
  “xxxxx”	
  	
  
secret_key	
  =	
  “xxxxx”
supermarket-terraform
Wait…should you use
a credentials file?
You can…but for the
sake of the example,
let’s supply them inline
supermarket-cluster.tf
provider	
  “aws”	
  {	
  
	
  	
  access_key	
  =	
  “${var.access_key}”	
  
	
  	
  secret_key	
  =	
  “${var.secret_key}”	
  
}
supermarket-terraform
$ terraform apply
supermarket-cluster.tf
Security
Group
$ terraform apply
supermarket-cluster.tf
Security
Group
Allow SSH
$ terraform apply
supermarket-cluster.tf
Security
Group
Security
Group
Allow SSH
$ terraform apply
supermarket-cluster.tf
Security
Group
Security
Group
Allow SSH Allow Out
$ terraform apply
supermarket-cluster.tf
Security
Group
Security
Group
EC2
Allow SSH Allow Out
$ terraform apply
supermarket-cluster.tf
Security
Group
Security
Group
EC2
Chef Server
Allow SSH Allow Out
$ terraform apply
supermarket-cluster.tf
EC2
Security
Group
Security
Group
EC2
Chef Server
Allow OutAllow SSH
$ terraform apply
supermarket-cluster.tf
EC2
Security
Group
Security
Group
EC2
Chef Server Supermarket
Allow OutAllow SSH
$ terraform apply
supermarket-cluster.tf
EC2
Security
Group
Security
Group
EC2
Chef Server Supermarket
Allow OutAllow SSH
$ terraform apply
supermarket-cluster.tf
EC2
Security
Group
Security
Group
EC2
Chef Server Supermarket
Allow OutAllow SSH
$ terraform apply
supermarket-cluster.tf
EC2
Security
Group
Security
Group
EC2
Chef Server Supermarket
Allow OutAllow SSH
$ terraform apply
supermarket-cluster.tf
EC2
Security
Group
Security
Group
EC2
Chef Server Supermarket
Allow OutAllow SSH
$ terraform apply
supermarket-cluster.tf
Hypothetical:
We are using too many
AWS Security Groups
Why Refactor?
We need this config
to create only
one security group
Why Refactor?
Source: Working Effectively with Legacy Code
How to Refactor?
Two Approaches
Source: Working Effectively with Legacy Code
How to Refactor?
• Edit and Pray
Two Approaches
• Edit and Pray
• Cover and Modify
Two Approaches
Source: Working Effectively with Legacy Code
How to Refactor?
Confidence in code
without tests is
false confidence
What code is intended to do
is much less important
than what it actually does
Do I have to add tests
for the entire thing?
No.
The point of adding tests is
to not make things worse
And to start making
the code better
here and now
How can we test Terraform?
How Can We Test Terraform?
• Test Kitchen (http://kitchen.ci)
How Can We Test Terraform?
• Test Kitchen (http://kitchen.ci)
• Kitchen Terraform
(http://github.com/newcontext/
kitchen-terraform)
driver:	
  
	
  	
  name:	
  terraform	
  
provisioner:	
  
	
  	
  name:	
  terraform	
  
	
  	
  variable_files:	
  terraform.@vars	
  
transport:	
  	
  
	
  	
  name:	
  ssh	
  
	
  	
  ssh_key:	
  ~/path/to/your/aws/key	
  
pla@orms:	
  
	
  	
  -­‐	
  name:	
  ubuntu	
  
suites	
  
	
  	
  -­‐	
  name:	
  default	
  
.kitchen.yml
driver:	
  
	
  	
  name:	
  terraform	
  
provisioner:	
  
	
  	
  name:	
  terraform	
  
	
  	
  variable_files:	
  terraform.@vars	
  
transport:	
  	
  
	
  	
  name:	
  ssh	
  
	
  	
  ssh_key:	
  ~/path/to/your/aws/key	
  
pla@orms:	
  
	
  	
  -­‐	
  name:	
  ubuntu	
  
suites	
  
	
  	
  -­‐	
  name:	
  default	
  
.kitchen.yml
driver:	
  
	
  	
  name:	
  terraform	
  
provisioner:	
  
	
  	
  name:	
  terraform	
  
	
  	
  variable_files:	
  terraform.5vars	
  
transport:	
  	
  
	
  	
  name:	
  ssh	
  
	
  	
  ssh_key:	
  ~/path/to/your/aws/key	
  
pla@orms:	
  
	
  	
  -­‐	
  name:	
  ubuntu	
  
suites	
  
	
  	
  -­‐	
  name:	
  default	
  
.kitchen.yml
driver:	
  
	
  	
  name:	
  terraform	
  
provisioner:	
  
	
  	
  name:	
  terraform	
  
	
  	
  variable_files:	
  terraform.5vars	
  
transport:	
  	
  
	
  	
  name:	
  ssh	
  
	
  	
  ssh_key:	
  ~/path/to/your/aws/key	
  
pla@orms:	
  
	
  	
  -­‐	
  name:	
  ubuntu	
  
suites	
  
	
  	
  -­‐	
  name:	
  default	
  
.kitchen.yml
driver:	
  
	
  	
  name:	
  terraform	
  
provisioner:	
  
	
  	
  name:	
  terraform	
  
	
  	
  variable_files:	
  terraform.@vars	
  
transport:	
  	
  
	
  	
  name:	
  ssh	
  
	
  	
  ssh_key:	
  ~/path/to/your/aws/key	
  
pla@orms:	
  
	
  	
  -­‐	
  name:	
  ubuntu	
  
suites	
  
	
  	
  -­‐	
  name:	
  default	
  
.kitchen.yml
.kitchen.yml
driver:	
  
	
  	
  name:	
  terraform	
  
provisioner:	
  
	
  	
  name:	
  terraform	
  
	
  	
  variable_files:	
  terraform.@vars	
  
transport:	
  	
  
	
  	
  name:	
  ssh	
  
	
  	
  ssh_key:	
  ~/path/to/your/aws/key	
  
pla5orms:	
  
	
  	
  -­‐	
  name:	
  ubuntu	
  
suites	
  
	
  	
  -­‐	
  name:	
  default	
  
Test Kitchen
Boilerplate
• Test Kitchen (http://kitchen.ci)
• Kitchen Terraform
(http://github.com/newcontext/
kitchen-terraform)
• Inspec (http://chef.io/inspec)
How Can We Test Terraform?
Now that we have
our tools…
Let’s start from
a clean slate
#provider	
  “aws”	
  {	
  
#	
  	
  access_key	
  =	
  “${var.access_key}”	
  
#	
  	
  secret_key	
  =	
  “${var.secret_key}”	
  
#	
  	
  region	
  =	
  “${var.region}”	
  
#}	
  
#resource	
  “aws_security_group”	
  “allow-­‐ssh”	
  {	
  
#	
  	
  name	
  =	
  “${var.user_name}-­‐allow-­‐ssh”	
  
#	
  	
  tags	
  =	
  {	
  
#	
  	
  	
  	
  Name	
  =	
  “${var.user_name}	
  Allow	
  All	
  SSH”	
  
#	
  	
  }	
  
…
supermarket-cluster.tf
$ terraform apply
supermarket-cluster.tf
$ terraform apply
Nothing happens!
supermarket-cluster.tf
First, we need the provider
provider	
  “aws”	
  {	
  
	
  	
  access_key	
  =	
  “${var.access_key}”	
  
	
  	
  secret_key	
  =	
  “${var.secret_key}”	
  
	
  	
  region	
  =	
  “${var.region}”	
  
}	
  
#resource	
  “aws_security_group”	
  “allow-­‐ssh”	
  {	
  
#	
  	
  name	
  =	
  “${var.user_name}-­‐allow-­‐ssh”	
  
#	
  	
  tags	
  =	
  {	
  
#	
  	
  	
  	
  Name	
  =	
  “${var.user_name}	
  Allow	
  All	
  SSH”	
  
#	
  	
  }	
  
…
supermarket-cluster.tf
We also need actual
AWS instances
Including both our
Chef Server…
…	
  
#resource	
  “aws_instance”	
  “chef_server”	
  {	
  
#	
  	
  ami	
  =	
  “${var.ami}”	
  
#	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
#	
  	
  key_name	
  =	
  “${var.key_name}”	
  
#	
  	
  tags	
  {	
  
#	
  	
  	
  	
  Name	
  =	
  “dev-­‐chef-­‐server”	
  
#	
  	
  }	
  
#	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”,	
  
#	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  “${aws_security_group.allow-­‐out.name}”]	
  
#	
  	
  (…)	
  
#}	
  
…
This is the
Chef Server
supermarket-cluster.tf
…	
  
resource	
  “aws_instance”	
  “chef_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐chef-­‐server”	
  
	
  	
  }	
  
	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  “${aws_security_group.allow-­‐out.name}”]	
  
	
  	
  (…)	
  
}	
  
…
This is the
Chef Server
supermarket-cluster.tf
$ terraform apply
supermarket-cluster.tf
EC2
Chef Server $ terraform apply
supermarket-cluster.tf
And our supermarket
server
…	
  
#resource	
  “aws_instance”	
  “supermarket_server”	
  {	
  
#	
  	
  ami	
  =	
  “${var.ami}”	
  
#	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
#	
  	
  key_name	
  =	
  “${var.key_name}”	
  
#	
  	
  tags	
  {	
  
#	
  	
  	
  	
  Name	
  =	
  “dev-­‐supermarket-­‐server”	
  
#	
  	
  }	
  
#	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”,	
  
#	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  “${aws_security_group.allow-­‐out.name}”]	
  
#	
  	
  (…)	
  
#}	
  
…
This is the
Supermarket
Server
supermarket-cluster.tf
…	
  
resource	
  “aws_instance”	
  “supermarket_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐supermarket-­‐server”	
  
	
  	
  }	
  
	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  “${aws_security_group.allow-­‐out.name}”]	
  
	
  	
  (…)	
  
}	
  
…
This is the
Supermarket
Server
supermarket-cluster.tf
EC2
Chef Server $ terraform apply
EC2
Supermarket
supermarket-cluster.tf
We also need at least
one security group
#resource	
  “aws_security_group”	
  “allow-­‐ssh”	
  {	
  
#	
  	
  name	
  =	
  “${var.user_name}-­‐allow-­‐ssh”	
  
#	
  	
  tags	
  =	
  {	
  
#	
  	
  	
  	
  Name	
  =	
  “${var.user_name}	
  Allow	
  all	
  ssh”	
  
#	
  	
  }	
  
#}	
  
#resource	
  “aws_security_group_rule”	
  “allow-­‐ssh”	
  {	
  
#	
  	
  type	
  =	
  “ingress”	
  
#	
  	
  from_port	
  =	
  22	
  
#	
  	
  to_port	
  =	
  22	
  
	
  	
  …	
  
#}
supermarket-cluster.tf
resource	
  “aws_security_group”	
  “allow-­‐ssh”	
  {	
  
	
  	
  name	
  =	
  “${var.user_name}-­‐allow-­‐ssh”	
  
	
  	
  tags	
  =	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “${var.user_name}	
  Allow	
  all	
  ssh”	
  
	
  	
  }	
  
}	
  
#resource	
  “aws_security_group_rule”	
  “allow-­‐ssh”	
  {	
  
#	
  	
  type	
  =	
  “ingress”	
  
#	
  	
  from_port	
  =	
  22	
  
#	
  	
  to_port	
  =	
  22	
  
	
  	
  …	
  
#}
supermarket-cluster.tf
EC2
Chef Server
supermarket-cluster.tf
$ terraform apply
EC2
Supermarket
Security
Group
kitchen-terraform
needs to be able to
ssh into our instances
We need a security
group rule
resource	
  “aws_security_group”	
  “allow-­‐ssh”	
  {	
  
	
  	
  name	
  =	
  “${var.user_name}-­‐allow-­‐ssh”	
  
	
  	
  tags	
  =	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “${var.user_name}	
  Allow	
  all	
  ssh”	
  
	
  	
  }	
  
}	
  
#resource	
  “aws_security_group_rule”	
  “allow-­‐ssh”	
  {	
  
#	
  type	
  =	
  “ingress”	
  
#	
  from_port	
  =	
  22	
  
#	
  to_port	
  =	
  22	
  
	
  	
  …	
  
#}
supermarket-cluster.tf
resource	
  “aws_security_group”	
  “allow-­‐ssh”	
  {	
  
	
  	
  name	
  =	
  “${var.user_name}-­‐allow-­‐ssh”	
  
	
  	
  tags	
  =	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “${var.user_name}	
  Allow	
  all	
  ssh”	
  
	
  	
  }	
  
}	
  
resource	
  “aws_security_group_rule”	
  “allow-­‐ssh”	
  {	
  
	
  type	
  =	
  “ingress”	
  
	
  from_port	
  =	
  22	
  
	
  to_port	
  =	
  22	
  
	
  	
  …	
  
}
supermarket-cluster.tf
EC2
Chef Server $ terraform apply
EC2
Supermarket
Security
Group
Allow SSH
supermarket-cluster.tf
Now, let’s create
our test cluster
$ kitchen converge
Like running terraform apply
$ kitchen converge
$ kitchen converge
(…)
>>>>>> ------Exception-------
>>>>>> Class: Kitchen::ActionFailed
>>>>>> Message: 1 actions failed.
>>>>>> Converge failed on instance
<default-ubuntu>.
>>>>>> Please see .kitchen/logs/kitchen.log for
more details
-­‐-­‐-­‐-­‐	
  Begin	
  output	
  of	
  terraform	
  validate	
  	
  /root/supermarket-­‐terraform-­‐2	
  -­‐-­‐-­‐-­‐	
  
STDOUT:	
  
STDERR:	
  ^[[31mError	
  validaWng:	
  2	
  error(s)	
  occurred:	
  
* resource	
  'aws_instance.chef_server'	
  config:	
  unknown	
  resource	
  	
  
* 'aws_security_group.allow-­‐egress'	
  referenced	
  in	
  	
  
* variable	
  aws_security_group.allow-­‐egress.name	
  
* resource	
  'aws_instance.supermarket_server'	
  config:	
  	
  
* unknown	
  resource	
  'aws_security_group.allow-­‐egress'	
  	
  
* referenced	
  in	
  variable	
  aws_security_group.allow-­‐egress.	
  
* name
.kitchen/logs/default-ubuntu.log
We need our EC2 resources
to reference only one
security group
Let’s look at the Chef Server
…	
  
resource	
  “aws_instance”	
  “chef_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐chef-­‐server”	
  
	
  	
  }	
  
	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  “${aws_security_group.allow-­‐out.name}”]	
  
	
  	
  (…)	
  
}	
  
…
This is the
Chef Server
supermarket-cluster.tf
…	
  
resource	
  “aws_instance”	
  “chef_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐chef-­‐server”	
  
	
  	
  }	
  
	
  	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”]	
  
	
  	
  (…)	
  
}	
  
…
This is the
Chef Server
supermarket-cluster.tf
And the Supermarket Server
…	
  
resource	
  “aws_instance”	
  “supermarket_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐supermarket-­‐server”	
  
	
  	
  }	
  
	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  “${aws_security_group.allow-­‐out.name}”]	
  
	
  	
  (…)	
  
}	
  
…
This is the
Supermarket
Server
supermarket-cluster.tf
…	
  
resource	
  “aws_instance”	
  “supermarket_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐supermarket-­‐server”	
  
	
  	
  }	
  
	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”	
  	
  	
  
	
  	
  (…)	
  
}	
  
…
This is the
Supermarket
Server
supermarket-cluster.tf
$ kitchen converge$ kitchen converge
$ kitchen converge
Apply complete! Resources: 2 added,
0 changed, 0 destroyed.
(…)
Finished converging <default-ubuntu>
(0m7.10s).
EC2
Chef Server
EC2
Supermarket
Security
Group
Allow SSH
supermarket-cluster.tf
$ terraform apply
Now let’s write
some tests
First, let’s define
a test group
driver:	
  
	
  	
  name:	
  terraform	
  
	
  	
  (…)	
  
verifier:	
  
	
  	
  name:	
  terraform	
  
	
  	
  format:	
  doc	
  
	
  	
  groups:	
  
	
  	
  -­‐	
  name:	
  default	
  
	
  	
  	
  	
  tests:	
  
	
  	
  	
  	
  	
  	
  	
  -­‐	
  security_groups	
  
	
  	
  	
  	
  hostnames:	
  aws_hostnames	
  
	
  	
  	
  	
  username:	
  ubuntu
.kitchen.yml
driver:	
  
	
  	
  name:	
  terraform	
  
	
  	
  (…)	
  
verifier:	
  
	
  	
  name:	
  terraform	
  
	
  	
  format:	
  doc	
  
	
  	
  groups:	
  
	
  	
  -­‐	
  name:	
  default	
  
	
  	
  	
  	
  tests:	
  
	
  	
  	
  	
  	
  	
  	
  -­‐	
  security_groups	
  
	
  	
  	
  	
  hostnames:	
  aws_hostnames	
  
	
  	
  	
  	
  username:	
  ubuntu
.kitchen.yml
driver:	
  
	
  	
  name:	
  terraform	
  
	
  	
  (…)	
  
verifier:	
  
	
  	
  name:	
  terraform	
  
	
  	
  format:	
  doc	
  
	
  	
  groups:	
  
	
  	
  -­‐	
  name:	
  default	
  
	
  	
  	
  	
  tests:	
  
	
  	
  	
  	
  	
  	
  	
  -­‐	
  security_groups	
  
	
  	
  	
  	
  hostnames:	
  aws_hostnames	
  
	
  	
  	
  	
  username:	
  ubuntu
.kitchen.yml
driver:	
  
	
  	
  name:	
  terraform	
  
	
  	
  (…)	
  
verifier:	
  
	
  	
  name:	
  terraform	
  
	
  	
  format:	
  doc	
  
	
  	
  groups:	
  
	
  	
  -­‐	
  name:	
  default	
  
	
  	
  	
  	
  tests:	
  
	
  	
  	
  	
  	
  	
  	
  -­‐	
  security_groups	
  
	
  	
  	
  	
  hostnames:	
  aws_hostnames	
  
	
  	
  	
  	
  username:	
  ubuntu
.kitchen.yml
Output variable
driver:	
  
	
  	
  name:	
  terraform	
  
	
  	
  (…)	
  
verifier:	
  
	
  	
  name:	
  terraform	
  
	
  	
  format:	
  doc	
  
	
  	
  groups:	
  
	
  	
  -­‐	
  name:	
  default	
  
	
  	
  	
  	
  tests:	
  
	
  	
  	
  	
  	
  	
  	
  -­‐	
  security_groups	
  
	
  	
  	
  	
  hostnames:	
  aws_hostnames	
  
	
  	
  	
  	
  username:	
  ubuntu
.kitchen.yml
We need to create
that output variable
output	
  “aws_hostnames”	
  {	
  
}
outputs.tf
output	
  “aws_hostnames”	
  {	
  
	
  	
  value	
  =	
  “${aws_instance.chef_server.public_dns},	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ${aws_instance.supermarket_server.public_dns}”	
  
}
outputs.tf
output	
  “aws_hostnames”	
  {	
  
	
  	
  value	
  =	
  “${aws_instance.chef_server.public_dns},	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ${aws_instance.supermarket_server.public_dns}”	
  
}
outputs.tf
Spins up AWS
resources
Using Outputs
Spins up AWS
resources
Captures public_dns
of EC2 instances
in aws_hostnames
Using Outputs
Spins up AWS
resources
Passes to
kitchen-terraform
Captures public_dns
of EC2 instances
in aws_hostnames
Using Outputs
Spins up AWS
resources
Captures public_dns
of EC2 instances
in aws_hostnames
Passes to
kitchen-terraform
kitchen-terraform
uses aws_hostnames
to ssh into the instances
Using Outputs
Spins up AWS
resources
Runs
Tests
kitchen-terraform
uses aws_hostnames
to ssh into the instances
Captures public_dns
of EC2 instances
in aws_hostnames
Passes to
kitchen-terraform
Using Outputs
$ kitchen destroy$ kitchen destroy
$ kitchen destroy
$ kitchen converge
$ kitchen destroy
$ kitchen converge
#resource	
  “aws_security_group”	
  “allow-­‐egress”	
  {	
  
#	
  	
  name	
  =	
  “${var.user_name}-­‐allow-­‐egress”	
  
#	
  	
  tags	
  =	
  {	
  
#	
  	
  	
  	
  Name	
  =	
  “${var.user_name}	
  Allow	
  connecLons	
  out”	
  
#	
  	
  }	
  
#}	
  
#resource	
  “aws_security_group_rule”	
  “allow-­‐out”	
  {	
  
#	
  type	
  =	
  “egress”	
  
#	
  from_port	
  =	
  0	
  
#	
  to_port	
  =	
  65535	
  
#	
  cidr_blocks	
  =	
  ["0.0.0.0/0"]	
  
	
  	
  …
supermarket-cluster.tf
Let’s write a test
describe	
  command(‘ping	
  -­‐c	
  1	
  google.com’)	
  do	
  
	
  	
  
end
security_groups_spec.rb
describe	
  command(‘ping	
  -­‐c	
  1	
  google.com’)	
  do	
  
	
  	
  its(‘stdout’)	
  {	
  should	
  match	
  /1	
  packets	
  transmiSed,	
  1	
  received/	
  }	
  
end
security_groups_spec.rb
$ kitchen verify$ kitchen verify
$ kitchen verify
Failure/Error:
expected "PING google.com (216.58.218.238)
56(84) bytes of data.nn--- google.com
ping statistics —n
1 packets transmitted, 0 received,
to match /1 packets transmitted, 1 received/
Diff:
@@ -1,2 +1,5 @@
-/1 packets transmitted, 1 received/
Good! We have a failure!
Now let’s make it pass
#resource	
  “aws_security_group”	
  “allow-­‐egress”	
  {	
  
#	
  	
  name	
  =	
  “${var.user_name}-­‐allow-­‐egress”	
  
#	
  	
  tags	
  =	
  {	
  
#	
  	
  	
  	
  Name	
  =	
  “${var.user_name}	
  Allow	
  connecLons	
  out”	
  
#	
  	
  }	
  
#}	
  
#resource	
  “aws_security_group_rule”	
  “allow-­‐out”	
  {	
  
#	
  type	
  =	
  “egress”	
  
#	
  from_port	
  =	
  0	
  
#	
  to_port	
  =	
  65535	
  
#	
  cidr_blocks	
  =	
  ["0.0.0.0/0"]	
  
	
  	
  …
supermarket-cluster.tf
resource	
  “aws_security_group”	
  “allow-­‐egress”	
  {	
  
	
  	
  name	
  =	
  “${var.user_name}-­‐allow-­‐egress”	
  
	
  	
  tags	
  =	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “${var.user_name}	
  Allow	
  connecTons	
  out”	
  
	
  	
  }	
  
}	
  
resource	
  “aws_security_group_rule”	
  “allow-­‐out”	
  {	
  
	
  type	
  =	
  “egress”	
  
	
  from_port	
  =	
  0	
  
	
  to_port	
  =	
  65535	
  
	
  cidr_blocks	
  =	
  ["0.0.0.0/0"]	
  
	
  	
  …	
  
supermarket-cluster.tf
EC2
Chef Server $ terraform apply
EC2
Supermarket
Security
Group
Allow SSH
Security
Group
Allow Out
supermarket-cluster.tf
Now let’s call this
security group from our
Chef Server
…	
  
resource	
  “aws_instance”	
  “chef_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐chef-­‐server”	
  
	
  	
  }	
  
	
  	
  	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”]	
  
	
  	
  (…)	
  
}	
  
…
This is the
Chef Server
supermarket-cluster.tf
…	
  
resource	
  “aws_instance”	
  “chef_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐chef-­‐server”	
  
	
  	
  }	
  
	
  	
  	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  “${aws_security_group.allow-­‐out.name}”]	
  
	
  	
  (…)	
  
}	
  
…
This is the
Chef Server
supermarket-cluster.tf
And the Supermarket Server
…	
  
resource	
  “aws_instance”	
  “supermarket_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐supermarket-­‐server”	
  
	
  	
  }	
  
	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”	
  	
  	
  
	
  	
  (…)	
  
}	
  
…
This is the
Supermarket
Server
supermarket-cluster.tf
…	
  
resource	
  “aws_instance”	
  “supermarket_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐supermarket-­‐server”	
  
	
  	
  }	
  
	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  “${aws_security_group.allow-­‐out.name}”]	
  
	
  	
  (…)	
  
}	
  
…
This is the
Supermarket
Server
supermarket-cluster.tf
$ kitchen destroy
$ kitchen converge
$ kitchen destroy
$ kitchen converge
$ kitchen destroy
$ kitchen converge
$ kitchen verify
$ kitchen verify$ kitchen verify$ kitchen verify
Command ping -c 1 google.com
stdout
should match /1 packets transmitted,
1 received/
1 example, 0 failures
It passes!
Now let’s make a
change
Let’s condense the
two security groups
into one security group
resource	
  “aws_security_group”	
  “allow-­‐egress”	
  {	
  
	
  	
  name	
  =	
  “${var.user_name}-­‐allow-­‐egress”	
  
	
  	
  tags	
  =	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “${var.user_name}	
  Allow	
  connecWons	
  out”	
  
	
  	
  }	
  
}	
  
resource	
  “aws_security_group_rule”	
  “allow-­‐out”	
  {	
  
	
  type	
  =	
  “egress”	
  
	
  from_port	
  =	
  0	
  
	
  to_port	
  =	
  65535	
  
	
  cidr_blocks	
  =	
  ["0.0.0.0/0"]	
  
	
  	
  …	
  
supermarket-cluster.tf
resource	
  “aws_security_group_rule”	
  “allow-­‐out”	
  {	
  
	
  type	
  =	
  “egress”	
  
	
  from_port	
  =	
  0	
  
	
  to_port	
  =	
  65535	
  
	
  cidr_blocks	
  =	
  ["0.0.0.0/0"]	
  
	
  security_group_id	
  “${aws_security_group.allow-­‐egress.id}”	
  
}
supermarket-cluster.tf
resource	
  “aws_security_group_rule”	
  “allow-­‐out”	
  {	
  
	
  type	
  =	
  “egress”	
  
	
  from_port	
  =	
  0	
  
	
  to_port	
  =	
  65535	
  
	
  cidr_blocks	
  =	
  ["0.0.0.0/0"]	
  
	
  security_group_id	
  “${aws_security_group.allow-­‐ssh.id}”	
  
}
supermarket-cluster.tf
Now our instances
should only use the
one security group
…	
  
resource	
  “aws_instance”	
  “chef_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐chef-­‐server”	
  
	
  	
  }	
  
	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  “${aws_security_group.allow-­‐out.name}”]	
  
	
  	
  (…)	
  
}	
  
…
This is the
Chef Server
supermarket-cluster.tf
…	
  
resource	
  “aws_instance”	
  “chef_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐chef-­‐server”	
  
	
  	
  }	
  
	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”]	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  (…)	
  
}	
  
…
This is the
Chef Server
supermarket-cluster.tf
…	
  
resource	
  “aws_instance”	
  “supermarket_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐supermarket-­‐server”	
  
	
  	
  }	
  
	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  “${aws_security_group.allow-­‐out.name}”]	
  	
  	
  
	
  (…)	
  
}	
  
…
This is the
Supermarket
Server
supermarket-cluster.tf
…	
  
resource	
  “aws_instance”	
  “supermarket_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐supermarket-­‐server”	
  
	
  	
  }	
  
	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”]	
  	
  
	
  (…)	
  
}	
  
…
This is the
Supermarket
Server
supermarket-cluster.tf
EC2
Chef Server
$ terraform apply EC2
Supermarket
Security
Group
Allow SSH
Allow Out
supermarket-cluster.tf
$ kitchen destroy
$ kitchen converge
$ kitchen destroy
$ kitchen converge
$ kitchen verify
$ kitchen verify$ kitchen verify
Command ping -c 1 google.com
stdout
should match /1 packets transmitted,
1 received/
1 example, 0 failures
Now let’s improve the design
By moving the security
group code into a module
Source: Terraform Docs
Why Move into a Module?
• Self-contained package
Source: Terraform Docs
Why Move into a Module?
• Self-contained package
• Reusable component
• Self-contained package
• Reusable component
• Improve organization
Source: Terraform Docs
Why Move into a Module?
$ kitchen destroy
$ mkdir security_groups
security-groups/main.tf
resource	
  “aws_security_group”	
  “allow-­‐ssh”	
  {	
  
	
  name	
  =	
  “${var.user_name}-­‐allow-­‐ssh”	
  
	
  tags	
  =	
  {	
  
	
  	
  	
  Name	
  =	
  “${var.user_name}	
  Allow	
  All	
  SSH”	
  
	
  }	
  
resource	
  “aws_security_group_rule”	
  “allow-­‐ssh”	
  {	
  
	
  type	
  =	
  “ingress”	
  
	
  from_port	
  =	
  22	
  
	
  to_port	
  =	
  22	
  
	
  	
  …	
  
}
security-groups/main.tf
Now we need to
connect to the module
from main config
First, we need to
know what variables
the module needs
passed to it
resource	
  “aws_security_group”	
  “allow-­‐ssh”	
  {	
  
	
  name	
  =	
  “${var.user_name}-­‐allow-­‐ssh”	
  
	
  tags	
  =	
  {	
  
	
  	
  	
  Name	
  =	
  “${var.user_name}	
  Allow	
  All	
  SSH”	
  
	
  }	
  
resource	
  “aws_security_group_rule”	
  “allow-­‐ssh”	
  {	
  
	
  type	
  =	
  “ingress”	
  
	
  from_port	
  =	
  22	
  
	
  	
  …	
  
	
  	
  security_group_id	
  =	
  “${aws_security_group.allow-­‐ssh.id}”	
  
}
Needs to be passed
to the module
security-groups/main.tf
resource	
  “aws_security_group”	
  “allow-­‐ssh”	
  {	
  
	
  name	
  =	
  “${var.user_name}-­‐allow-­‐ssh”	
  
	
  tags	
  =	
  {	
  
	
  	
  	
  Name	
  =	
  “${var.user_name}	
  Allow	
  All	
  SSH”	
  
	
  }	
  
resource	
  “aws_security_group_rule”	
  “allow-­‐ssh”	
  {	
  
	
  type	
  =	
  “ingress”	
  
	
  from_port	
  =	
  22	
  
	
  	
  …	
  
	
  	
  security_group_id	
  =	
  “${aws_security_group.allow-­‐ssh.id}”	
  
}
security-groups/main.tf
Thank you,
Nikhil Vaze!
resource	
  “aws_security_group”	
  “allow-­‐ssh”	
  {	
  
	
  name	
  =	
  “${var.user_name}-­‐allow-­‐ssh”	
  
	
  tags	
  =	
  {	
  
	
  	
  	
  Name	
  =	
  “${var.user_name}	
  Allow	
  All	
  SSH”	
  
	
  }	
  
resource	
  “aws_security_group_rule”	
  “allow-­‐ssh”	
  {	
  
	
  type	
  =	
  “ingress”	
  
	
  from_port	
  =	
  22	
  
	
  	
  …	
  
	
  	
  security_group_id	
  =	
  “${aws_security_group.allow-­‐ssh.id}”	
  
}
Does not need
to be passed in
security-groups/main.tf
Uses
variables
supermarket-
cluster.tf
Using the Module
variables.tf
supermarket-
cluster.tf
Defines
variables
used by
config
Using the Module
terraform.tfvars
variables.tf
supermarket-
cluster.tf
Defines
values
for
variables
Using the Module
terraform.tfvars
variables.tf
supermarket-
cluster.tf
security-groups module
Defines
variables used
by module config
variables.tf
Using the Module
variable	
  “user_name”	
  {}
security-groups/variables.tf
terraform.tfvars
variables.tf
supermarket-
cluster.tf
security-groups module
Uses
variables
variables.tf
main.tf
Using the Module
terraform.tfvars
variables.tf
supermarket-
cluster.tf
security-groups module
Passes
variables
to
module
variables.tf
main.tf
Using the Module
module	
  “security-­‐groups”	
  {	
  
	
  	
  source	
  =	
  “./security-­‐groups”	
  
	
  	
  user_name	
  =	
  “${var.user_name}”	
  
}
supermarket-cluster.tf
module	
  “security-­‐groups”	
  {	
  
	
  	
  source	
  =	
  “./security-­‐groups”	
  
	
  	
  user_name	
  =	
  “${var.user_name}”	
  
}
supermarket-cluster.tf
$ kitchen converge
$ kitchen converge
-----> Starting Kitchen (v1.10.2)
-----> Converging <default-ubuntu>…
(…)
>>>>>> ------Exception-------
>>>>>> Class: Kitchen::ActionFailed
Message: 1 actions failed.
>>>>>> Converge failed on instance
<default-ubuntu>. Please see
.kitchen/logs/default-ubuntu.log for more details
$ kitchen converge
-----> Starting Kitchen (v1.10.2)
-----> Converging <default-ubuntu>…
(…)
>>>>>> ------Exception-------
>>>>>> Class: Kitchen::ActionFailed
Message: 1 actions failed.
>>>>>> Converge failed on instance
<default-ubuntu>. Please see
.kitchen/logs/default-ubuntu.log for more details
-­‐-­‐-­‐	
  Begin	
  output	
  of	
  terraform	
  validate	
  (…)	
  
STDOUT:	
  
STDERR:	
  Error	
  validaWng:	
  2	
  error(s)	
  occurred:	
  
* resource	
  'aws_instance.supermarket_server'	
  config:	
  	
  
* unknown	
  resource	
  'aws_security_group.allow-­‐ssh'	
  	
  
* referenced	
  in	
  variable	
  aws_security_group.allow-­‐ssh.name	
  
* resource	
  'aws_instance.chef_server'	
  config:	
  	
  
* unknown	
  resource	
  'aws_security_group.allow-­‐ssh'	
  	
  
* referenced	
  in	
  variable	
  aws_security_group.allow-­‐ssh.name
.kitchen/logs/default-ubuntu.log
terraform.tfvars
variables.tf
supermarket-
cluster.tf
security-groups module
variables.tf
main.tf
output.tf
Passes
output
values to
main
config
Workflow Into The Module
output	
  “sg-­‐name”	
  {	
  
	
  	
  
}
security-groups/output.tf
output	
  “sg-­‐name”	
  {	
  
	
  	
  value	
  =	
  “${aws_security_group.allow-­‐ssh.name}”	
  
}
security-groups/output.tf
Now, we need to use
this output in our
supermarket-cluster
config
…	
  
resource	
  “aws_instance”	
  “chef_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐chef-­‐server”	
  
	
  	
  }	
  
	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh.name}”]	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  (…)	
  
}	
  
…
This is the
Chef Server
supermarket-cluster.tf
…	
  
resource	
  “aws_instance”	
  “chef_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐chef-­‐server”	
  
	
  	
  }	
  
	
  	
  security_groups	
  =	
  [“${module.security-­‐groups.sg-­‐name}”]	
  
	
  	
  	
  
	
  	
  (…)	
  
}	
  
…
This is the
Chef Server
supermarket-cluster.tf
…	
  
resource	
  “aws_instance”	
  “supermarket_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐supermarket-­‐server”	
  
	
  	
  }	
  
	
  	
  security_groups	
  =	
  [“${aws_security_group.allow-­‐ssh-­‐name}”]	
  	
  
	
  	
  (…)	
  
}	
  
…
This is the
Supermarket
Server
supermarket-cluster.tf
…	
  
resource	
  “aws_instance”	
  “supermarket_server”	
  {	
  
	
  	
  ami	
  =	
  “${var.ami}”	
  
	
  	
  instance_type	
  =	
  “${var.instance_type}”	
  
	
  	
  key_name	
  =	
  “${var.key_name}”	
  
	
  	
  tags	
  {	
  
	
  	
  	
  	
  Name	
  =	
  “dev-­‐supermarket-­‐server”	
  
	
  	
  }	
  
	
  	
  security_groups	
  =	
  [“${module.security-­‐groups.sg-­‐name}”]	
  
	
  	
  
	
  	
  (…)	
  
}	
  
…
This is the
Supermarket
Server
supermarket-cluster.tf
$ kitchen converge
$ kitchen converge
$ kitchen verify
$ kitchen verify$ kitchen verify$ kitchen verify
Command ping -c 1 google.com
stdout
should match /1 packets transmitted,
1 received/
1 example, 0 failures
So we have improved our
resource usage
And the code’s
organization and
design
With minimal risk
Infrastructure code
must be maintained
and refactored just like
application code
Even more so
because infrastructure
code involves so many
moving pieces
When refactoring,
always cover with tests
And refactor one small
piece at a time
Thank you
Who Am I?
Nell Shamrell-Harrington
• Software Engineer at Chef
• @nellshamrell
• nshamrell@chef.io
Who Am I?
Any Questions?
Nell Shamrell-Harrington
• Software Engineer at Chef
• @nellshamrell
• nshamrell@chef.io

Más contenido relacionado

La actualidad más candente

"Continuously delivering infrastructure using Terraform and Packer" training ...
"Continuously delivering infrastructure using Terraform and Packer" training ..."Continuously delivering infrastructure using Terraform and Packer" training ...
"Continuously delivering infrastructure using Terraform and Packer" training ...Anton Babenko
 
A Hands-on Introduction on Terraform Best Concepts and Best Practices
A Hands-on Introduction on Terraform Best Concepts and Best Practices A Hands-on Introduction on Terraform Best Concepts and Best Practices
A Hands-on Introduction on Terraform Best Concepts and Best Practices Nebulaworks
 
An intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECSAn intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECSYevgeniy Brikman
 
Infrastructure as Code: Introduction to Terraform
Infrastructure as Code: Introduction to TerraformInfrastructure as Code: Introduction to Terraform
Infrastructure as Code: Introduction to TerraformAlexander Popov
 
Terraform - Taming Modern Clouds
Terraform  - Taming Modern CloudsTerraform  - Taming Modern Clouds
Terraform - Taming Modern CloudsNic Jackson
 
Terraform introduction
Terraform introductionTerraform introduction
Terraform introductionJason Vance
 
Terraform: Cloud Configuration Management (WTC/IPC'16)
Terraform: Cloud Configuration Management (WTC/IPC'16)Terraform: Cloud Configuration Management (WTC/IPC'16)
Terraform: Cloud Configuration Management (WTC/IPC'16)Martin Schütte
 
Infrastructure as Code with Terraform
Infrastructure as Code with TerraformInfrastructure as Code with Terraform
Infrastructure as Code with TerraformMario IC
 
Reusable, composable, battle-tested Terraform modules
Reusable, composable, battle-tested Terraform modulesReusable, composable, battle-tested Terraform modules
Reusable, composable, battle-tested Terraform modulesYevgeniy Brikman
 
Terraform in deployment pipeline
Terraform in deployment pipelineTerraform in deployment pipeline
Terraform in deployment pipelineAnton Babenko
 
AWS DevOps - Terraform, Docker, HashiCorp Vault
AWS DevOps - Terraform, Docker, HashiCorp VaultAWS DevOps - Terraform, Docker, HashiCorp Vault
AWS DevOps - Terraform, Docker, HashiCorp VaultGrzegorz Adamowicz
 
Terraform Modules and Continuous Deployment
Terraform Modules and Continuous DeploymentTerraform Modules and Continuous Deployment
Terraform Modules and Continuous DeploymentZane Williamson
 
Terraform: Configuration Management for Cloud Services
Terraform: Configuration Management for Cloud ServicesTerraform: Configuration Management for Cloud Services
Terraform: Configuration Management for Cloud ServicesMartin Schütte
 
Terraforming the Kubernetes Land
Terraforming the Kubernetes LandTerraforming the Kubernetes Land
Terraforming the Kubernetes LandRadek Simko
 
Comprehensive Terraform Training
Comprehensive Terraform TrainingComprehensive Terraform Training
Comprehensive Terraform TrainingYevgeniy Brikman
 
Everything as Code with Terraform
Everything as Code with TerraformEverything as Code with Terraform
Everything as Code with TerraformAll Things Open
 
Writing Ansible Modules (DENOG11)
Writing Ansible Modules (DENOG11)Writing Ansible Modules (DENOG11)
Writing Ansible Modules (DENOG11)Martin Schütte
 
Infrastructure as Code in Google Cloud
Infrastructure as Code in Google CloudInfrastructure as Code in Google Cloud
Infrastructure as Code in Google CloudRadek Simko
 

La actualidad más candente (20)

"Continuously delivering infrastructure using Terraform and Packer" training ...
"Continuously delivering infrastructure using Terraform and Packer" training ..."Continuously delivering infrastructure using Terraform and Packer" training ...
"Continuously delivering infrastructure using Terraform and Packer" training ...
 
A Hands-on Introduction on Terraform Best Concepts and Best Practices
A Hands-on Introduction on Terraform Best Concepts and Best Practices A Hands-on Introduction on Terraform Best Concepts and Best Practices
A Hands-on Introduction on Terraform Best Concepts and Best Practices
 
Intro to Terraform
Intro to TerraformIntro to Terraform
Intro to Terraform
 
An intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECSAn intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECS
 
Infrastructure as Code: Introduction to Terraform
Infrastructure as Code: Introduction to TerraformInfrastructure as Code: Introduction to Terraform
Infrastructure as Code: Introduction to Terraform
 
Terraform - Taming Modern Clouds
Terraform  - Taming Modern CloudsTerraform  - Taming Modern Clouds
Terraform - Taming Modern Clouds
 
Terraform introduction
Terraform introductionTerraform introduction
Terraform introduction
 
Terraform: Cloud Configuration Management (WTC/IPC'16)
Terraform: Cloud Configuration Management (WTC/IPC'16)Terraform: Cloud Configuration Management (WTC/IPC'16)
Terraform: Cloud Configuration Management (WTC/IPC'16)
 
Infrastructure as Code with Terraform
Infrastructure as Code with TerraformInfrastructure as Code with Terraform
Infrastructure as Code with Terraform
 
Reusable, composable, battle-tested Terraform modules
Reusable, composable, battle-tested Terraform modulesReusable, composable, battle-tested Terraform modules
Reusable, composable, battle-tested Terraform modules
 
Terraform in deployment pipeline
Terraform in deployment pipelineTerraform in deployment pipeline
Terraform in deployment pipeline
 
AWS DevOps - Terraform, Docker, HashiCorp Vault
AWS DevOps - Terraform, Docker, HashiCorp VaultAWS DevOps - Terraform, Docker, HashiCorp Vault
AWS DevOps - Terraform, Docker, HashiCorp Vault
 
Terraform Modules and Continuous Deployment
Terraform Modules and Continuous DeploymentTerraform Modules and Continuous Deployment
Terraform Modules and Continuous Deployment
 
Everything as Code with Terraform
Everything as Code with TerraformEverything as Code with Terraform
Everything as Code with Terraform
 
Terraform: Configuration Management for Cloud Services
Terraform: Configuration Management for Cloud ServicesTerraform: Configuration Management for Cloud Services
Terraform: Configuration Management for Cloud Services
 
Terraforming the Kubernetes Land
Terraforming the Kubernetes LandTerraforming the Kubernetes Land
Terraforming the Kubernetes Land
 
Comprehensive Terraform Training
Comprehensive Terraform TrainingComprehensive Terraform Training
Comprehensive Terraform Training
 
Everything as Code with Terraform
Everything as Code with TerraformEverything as Code with Terraform
Everything as Code with Terraform
 
Writing Ansible Modules (DENOG11)
Writing Ansible Modules (DENOG11)Writing Ansible Modules (DENOG11)
Writing Ansible Modules (DENOG11)
 
Infrastructure as Code in Google Cloud
Infrastructure as Code in Google CloudInfrastructure as Code in Google Cloud
Infrastructure as Code in Google Cloud
 

Destacado

Building Enigma with State Monad & Lens
Building Enigma with State Monad & LensBuilding Enigma with State Monad & Lens
Building Enigma with State Monad & LensTimothy Perrett
 
Terraform and cloud.ca
Terraform and cloud.caTerraform and cloud.ca
Terraform and cloud.caCloudOps2005
 
Rapid Infrastructure Provisioning
Rapid Infrastructure ProvisioningRapid Infrastructure Provisioning
Rapid Infrastructure ProvisioningUchit Vyas ☁
 
DevOps - Infrastructure as Code by Andre Marcelo-Tanner
DevOps - Infrastructure as Code by Andre Marcelo-TannerDevOps - Infrastructure as Code by Andre Marcelo-Tanner
DevOps - Infrastructure as Code by Andre Marcelo-TannerDEVCON
 
2016 - IGNITE - Terraform to go from Zero to Prod in less than 1 month and TH...
2016 - IGNITE - Terraform to go from Zero to Prod in less than 1 month and TH...2016 - IGNITE - Terraform to go from Zero to Prod in less than 1 month and TH...
2016 - IGNITE - Terraform to go from Zero to Prod in less than 1 month and TH...devopsdaysaustin
 
TerraformでECS+ECRする話
TerraformでECS+ECRする話TerraformでECS+ECRする話
TerraformでECS+ECRする話Satoshi Hirayama
 
Rediscovering Developer Opportunities in the Philippines by Fred Tshidimba
Rediscovering Developer Opportunities in the Philippines by Fred TshidimbaRediscovering Developer Opportunities in the Philippines by Fred Tshidimba
Rediscovering Developer Opportunities in the Philippines by Fred TshidimbaDEVCON
 
Jsonnet, terraform & packer
Jsonnet, terraform & packerJsonnet, terraform & packer
Jsonnet, terraform & packerDavid Cunningham
 
Infrastructure as code with Terraform
Infrastructure as code with TerraformInfrastructure as code with Terraform
Infrastructure as code with TerraformSam Bashton
 
Enterprise Algebras, Scala World 2016
Enterprise Algebras, Scala World 2016Enterprise Algebras, Scala World 2016
Enterprise Algebras, Scala World 2016Timothy Perrett
 
Automation with Packer and TerraForm
Automation with Packer and TerraFormAutomation with Packer and TerraForm
Automation with Packer and TerraFormWesley Charles Blake
 
Delivering Go.CD with Terraform and Docker
Delivering Go.CD with Terraform and DockerDelivering Go.CD with Terraform and Docker
Delivering Go.CD with Terraform and DockerJorrit Salverda
 
Large-scale Infrastructure Automation at Verizon
Large-scale Infrastructure Automation at VerizonLarge-scale Infrastructure Automation at Verizon
Large-scale Infrastructure Automation at VerizonTimothy Perrett
 
Terraform: An Overview & Introduction
Terraform: An Overview & IntroductionTerraform: An Overview & Introduction
Terraform: An Overview & IntroductionLee Trout
 

Destacado (20)

Terraform
TerraformTerraform
Terraform
 
Scala Helix
Scala HelixScala Helix
Scala Helix
 
Building Enigma with State Monad & Lens
Building Enigma with State Monad & LensBuilding Enigma with State Monad & Lens
Building Enigma with State Monad & Lens
 
Terraform and cloud.ca
Terraform and cloud.caTerraform and cloud.ca
Terraform and cloud.ca
 
Terraform
TerraformTerraform
Terraform
 
Rapid Infrastructure Provisioning
Rapid Infrastructure ProvisioningRapid Infrastructure Provisioning
Rapid Infrastructure Provisioning
 
Terraform
TerraformTerraform
Terraform
 
DevOps - Infrastructure as Code by Andre Marcelo-Tanner
DevOps - Infrastructure as Code by Andre Marcelo-TannerDevOps - Infrastructure as Code by Andre Marcelo-Tanner
DevOps - Infrastructure as Code by Andre Marcelo-Tanner
 
Etcd terraform by Alex Somesan
Etcd terraform by Alex SomesanEtcd terraform by Alex Somesan
Etcd terraform by Alex Somesan
 
2016 - IGNITE - Terraform to go from Zero to Prod in less than 1 month and TH...
2016 - IGNITE - Terraform to go from Zero to Prod in less than 1 month and TH...2016 - IGNITE - Terraform to go from Zero to Prod in less than 1 month and TH...
2016 - IGNITE - Terraform to go from Zero to Prod in less than 1 month and TH...
 
TerraformでECS+ECRする話
TerraformでECS+ECRする話TerraformでECS+ECRする話
TerraformでECS+ECRする話
 
Rediscovering Developer Opportunities in the Philippines by Fred Tshidimba
Rediscovering Developer Opportunities in the Philippines by Fred TshidimbaRediscovering Developer Opportunities in the Philippines by Fred Tshidimba
Rediscovering Developer Opportunities in the Philippines by Fred Tshidimba
 
Jsonnet, terraform & packer
Jsonnet, terraform & packerJsonnet, terraform & packer
Jsonnet, terraform & packer
 
Infrastructure as code with Terraform
Infrastructure as code with TerraformInfrastructure as code with Terraform
Infrastructure as code with Terraform
 
London Hug 19/5 - Terraform in Production
London Hug 19/5 - Terraform in ProductionLondon Hug 19/5 - Terraform in Production
London Hug 19/5 - Terraform in Production
 
Enterprise Algebras, Scala World 2016
Enterprise Algebras, Scala World 2016Enterprise Algebras, Scala World 2016
Enterprise Algebras, Scala World 2016
 
Automation with Packer and TerraForm
Automation with Packer and TerraFormAutomation with Packer and TerraForm
Automation with Packer and TerraForm
 
Delivering Go.CD with Terraform and Docker
Delivering Go.CD with Terraform and DockerDelivering Go.CD with Terraform and Docker
Delivering Go.CD with Terraform and Docker
 
Large-scale Infrastructure Automation at Verizon
Large-scale Infrastructure Automation at VerizonLarge-scale Infrastructure Automation at Verizon
Large-scale Infrastructure Automation at Verizon
 
Terraform: An Overview & Introduction
Terraform: An Overview & IntroductionTerraform: An Overview & Introduction
Terraform: An Overview & Introduction
 

Similar a Refactoring terraform

How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine YardHow I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine YardSV Ruby on Rails Meetup
 
Workshop Infrastructure as Code - Suestra
Workshop Infrastructure as Code - SuestraWorkshop Infrastructure as Code - Suestra
Workshop Infrastructure as Code - SuestraMario IC
 
Testing servers like software
Testing servers like softwareTesting servers like software
Testing servers like softwarePeter Souter
 
Introduction to Perl
Introduction to PerlIntroduction to Perl
Introduction to Perlworr1244
 
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and MoreAutomated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and MoreC4Media
 
How to test infrastructure code: automated testing for Terraform, Kubernetes,...
How to test infrastructure code: automated testing for Terraform, Kubernetes,...How to test infrastructure code: automated testing for Terraform, Kubernetes,...
How to test infrastructure code: automated testing for Terraform, Kubernetes,...Yevgeniy Brikman
 
fog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloudfog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the CloudWesley Beary
 
PM : code faster
PM : code fasterPM : code faster
PM : code fasterPHPPRO
 
Agiles Peru 2019 - Infrastructure As Code
Agiles Peru 2019 - Infrastructure As CodeAgiles Peru 2019 - Infrastructure As Code
Agiles Peru 2019 - Infrastructure As CodeMario IC
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Michelangelo van Dam
 
Can you upgrade to Puppet 4.x?
Can you upgrade to Puppet 4.x?Can you upgrade to Puppet 4.x?
Can you upgrade to Puppet 4.x?Martin Alfke
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)Wesley Beary
 
Chef Fundamentals Training Series Module 3: Setting up Nodes and Cookbook Aut...
Chef Fundamentals Training Series Module 3: Setting up Nodes and Cookbook Aut...Chef Fundamentals Training Series Module 3: Setting up Nodes and Cookbook Aut...
Chef Fundamentals Training Series Module 3: Setting up Nodes and Cookbook Aut...Chef Software, Inc.
 
Úvod do programování 5
Úvod do programování 5Úvod do programování 5
Úvod do programování 5Karel Minarik
 
EC2 AMI Factory with Chef, Berkshelf, and Packer
EC2 AMI Factory with Chef, Berkshelf, and PackerEC2 AMI Factory with Chef, Berkshelf, and Packer
EC2 AMI Factory with Chef, Berkshelf, and PackerGeorge Miranda
 
Common configuration with Data Bags - Fundamentals Webinar Series Part 4
Common configuration with Data Bags - Fundamentals Webinar Series Part 4Common configuration with Data Bags - Fundamentals Webinar Series Part 4
Common configuration with Data Bags - Fundamentals Webinar Series Part 4Chef
 
Przemysław Iwanek - ABC AWS, budowanie infrastruktury przy pomocy Terraform
Przemysław Iwanek - ABC AWS, budowanie infrastruktury przy pomocy TerraformPrzemysław Iwanek - ABC AWS, budowanie infrastruktury przy pomocy Terraform
Przemysław Iwanek - ABC AWS, budowanie infrastruktury przy pomocy Terraformjzielinski_pl
 

Similar a Refactoring terraform (20)

Refactoring Infrastructure Code
Refactoring Infrastructure CodeRefactoring Infrastructure Code
Refactoring Infrastructure Code
 
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine YardHow I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
 
Workshop Infrastructure as Code - Suestra
Workshop Infrastructure as Code - SuestraWorkshop Infrastructure as Code - Suestra
Workshop Infrastructure as Code - Suestra
 
Testing servers like software
Testing servers like softwareTesting servers like software
Testing servers like software
 
Introduction to Perl
Introduction to PerlIntroduction to Perl
Introduction to Perl
 
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and MoreAutomated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
 
How to test infrastructure code: automated testing for Terraform, Kubernetes,...
How to test infrastructure code: automated testing for Terraform, Kubernetes,...How to test infrastructure code: automated testing for Terraform, Kubernetes,...
How to test infrastructure code: automated testing for Terraform, Kubernetes,...
 
fog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloudfog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloud
 
PM : code faster
PM : code fasterPM : code faster
PM : code faster
 
Agiles Peru 2019 - Infrastructure As Code
Agiles Peru 2019 - Infrastructure As CodeAgiles Peru 2019 - Infrastructure As Code
Agiles Peru 2019 - Infrastructure As Code
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012
 
Can you upgrade to Puppet 4.x?
Can you upgrade to Puppet 4.x?Can you upgrade to Puppet 4.x?
Can you upgrade to Puppet 4.x?
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
 
Chef Fundamentals Training Series Module 3: Setting up Nodes and Cookbook Aut...
Chef Fundamentals Training Series Module 3: Setting up Nodes and Cookbook Aut...Chef Fundamentals Training Series Module 3: Setting up Nodes and Cookbook Aut...
Chef Fundamentals Training Series Module 3: Setting up Nodes and Cookbook Aut...
 
Úvod do programování 5
Úvod do programování 5Úvod do programování 5
Úvod do programování 5
 
EC2 AMI Factory with Chef, Berkshelf, and Packer
EC2 AMI Factory with Chef, Berkshelf, and PackerEC2 AMI Factory with Chef, Berkshelf, and Packer
EC2 AMI Factory with Chef, Berkshelf, and Packer
 
Revoke-Obfuscation
Revoke-ObfuscationRevoke-Obfuscation
Revoke-Obfuscation
 
Common configuration with Data Bags - Fundamentals Webinar Series Part 4
Common configuration with Data Bags - Fundamentals Webinar Series Part 4Common configuration with Data Bags - Fundamentals Webinar Series Part 4
Common configuration with Data Bags - Fundamentals Webinar Series Part 4
 
CakePHP
CakePHPCakePHP
CakePHP
 
Przemysław Iwanek - ABC AWS, budowanie infrastruktury przy pomocy Terraform
Przemysław Iwanek - ABC AWS, budowanie infrastruktury przy pomocy TerraformPrzemysław Iwanek - ABC AWS, budowanie infrastruktury przy pomocy Terraform
Przemysław Iwanek - ABC AWS, budowanie infrastruktury przy pomocy Terraform
 

Más de Nell Shamrell-Harrington

This Week in Rust: 400 Issues and Counting!
This Week in Rust: 400 Issues and Counting!This Week in Rust: 400 Issues and Counting!
This Week in Rust: 400 Issues and Counting!Nell Shamrell-Harrington
 
Higher. Faster. Stronger. Your Applications with Habitat
Higher. Faster. Stronger. Your Applications with HabitatHigher. Faster. Stronger. Your Applications with Habitat
Higher. Faster. Stronger. Your Applications with HabitatNell Shamrell-Harrington
 
Containers, Virtual Machines, and Bare Metal, Oh My!
Containers, Virtual Machines, and Bare Metal, Oh My!Containers, Virtual Machines, and Bare Metal, Oh My!
Containers, Virtual Machines, and Bare Metal, Oh My!Nell Shamrell-Harrington
 
Creating Packages that Run Anywhere with Chef Habitat
Creating Packages that Run Anywhere with Chef HabitatCreating Packages that Run Anywhere with Chef Habitat
Creating Packages that Run Anywhere with Chef HabitatNell Shamrell-Harrington
 
First Do No Harm: Surgical Refactoring (extended edition)
First Do No Harm: Surgical Refactoring (extended edition)First Do No Harm: Surgical Refactoring (extended edition)
First Do No Harm: Surgical Refactoring (extended edition)Nell Shamrell-Harrington
 
A Supermarket of Your Own: Running a Private Chef Supermarket
A Supermarket of Your Own: Running a Private Chef SupermarketA Supermarket of Your Own: Running a Private Chef Supermarket
A Supermarket of Your Own: Running a Private Chef SupermarketNell Shamrell-Harrington
 
Beneath the Surface: Regular Expressions in Ruby
Beneath the Surface: Regular Expressions in RubyBeneath the Surface: Regular Expressions in Ruby
Beneath the Surface: Regular Expressions in RubyNell Shamrell-Harrington
 

Más de Nell Shamrell-Harrington (20)

This Week in Rust: 400 Issues and Counting!
This Week in Rust: 400 Issues and Counting!This Week in Rust: 400 Issues and Counting!
This Week in Rust: 400 Issues and Counting!
 
The Rust Borrow Checker
The Rust Borrow CheckerThe Rust Borrow Checker
The Rust Borrow Checker
 
Higher. Faster. Stronger. Your Applications with Habitat
Higher. Faster. Stronger. Your Applications with HabitatHigher. Faster. Stronger. Your Applications with Habitat
Higher. Faster. Stronger. Your Applications with Habitat
 
Habitat Service Discovery
Habitat Service DiscoveryHabitat Service Discovery
Habitat Service Discovery
 
Web Operations101
Web Operations101Web Operations101
Web Operations101
 
Rust Traits And You: A Deep Dive
Rust Traits And You: A Deep DiveRust Traits And You: A Deep Dive
Rust Traits And You: A Deep Dive
 
Rust, Redis, and Protobuf - Oh My!
Rust, Redis, and Protobuf - Oh My!Rust, Redis, and Protobuf - Oh My!
Rust, Redis, and Protobuf - Oh My!
 
Containers, Virtual Machines, and Bare Metal, Oh My!
Containers, Virtual Machines, and Bare Metal, Oh My!Containers, Virtual Machines, and Bare Metal, Oh My!
Containers, Virtual Machines, and Bare Metal, Oh My!
 
Chef Vault: A Deep Dive
Chef Vault: A Deep DiveChef Vault: A Deep Dive
Chef Vault: A Deep Dive
 
Open Source Governance 101
Open Source Governance 101Open Source Governance 101
Open Source Governance 101
 
DevOps in Politics
DevOps in PoliticsDevOps in Politics
DevOps in Politics
 
Open Source Governance - The Hard Parts
Open Source Governance - The Hard PartsOpen Source Governance - The Hard Parts
Open Source Governance - The Hard Parts
 
Creating Packages that Run Anywhere with Chef Habitat
Creating Packages that Run Anywhere with Chef HabitatCreating Packages that Run Anywhere with Chef Habitat
Creating Packages that Run Anywhere with Chef Habitat
 
Devops: A History
Devops: A HistoryDevops: A History
Devops: A History
 
First Do No Harm: Surgical Refactoring (extended edition)
First Do No Harm: Surgical Refactoring (extended edition)First Do No Harm: Surgical Refactoring (extended edition)
First Do No Harm: Surgical Refactoring (extended edition)
 
First Do No Harm: Surgical Refactoring
First Do No Harm: Surgical RefactoringFirst Do No Harm: Surgical Refactoring
First Do No Harm: Surgical Refactoring
 
A Supermarket of Your Own: Running a Private Chef Supermarket
A Supermarket of Your Own: Running a Private Chef SupermarketA Supermarket of Your Own: Running a Private Chef Supermarket
A Supermarket of Your Own: Running a Private Chef Supermarket
 
Public Supermarket: The Insider's Tour
Public Supermarket: The Insider's TourPublic Supermarket: The Insider's Tour
Public Supermarket: The Insider's Tour
 
Beneath the Surface - Rubyconf 2013
Beneath the Surface - Rubyconf 2013Beneath the Surface - Rubyconf 2013
Beneath the Surface - Rubyconf 2013
 
Beneath the Surface: Regular Expressions in Ruby
Beneath the Surface: Regular Expressions in RubyBeneath the Surface: Regular Expressions in Ruby
Beneath the Surface: Regular Expressions in Ruby
 

Último

Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityIES VE
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPathCommunity
 
Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Farhan Tariq
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observabilityitnewsafrica
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Alkin Tezuysal
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...itnewsafrica
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...itnewsafrica
 
Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Kaya Weers
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfIngrid Airi González
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterMydbops
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch TuesdayIvanti
 
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesMuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesManik S Magar
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfpanagenda
 

Último (20)

Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a reality
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to Hero
 
Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...
 
Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdf
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL Router
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch Tuesday
 
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesMuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
 

Refactoring terraform

  • 2. Who Am I? Nell Shamrell-Harrington • Software Engineer at Chef • @nellshamrell • nshamrell@chef.io
  • 3. Let’s talk about Terraform!
  • 5. • Add a feature • Fix a bug Why Refactor?
  • 6. • Add a feature • Fix a bug • Improve the design Why Refactor?
  • 7. • Add a feature • Fix a bug • Improve the design • Optimize resource usage Why Refactor?
  • 9. Today, we will refactor supermarket-terraform http://github.com/nellshamrell/supermarket-terraform supermarket-terraform
  • 10. supermarket-cluster.tf provider  “aws”  {      access_key  =  “${var.access_key}”      secret_key  =  “${var.secret_key}”   } supermarket-terraform
  • 11. supermarket-cluster.tf provider  “aws”  {      access_key  =  “${var.access_key}”      secret_key  =  “${var.secret_key}”   } supermarket-terraform
  • 12. supermarket-cluster.tf variables.tf provider  “aws”  {      access_key  =  “${var.access_key}”      secret_key  =  “${var.secret_key}”   } variable  “access_key”  =  {}     variable  “secret_key”  =  {} supermarket-terraform
  • 13. supermarket-cluster.tf variables.tf terraform.tfvars provider  “aws”  {      access_key  =  “${var.access_key}”      secret_key  =  “${var.secret_key}”   } variable  “access_key”  =  {}     variable  “secret_key”  =  {} access_key  =  “xxxxx”     secret_key  =  “xxxxx” supermarket-terraform
  • 14. Wait…should you use a credentials file?
  • 15. You can…but for the sake of the example, let’s supply them inline
  • 16. supermarket-cluster.tf provider  “aws”  {      access_key  =  “${var.access_key}”      secret_key  =  “${var.secret_key}”   } supermarket-terraform
  • 19. Security Group Allow SSH $ terraform apply supermarket-cluster.tf
  • 21. Security Group Security Group Allow SSH Allow Out $ terraform apply supermarket-cluster.tf
  • 22. Security Group Security Group EC2 Allow SSH Allow Out $ terraform apply supermarket-cluster.tf
  • 23. Security Group Security Group EC2 Chef Server Allow SSH Allow Out $ terraform apply supermarket-cluster.tf
  • 24. EC2 Security Group Security Group EC2 Chef Server Allow OutAllow SSH $ terraform apply supermarket-cluster.tf
  • 25. EC2 Security Group Security Group EC2 Chef Server Supermarket Allow OutAllow SSH $ terraform apply supermarket-cluster.tf
  • 26. EC2 Security Group Security Group EC2 Chef Server Supermarket Allow OutAllow SSH $ terraform apply supermarket-cluster.tf
  • 27. EC2 Security Group Security Group EC2 Chef Server Supermarket Allow OutAllow SSH $ terraform apply supermarket-cluster.tf
  • 28. EC2 Security Group Security Group EC2 Chef Server Supermarket Allow OutAllow SSH $ terraform apply supermarket-cluster.tf
  • 29. EC2 Security Group Security Group EC2 Chef Server Supermarket Allow OutAllow SSH $ terraform apply supermarket-cluster.tf
  • 30. Hypothetical: We are using too many AWS Security Groups Why Refactor?
  • 31. We need this config to create only one security group Why Refactor?
  • 32. Source: Working Effectively with Legacy Code How to Refactor? Two Approaches
  • 33. Source: Working Effectively with Legacy Code How to Refactor? • Edit and Pray Two Approaches
  • 34. • Edit and Pray • Cover and Modify Two Approaches Source: Working Effectively with Legacy Code How to Refactor?
  • 35. Confidence in code without tests is false confidence
  • 36. What code is intended to do is much less important than what it actually does
  • 37. Do I have to add tests for the entire thing?
  • 38. No.
  • 39. The point of adding tests is to not make things worse
  • 40. And to start making the code better here and now
  • 41. How can we test Terraform?
  • 42. How Can We Test Terraform? • Test Kitchen (http://kitchen.ci)
  • 43. How Can We Test Terraform? • Test Kitchen (http://kitchen.ci) • Kitchen Terraform (http://github.com/newcontext/ kitchen-terraform)
  • 44. driver:      name:  terraform   provisioner:      name:  terraform      variable_files:  terraform.@vars   transport:        name:  ssh      ssh_key:  ~/path/to/your/aws/key   pla@orms:      -­‐  name:  ubuntu   suites      -­‐  name:  default   .kitchen.yml
  • 45. driver:      name:  terraform   provisioner:      name:  terraform      variable_files:  terraform.@vars   transport:        name:  ssh      ssh_key:  ~/path/to/your/aws/key   pla@orms:      -­‐  name:  ubuntu   suites      -­‐  name:  default   .kitchen.yml
  • 46. driver:      name:  terraform   provisioner:      name:  terraform      variable_files:  terraform.5vars   transport:        name:  ssh      ssh_key:  ~/path/to/your/aws/key   pla@orms:      -­‐  name:  ubuntu   suites      -­‐  name:  default   .kitchen.yml
  • 47. driver:      name:  terraform   provisioner:      name:  terraform      variable_files:  terraform.5vars   transport:        name:  ssh      ssh_key:  ~/path/to/your/aws/key   pla@orms:      -­‐  name:  ubuntu   suites      -­‐  name:  default   .kitchen.yml
  • 48. driver:      name:  terraform   provisioner:      name:  terraform      variable_files:  terraform.@vars   transport:        name:  ssh      ssh_key:  ~/path/to/your/aws/key   pla@orms:      -­‐  name:  ubuntu   suites      -­‐  name:  default   .kitchen.yml
  • 49. .kitchen.yml driver:      name:  terraform   provisioner:      name:  terraform      variable_files:  terraform.@vars   transport:        name:  ssh      ssh_key:  ~/path/to/your/aws/key   pla5orms:      -­‐  name:  ubuntu   suites      -­‐  name:  default   Test Kitchen Boilerplate
  • 50. • Test Kitchen (http://kitchen.ci) • Kitchen Terraform (http://github.com/newcontext/ kitchen-terraform) • Inspec (http://chef.io/inspec) How Can We Test Terraform?
  • 51. Now that we have our tools…
  • 52. Let’s start from a clean slate
  • 53. #provider  “aws”  {   #    access_key  =  “${var.access_key}”   #    secret_key  =  “${var.secret_key}”   #    region  =  “${var.region}”   #}   #resource  “aws_security_group”  “allow-­‐ssh”  {   #    name  =  “${var.user_name}-­‐allow-­‐ssh”   #    tags  =  {   #        Name  =  “${var.user_name}  Allow  All  SSH”   #    }   … supermarket-cluster.tf
  • 55. $ terraform apply Nothing happens! supermarket-cluster.tf
  • 56. First, we need the provider
  • 57. provider  “aws”  {      access_key  =  “${var.access_key}”      secret_key  =  “${var.secret_key}”      region  =  “${var.region}”   }   #resource  “aws_security_group”  “allow-­‐ssh”  {   #    name  =  “${var.user_name}-­‐allow-­‐ssh”   #    tags  =  {   #        Name  =  “${var.user_name}  Allow  All  SSH”   #    }   … supermarket-cluster.tf
  • 58. We also need actual AWS instances
  • 60. …   #resource  “aws_instance”  “chef_server”  {   #    ami  =  “${var.ami}”   #    instance_type  =  “${var.instance_type}”   #    key_name  =  “${var.key_name}”   #    tags  {   #        Name  =  “dev-­‐chef-­‐server”   #    }   #    security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”,   #                                                                        “${aws_security_group.allow-­‐out.name}”]   #    (…)   #}   … This is the Chef Server supermarket-cluster.tf
  • 61. …   resource  “aws_instance”  “chef_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐chef-­‐server”      }      security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”,                                                                          “${aws_security_group.allow-­‐out.name}”]      (…)   }   … This is the Chef Server supermarket-cluster.tf
  • 63. EC2 Chef Server $ terraform apply supermarket-cluster.tf
  • 65. …   #resource  “aws_instance”  “supermarket_server”  {   #    ami  =  “${var.ami}”   #    instance_type  =  “${var.instance_type}”   #    key_name  =  “${var.key_name}”   #    tags  {   #        Name  =  “dev-­‐supermarket-­‐server”   #    }   #    security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”,   #                                                                        “${aws_security_group.allow-­‐out.name}”]   #    (…)   #}   … This is the Supermarket Server supermarket-cluster.tf
  • 66. …   resource  “aws_instance”  “supermarket_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐supermarket-­‐server”      }      security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”,                                                                          “${aws_security_group.allow-­‐out.name}”]      (…)   }   … This is the Supermarket Server supermarket-cluster.tf
  • 67. EC2 Chef Server $ terraform apply EC2 Supermarket supermarket-cluster.tf
  • 68. We also need at least one security group
  • 69. #resource  “aws_security_group”  “allow-­‐ssh”  {   #    name  =  “${var.user_name}-­‐allow-­‐ssh”   #    tags  =  {   #        Name  =  “${var.user_name}  Allow  all  ssh”   #    }   #}   #resource  “aws_security_group_rule”  “allow-­‐ssh”  {   #    type  =  “ingress”   #    from_port  =  22   #    to_port  =  22      …   #} supermarket-cluster.tf
  • 70. resource  “aws_security_group”  “allow-­‐ssh”  {      name  =  “${var.user_name}-­‐allow-­‐ssh”      tags  =  {          Name  =  “${var.user_name}  Allow  all  ssh”      }   }   #resource  “aws_security_group_rule”  “allow-­‐ssh”  {   #    type  =  “ingress”   #    from_port  =  22   #    to_port  =  22      …   #} supermarket-cluster.tf
  • 71. EC2 Chef Server supermarket-cluster.tf $ terraform apply EC2 Supermarket Security Group
  • 72. kitchen-terraform needs to be able to ssh into our instances
  • 73. We need a security group rule
  • 74. resource  “aws_security_group”  “allow-­‐ssh”  {      name  =  “${var.user_name}-­‐allow-­‐ssh”      tags  =  {          Name  =  “${var.user_name}  Allow  all  ssh”      }   }   #resource  “aws_security_group_rule”  “allow-­‐ssh”  {   #  type  =  “ingress”   #  from_port  =  22   #  to_port  =  22      …   #} supermarket-cluster.tf
  • 75. resource  “aws_security_group”  “allow-­‐ssh”  {      name  =  “${var.user_name}-­‐allow-­‐ssh”      tags  =  {          Name  =  “${var.user_name}  Allow  all  ssh”      }   }   resource  “aws_security_group_rule”  “allow-­‐ssh”  {    type  =  “ingress”    from_port  =  22    to_port  =  22      …   } supermarket-cluster.tf
  • 76. EC2 Chef Server $ terraform apply EC2 Supermarket Security Group Allow SSH supermarket-cluster.tf
  • 77. Now, let’s create our test cluster
  • 79. Like running terraform apply $ kitchen converge
  • 80. $ kitchen converge (…) >>>>>> ------Exception------- >>>>>> Class: Kitchen::ActionFailed >>>>>> Message: 1 actions failed. >>>>>> Converge failed on instance <default-ubuntu>. >>>>>> Please see .kitchen/logs/kitchen.log for more details
  • 81. -­‐-­‐-­‐-­‐  Begin  output  of  terraform  validate    /root/supermarket-­‐terraform-­‐2  -­‐-­‐-­‐-­‐   STDOUT:   STDERR:  ^[[31mError  validaWng:  2  error(s)  occurred:   * resource  'aws_instance.chef_server'  config:  unknown  resource     * 'aws_security_group.allow-­‐egress'  referenced  in     * variable  aws_security_group.allow-­‐egress.name   * resource  'aws_instance.supermarket_server'  config:     * unknown  resource  'aws_security_group.allow-­‐egress'     * referenced  in  variable  aws_security_group.allow-­‐egress.   * name .kitchen/logs/default-ubuntu.log
  • 82. We need our EC2 resources to reference only one security group
  • 83. Let’s look at the Chef Server
  • 84. …   resource  “aws_instance”  “chef_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐chef-­‐server”      }      security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”,                                                                          “${aws_security_group.allow-­‐out.name}”]      (…)   }   … This is the Chef Server supermarket-cluster.tf
  • 85. …   resource  “aws_instance”  “chef_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐chef-­‐server”      }        security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”]      (…)   }   … This is the Chef Server supermarket-cluster.tf
  • 87. …   resource  “aws_instance”  “supermarket_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐supermarket-­‐server”      }      security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”,                                                                          “${aws_security_group.allow-­‐out.name}”]      (…)   }   … This is the Supermarket Server supermarket-cluster.tf
  • 88. …   resource  “aws_instance”  “supermarket_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐supermarket-­‐server”      }      security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”          (…)   }   … This is the Supermarket Server supermarket-cluster.tf
  • 89. $ kitchen converge$ kitchen converge
  • 90. $ kitchen converge Apply complete! Resources: 2 added, 0 changed, 0 destroyed. (…) Finished converging <default-ubuntu> (0m7.10s).
  • 94. driver:      name:  terraform      (…)   verifier:      name:  terraform      format:  doc      groups:      -­‐  name:  default          tests:                -­‐  security_groups          hostnames:  aws_hostnames          username:  ubuntu .kitchen.yml
  • 95. driver:      name:  terraform      (…)   verifier:      name:  terraform      format:  doc      groups:      -­‐  name:  default          tests:                -­‐  security_groups          hostnames:  aws_hostnames          username:  ubuntu .kitchen.yml
  • 96. driver:      name:  terraform      (…)   verifier:      name:  terraform      format:  doc      groups:      -­‐  name:  default          tests:                -­‐  security_groups          hostnames:  aws_hostnames          username:  ubuntu .kitchen.yml
  • 97. driver:      name:  terraform      (…)   verifier:      name:  terraform      format:  doc      groups:      -­‐  name:  default          tests:                -­‐  security_groups          hostnames:  aws_hostnames          username:  ubuntu .kitchen.yml
  • 98. Output variable driver:      name:  terraform      (…)   verifier:      name:  terraform      format:  doc      groups:      -­‐  name:  default          tests:                -­‐  security_groups          hostnames:  aws_hostnames          username:  ubuntu .kitchen.yml
  • 99. We need to create that output variable
  • 101. output  “aws_hostnames”  {      value  =  “${aws_instance.chef_server.public_dns},                                      ${aws_instance.supermarket_server.public_dns}”   } outputs.tf
  • 102. output  “aws_hostnames”  {      value  =  “${aws_instance.chef_server.public_dns},                                      ${aws_instance.supermarket_server.public_dns}”   } outputs.tf
  • 104. Spins up AWS resources Captures public_dns of EC2 instances in aws_hostnames Using Outputs
  • 105. Spins up AWS resources Passes to kitchen-terraform Captures public_dns of EC2 instances in aws_hostnames Using Outputs
  • 106. Spins up AWS resources Captures public_dns of EC2 instances in aws_hostnames Passes to kitchen-terraform kitchen-terraform uses aws_hostnames to ssh into the instances Using Outputs
  • 107. Spins up AWS resources Runs Tests kitchen-terraform uses aws_hostnames to ssh into the instances Captures public_dns of EC2 instances in aws_hostnames Passes to kitchen-terraform Using Outputs
  • 108. $ kitchen destroy$ kitchen destroy
  • 109. $ kitchen destroy $ kitchen converge $ kitchen destroy $ kitchen converge
  • 110. #resource  “aws_security_group”  “allow-­‐egress”  {   #    name  =  “${var.user_name}-­‐allow-­‐egress”   #    tags  =  {   #        Name  =  “${var.user_name}  Allow  connecLons  out”   #    }   #}   #resource  “aws_security_group_rule”  “allow-­‐out”  {   #  type  =  “egress”   #  from_port  =  0   #  to_port  =  65535   #  cidr_blocks  =  ["0.0.0.0/0"]      … supermarket-cluster.tf
  • 112. describe  command(‘ping  -­‐c  1  google.com’)  do       end security_groups_spec.rb
  • 113. describe  command(‘ping  -­‐c  1  google.com’)  do      its(‘stdout’)  {  should  match  /1  packets  transmiSed,  1  received/  }   end security_groups_spec.rb
  • 114. $ kitchen verify$ kitchen verify
  • 115. $ kitchen verify Failure/Error: expected "PING google.com (216.58.218.238) 56(84) bytes of data.nn--- google.com ping statistics —n 1 packets transmitted, 0 received, to match /1 packets transmitted, 1 received/ Diff: @@ -1,2 +1,5 @@ -/1 packets transmitted, 1 received/
  • 116. Good! We have a failure!
  • 117. Now let’s make it pass
  • 118. #resource  “aws_security_group”  “allow-­‐egress”  {   #    name  =  “${var.user_name}-­‐allow-­‐egress”   #    tags  =  {   #        Name  =  “${var.user_name}  Allow  connecLons  out”   #    }   #}   #resource  “aws_security_group_rule”  “allow-­‐out”  {   #  type  =  “egress”   #  from_port  =  0   #  to_port  =  65535   #  cidr_blocks  =  ["0.0.0.0/0"]      … supermarket-cluster.tf
  • 119. resource  “aws_security_group”  “allow-­‐egress”  {      name  =  “${var.user_name}-­‐allow-­‐egress”      tags  =  {          Name  =  “${var.user_name}  Allow  connecTons  out”      }   }   resource  “aws_security_group_rule”  “allow-­‐out”  {    type  =  “egress”    from_port  =  0    to_port  =  65535    cidr_blocks  =  ["0.0.0.0/0"]      …   supermarket-cluster.tf
  • 120. EC2 Chef Server $ terraform apply EC2 Supermarket Security Group Allow SSH Security Group Allow Out supermarket-cluster.tf
  • 121. Now let’s call this security group from our Chef Server
  • 122. …   resource  “aws_instance”  “chef_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐chef-­‐server”      }          security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”]      (…)   }   … This is the Chef Server supermarket-cluster.tf
  • 123. …   resource  “aws_instance”  “chef_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐chef-­‐server”      }          security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”,                                                                          “${aws_security_group.allow-­‐out.name}”]      (…)   }   … This is the Chef Server supermarket-cluster.tf
  • 125. …   resource  “aws_instance”  “supermarket_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐supermarket-­‐server”      }      security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”          (…)   }   … This is the Supermarket Server supermarket-cluster.tf
  • 126. …   resource  “aws_instance”  “supermarket_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐supermarket-­‐server”      }      security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”,                                                                          “${aws_security_group.allow-­‐out.name}”]      (…)   }   … This is the Supermarket Server supermarket-cluster.tf
  • 127. $ kitchen destroy $ kitchen converge $ kitchen destroy $ kitchen converge
  • 128. $ kitchen destroy $ kitchen converge $ kitchen verify
  • 129. $ kitchen verify$ kitchen verify$ kitchen verify Command ping -c 1 google.com stdout should match /1 packets transmitted, 1 received/ 1 example, 0 failures
  • 130. It passes! Now let’s make a change
  • 131. Let’s condense the two security groups into one security group
  • 132. resource  “aws_security_group”  “allow-­‐egress”  {      name  =  “${var.user_name}-­‐allow-­‐egress”      tags  =  {          Name  =  “${var.user_name}  Allow  connecWons  out”      }   }   resource  “aws_security_group_rule”  “allow-­‐out”  {    type  =  “egress”    from_port  =  0    to_port  =  65535    cidr_blocks  =  ["0.0.0.0/0"]      …   supermarket-cluster.tf
  • 133. resource  “aws_security_group_rule”  “allow-­‐out”  {    type  =  “egress”    from_port  =  0    to_port  =  65535    cidr_blocks  =  ["0.0.0.0/0"]    security_group_id  “${aws_security_group.allow-­‐egress.id}”   } supermarket-cluster.tf
  • 134. resource  “aws_security_group_rule”  “allow-­‐out”  {    type  =  “egress”    from_port  =  0    to_port  =  65535    cidr_blocks  =  ["0.0.0.0/0"]    security_group_id  “${aws_security_group.allow-­‐ssh.id}”   } supermarket-cluster.tf
  • 135. Now our instances should only use the one security group
  • 136. …   resource  “aws_instance”  “chef_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐chef-­‐server”      }      security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”,                                                                          “${aws_security_group.allow-­‐out.name}”]      (…)   }   … This is the Chef Server supermarket-cluster.tf
  • 137. …   resource  “aws_instance”  “chef_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐chef-­‐server”      }      security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”]                                                                          (…)   }   … This is the Chef Server supermarket-cluster.tf
  • 138. …   resource  “aws_instance”  “supermarket_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐supermarket-­‐server”      }      security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”,                                                                          “${aws_security_group.allow-­‐out.name}”]        (…)   }   … This is the Supermarket Server supermarket-cluster.tf
  • 139. …   resource  “aws_instance”  “supermarket_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐supermarket-­‐server”      }      security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”]      (…)   }   … This is the Supermarket Server supermarket-cluster.tf
  • 140. EC2 Chef Server $ terraform apply EC2 Supermarket Security Group Allow SSH Allow Out supermarket-cluster.tf
  • 141. $ kitchen destroy $ kitchen converge
  • 142. $ kitchen destroy $ kitchen converge $ kitchen verify
  • 143. $ kitchen verify$ kitchen verify Command ping -c 1 google.com stdout should match /1 packets transmitted, 1 received/ 1 example, 0 failures
  • 144. Now let’s improve the design
  • 145. By moving the security group code into a module
  • 146. Source: Terraform Docs Why Move into a Module? • Self-contained package
  • 147. Source: Terraform Docs Why Move into a Module? • Self-contained package • Reusable component
  • 148. • Self-contained package • Reusable component • Improve organization Source: Terraform Docs Why Move into a Module?
  • 152. resource  “aws_security_group”  “allow-­‐ssh”  {    name  =  “${var.user_name}-­‐allow-­‐ssh”    tags  =  {        Name  =  “${var.user_name}  Allow  All  SSH”    }   resource  “aws_security_group_rule”  “allow-­‐ssh”  {    type  =  “ingress”    from_port  =  22    to_port  =  22      …   } security-groups/main.tf
  • 153. Now we need to connect to the module from main config
  • 154. First, we need to know what variables the module needs passed to it
  • 155. resource  “aws_security_group”  “allow-­‐ssh”  {    name  =  “${var.user_name}-­‐allow-­‐ssh”    tags  =  {        Name  =  “${var.user_name}  Allow  All  SSH”    }   resource  “aws_security_group_rule”  “allow-­‐ssh”  {    type  =  “ingress”    from_port  =  22      …      security_group_id  =  “${aws_security_group.allow-­‐ssh.id}”   } Needs to be passed to the module security-groups/main.tf
  • 156. resource  “aws_security_group”  “allow-­‐ssh”  {    name  =  “${var.user_name}-­‐allow-­‐ssh”    tags  =  {        Name  =  “${var.user_name}  Allow  All  SSH”    }   resource  “aws_security_group_rule”  “allow-­‐ssh”  {    type  =  “ingress”    from_port  =  22      …      security_group_id  =  “${aws_security_group.allow-­‐ssh.id}”   } security-groups/main.tf Thank you, Nikhil Vaze!
  • 157. resource  “aws_security_group”  “allow-­‐ssh”  {    name  =  “${var.user_name}-­‐allow-­‐ssh”    tags  =  {        Name  =  “${var.user_name}  Allow  All  SSH”    }   resource  “aws_security_group_rule”  “allow-­‐ssh”  {    type  =  “ingress”    from_port  =  22      …      security_group_id  =  “${aws_security_group.allow-­‐ssh.id}”   } Does not need to be passed in security-groups/main.tf
  • 165. module  “security-­‐groups”  {      source  =  “./security-­‐groups”      user_name  =  “${var.user_name}”   } supermarket-cluster.tf
  • 166. module  “security-­‐groups”  {      source  =  “./security-­‐groups”      user_name  =  “${var.user_name}”   } supermarket-cluster.tf
  • 168. $ kitchen converge -----> Starting Kitchen (v1.10.2) -----> Converging <default-ubuntu>… (…) >>>>>> ------Exception------- >>>>>> Class: Kitchen::ActionFailed Message: 1 actions failed. >>>>>> Converge failed on instance <default-ubuntu>. Please see .kitchen/logs/default-ubuntu.log for more details
  • 169. $ kitchen converge -----> Starting Kitchen (v1.10.2) -----> Converging <default-ubuntu>… (…) >>>>>> ------Exception------- >>>>>> Class: Kitchen::ActionFailed Message: 1 actions failed. >>>>>> Converge failed on instance <default-ubuntu>. Please see .kitchen/logs/default-ubuntu.log for more details
  • 170. -­‐-­‐-­‐  Begin  output  of  terraform  validate  (…)   STDOUT:   STDERR:  Error  validaWng:  2  error(s)  occurred:   * resource  'aws_instance.supermarket_server'  config:     * unknown  resource  'aws_security_group.allow-­‐ssh'     * referenced  in  variable  aws_security_group.allow-­‐ssh.name   * resource  'aws_instance.chef_server'  config:     * unknown  resource  'aws_security_group.allow-­‐ssh'     * referenced  in  variable  aws_security_group.allow-­‐ssh.name .kitchen/logs/default-ubuntu.log
  • 172. output  “sg-­‐name”  {       } security-groups/output.tf
  • 173. output  “sg-­‐name”  {      value  =  “${aws_security_group.allow-­‐ssh.name}”   } security-groups/output.tf
  • 174. Now, we need to use this output in our supermarket-cluster config
  • 175. …   resource  “aws_instance”  “chef_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐chef-­‐server”      }      security_groups  =  [“${aws_security_group.allow-­‐ssh.name}”]                                                                          (…)   }   … This is the Chef Server supermarket-cluster.tf
  • 176. …   resource  “aws_instance”  “chef_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐chef-­‐server”      }      security_groups  =  [“${module.security-­‐groups.sg-­‐name}”]            (…)   }   … This is the Chef Server supermarket-cluster.tf
  • 177. …   resource  “aws_instance”  “supermarket_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐supermarket-­‐server”      }      security_groups  =  [“${aws_security_group.allow-­‐ssh-­‐name}”]        (…)   }   … This is the Supermarket Server supermarket-cluster.tf
  • 178. …   resource  “aws_instance”  “supermarket_server”  {      ami  =  “${var.ami}”      instance_type  =  “${var.instance_type}”      key_name  =  “${var.key_name}”      tags  {          Name  =  “dev-­‐supermarket-­‐server”      }      security_groups  =  [“${module.security-­‐groups.sg-­‐name}”]          (…)   }   … This is the Supermarket Server supermarket-cluster.tf
  • 180. $ kitchen converge $ kitchen verify
  • 181. $ kitchen verify$ kitchen verify$ kitchen verify Command ping -c 1 google.com stdout should match /1 packets transmitted, 1 received/ 1 example, 0 failures
  • 182. So we have improved our resource usage
  • 185. Infrastructure code must be maintained and refactored just like application code
  • 186. Even more so because infrastructure code involves so many moving pieces
  • 188. And refactor one small piece at a time
  • 190. Who Am I? Nell Shamrell-Harrington • Software Engineer at Chef • @nellshamrell • nshamrell@chef.io
  • 191. Who Am I? Any Questions? Nell Shamrell-Harrington • Software Engineer at Chef • @nellshamrell • nshamrell@chef.io