Skip to content
This repository has been archived by the owner on Jun 21, 2022. It is now read-only.

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
vancluever committed Jan 25, 2016
0 parents commit 4faecc9
Show file tree
Hide file tree
Showing 16 changed files with 599 additions and 0 deletions.
23 changes: 23 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/.bundle/
/.yardoc
/Gemfile.lock
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/

# Adding bin and vendor as this should never be vendored in production
/bin/
/vendor/

# Chef stuff
.kitchen/
berks-cookbooks/
Berksfile.lock

# Terraform
.terraform
terraform.tfstate
terraform.tfstate.backup
17 changes: 17 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2016 Chris Marchesi
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

source 'https://rubygems.org'

gemspec
67 changes: 67 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Packer and Terraform Pattern Example

This repository houses a simple application that demonstrates an end-to-end
infrastructure as code pattern using Packer and Terraform.

This repository will serve as the basis for an accompanying article at
http://vancluevertech.com (soon to follow).

## The Components

* A small ruby gem (`vancluever_hello`). This is built using rubygems tasks
using `rake`.
* A Chef recipe designed for deploying the applicatin (`packer_payload`).
This is a single-purpose cookbook that is not intended to be shared in
Supermarket, etc. It's only intended for use with Packer. With that said,
having a cookbook allows you to port this functionality to a general-use
cookbook if necessary - this can then be included from a fresh
`packer_payload` cookbook.
* A packer template located at `packer/ami.json`
* Terraform infrastructure in the `terraform` directory, comprised of a single
template for now, `main.tf`.

You manage all of this with `rake`.

## The `Rakefile`

The `Rakefile` has tasks for managing the full lifecycle from building of the
gem, to AMI, to deployment. The list is below:

```
rake ami # Create an application AMI with Packer
rake berks_cookbooks # Vendors dependent cookbooks in berks-cookbooks (for Packer)
rake build # Build vancluever_hello-0.1.0.gem into the pkg directory
rake clean # Remove any temporary products
rake clobber # Remove any generated files
rake infrastructure # Deploy infrastructure using Terraform
```

In addition to that, the file also has helper functions for looking up
AMI IDs to be used in the build process.

## Using this Repository

To prepare the repository for use, clone it and run

```
bundle install --binstubs --path vendor/bundle
```

You should then be good to start using `bundle exec rake`.

