SlideShare ist ein Scribd-Unternehmen logo
1 von 191
Downloaden Sie, um offline zu lesen
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

Weitere ähnliche Inhalte

Was ist angesagt?

"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
 

Was ist angesagt? (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
 

Andere mochten auch

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
 

Andere mochten auch (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
 

Ähnlich wie 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
 

Ähnlich wie 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
 

Mehr von 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
 

Mehr von 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
 

Kürzlich hochgeladen

A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 

Kürzlich hochgeladen (20)

A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 

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