You also need [Packer](https://www.packer.io/) and
[Terraform](https://www.terraform.io/).

Finally, valid AWS credentials will need to be available in your credential
chain, either as environment variables (ie: AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN), or your credentials in your
`~/.aws` directory.

### Environment variables

You can also control the build process through the following environment
variables:

* `DISTRO` To control the Ubuntu distribution to use (default `trusty`).
* `REGION` To control the region to deploy to (default `us-east-1`).
* `TF_CMD` To control the Terrafrom command (default `apply`).
108 changes: 108 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Copyright 2016 Chris Marchesi
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'bundler/gem_tasks'
require 'ubuntu_ami'
require 'vancluever_hello/version'
require 'aws-sdk'
require 'date'

# Return a default distro if not defined
def distro
if ENV.include?('DISTRO')
ENV['DISTRO']
else
'trusty'
end
end

# Return a default region if not defined
def region
if ENV.include?('REGION')
ENV['REGION']
else
'us-east-1'
end
end

# Return a default Terraform command if not defined
def tf_cmd
if ENV.include?('TF_CMD')
ENV['TF_CMD']
else
'apply'
end
end

# Get an ubuntu AMI ID to build off of (for Packer)
def ubuntu_ami_id
Ubuntu.release(distro).amis.find do |ami|
ami.arch == 'amd64' &&
ami.root_store == 'ebs-ssd' &&
ami.region == region
end.name
end

# Timestamp conversion for AMI timestamp.
def rfc3339_to_unix(timestamp)
DateTime.rfc3339(timestamp).to_time.seconds
end

# Get the latest AMI ID that we have built (for Terraform)
def app_ami_id
ec2 = Aws::EC2::Client.new(region: region)
resp = ec2.describe_images(
filters: [
{
name: 'tag:app_name',
values: ['vancluever_hello']
}
]
)
fail 'No built application images found' if resp.images.length < 1
images = resp.images.sort do |a, b|
rfc3339_to_unix(b.creation_date) <=> rfc3339_to_unix(a.creation_date)
end
images[0].image_id
end

# Make sure I don't release/push this to rubygems by mistake
Rake::Task['release'].clear

# Also no system install
Rake::Task['install:local'].clear
Rake::Task['install'].clear

desc 'Vendors dependent cookbooks in berks-cookbooks (for Packer)'
task :berks_cookbooks do
sh 'rm -rf berks-cookbooks'
sh 'berks vendor -b cookbooks/packer_payload/Berksfile'
end

desc 'Create an application AMI with Packer'
task :ami => [:build, :berks_cookbooks] do
sh "DISTRO=#{distro} \
SRC_AMI=#{ubuntu_ami_id} \
SRC_REGION=#{region} \
APP_VERSION=#{VanclueverHello::VERSION} \
packer build packer/ami.json"
end

desc 'Deploy infrastructure using Terraform'
task :infrastructure do
sh "DISTRO=#{distro} \
TF_VAR_ami_id=#{app_ami_id} \
TF_VAR_region=#{region} \
terraform #{tf_cmd} terraform"
end
42 changes: 42 additions & 0 deletions cookbooks/packer_payload/.kitchen.cloud.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright 2016 Chris Marchesi
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

---
driver:
name: ec2

driver_config:
aws_ssh_key_id: chef-kitchen-test-aws
instance_type: t2.medium

transport:
username: <%= ENV['AWS_KITCHEN_USER'] %>

provisioner:
name: chef_zero
data_path: ../../pkg/

platforms:
- name: aws
driver:
image_id: <%= ENV['AWS_KITCHEN_AMI_ID'] %>

suites:
- name: default
run_list:
- recipe[packer_payload::default]
attributes:
packer_payload:
source_path: /tmp/kitchen/data
app_version: <%= ENV['KITCHEN_APP_VERSION'] %>
3 changes: 3 additions & 0 deletions cookbooks/packer_payload/Berksfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
source 'https://supermarket.chef.io/'

metadata
18 changes: 18 additions & 0 deletions cookbooks/packer_payload/attributes/default.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2016 Chris Marchesi
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

default['packer_payload']['source_path'] = '/tmp/gem_pkg'
default['packer_payload']['app_user'] = 'ubuntu'
default['packer_payload']['app_path'] = '/home/ubuntu'
default['packer_payload']['app_version'] = '0.1.0'
18 changes: 18 additions & 0 deletions cookbooks/packer_payload/metadata.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2016 Chris Marchesi
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name 'packer_payload'
depends 'poise-ruby'
depends 'poise-ruby-build'
depends 'poise-service'
31 changes: 31 additions & 0 deletions cookbooks/packer_payload/recipes/default.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright 2016 Chris Marchesi
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

SRC_PATH = node['packer_payload']['source_path']
APP_VERSION = node['packer_payload']['app_version']

ruby_runtime '2.1' do
provider :ruby_build
action :install
end

ruby_gem "#{SRC_PATH}/vancluever_hello-#{APP_VERSION}.gem" do
action :install
end

poise_service 'vancluever_hello' do
command '/opt/ruby_build/builds/2.1/bin/vancluever_hello'
user node['packer_payload']['app_user']
directory node['packer_payload']['app_path']
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require 'serverspec'

set :backend, :exec

describe port(4567) do
it { should be_listening.on('0.0.0.0') }
end
20 changes: 20 additions & 0 deletions exe/vancluever_hello
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env ruby
#
# Copyright 2016 Chris Marchesi
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'vancluever_hello'
require 'socket'

VanclueverHello::Server.run_server
31 changes: 31 additions & 0 deletions lib/vancluever_hello.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright 2016 Chris Marchesi
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'sinatra/base'
require 'socket'

module VanclueverHello
# Run the test server.
class Server < Sinatra::Base
def self.run_server
set :bind, '0.0.0.0'

get '/' do
"Hello from #{Socket.gethostname}!!!"
end

run!
end
end
end
Loading

0 comments on commit 4faecc9

Please sign in to comment.