Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 513c6f9
Showing
8 changed files
with
191 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
*.gem | ||
.bundle | ||
Gemfile.lock | ||
pkg/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
source "http://rubygems.org" | ||
|
||
# Specify your gem's dependencies in terraform.gemspec | ||
gemspec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
Terraform is a small goal-oriented DSL for setting up a machine, similar in purpose to Chef and | ||
Puppet. Its design is inspired by Babushka, but it's simpler and tailored specifically for provisioning a machine for a webapp. | ||
|
||
Usage | ||
----- | ||
|
||
require "terraform_dsl" | ||
include TerraformDsl | ||
dep "my library" do | ||
met? { (check if your dependency is met) } | ||
meet { (install your dependency) } | ||
end | ||
|
||
A more detailed README is coming shortly. | ||
|
||
Contribute | ||
---------- | ||
When editing this gem, to test your changes, you can load your local copy of the gem in your project by using this in your Gemfile: | ||
|
||
gem "terraform", :path => "~/p/terraform" | ||
|
||
Credits | ||
------- | ||
Dmac -- thanks for the name! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
require "bundler/gem_tasks" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
require "terraform/version" | ||
require "fileutils" | ||
|
||
module Terraform | ||
# Writes the terraform_dsl.rb to the given file or directory. | ||
def self.write_dsl_file(path) | ||
path = File.join(path, "terraform_dsl.rb") if File.directory?(path) | ||
FileUtils.cp(File.expand_path(File.join(File.dirname(__FILE__), "terraform/terraform_dsl.rb")), path) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
# This is small goal-oriented DSL for installing system components, similar in purpose to Chef and Puppet. | ||
# Its design is inspired by Babushka but it's simpler and tailored specifically for provisioning a machine | ||
# for a webapp. | ||
# | ||
# Usage: | ||
# | ||
# require "terraform_dsl" | ||
# include TerraformDsl | ||
# dep "my library" do | ||
# met? { (check if your dependency is met) } | ||
# meet { (install your dependency) } | ||
# end | ||
|
||
require "fileutils" | ||
require "digest/md5" | ||
|
||
module TerraformDsl | ||
def dep(name) | ||
@dependencies ||= [] | ||
# If a dep gets required or defined twice, only run it once. | ||
return if @dependencies.find { |dep| dep[:name] == name } | ||
@dependencies.push(@current_dependency = { :name => name }) | ||
yield | ||
end | ||
def met?(&block) @current_dependency[:met?] = block end | ||
def meet(&block) @current_dependency[:meet] = block end | ||
def in_path?(command) `which #{command}`.size > 0 end | ||
def fail_and_exit(message) puts message; exit 1 end | ||
|
||
# Runs a command and raises an exception if its exit status was nonzero. | ||
# - silent: if false, log the command being run and its stdout. False by default. | ||
# - check_exit_code: raises an error if the command had a non-zero exit code. True by default. | ||
def shell(command, options = {}) | ||
silent = (options[:silent] != false) | ||
puts command unless silent | ||
output = `#{command}` | ||
puts output unless output.empty? || silent | ||
raise "#{command} had a failure exit status of #{$?.to_i}" unless $?.to_i == 0 | ||
true | ||
end | ||
|
||
def satisfy_dependencies | ||
STDOUT.sync = true # Ensure that we flush logging output as we go along. | ||
@dependencies.each do |dep| | ||
unless dep[:met?].call | ||
puts "* Dependency #{dep[:name]} is not met. Meeting it." | ||
dep[:meet].call | ||
fail_and_exit %Q("met?" for #{dep[:name]} is still false after running "meet".) unless dep[:met?].call | ||
end | ||
end | ||
end | ||
|
||
# | ||
# These are very common tasks which are needed by almost everyone, and so they're bundled with this DSL. | ||
# | ||
|
||
def package_installed?(package) `dpkg -s #{package} 2> /dev/null | grep Status`.match(/\sinstalled/) end | ||
def install_package(package) | ||
# Specify a noninteractive frontend, so dpkg won't prompt you for info. -q is quiet; -y is "answer yes". | ||
shell "sudo DEBIAN_FRONTEND=noninteractive apt-get install -qy #{package}" | ||
end | ||
|
||
def ensure_packages(*packages) packages.each { |package| ensure_package(package) } end | ||
def ensure_package(package) | ||
dep package do | ||
met? { package_installed?(package) } | ||
meet { install_package(package) } | ||
end | ||
end | ||
|
||
def gem_installed?(gem) `gem list '#{gem}'`.include?(gem) end | ||
|
||
def ensure_gem(gem) | ||
dep gem do | ||
met? { gem_installed?(gem) } | ||
meet { shell "gem install #{gem} --no-ri --no-rdoc" } | ||
end | ||
end | ||
|
||
# Ensures the file at dest_path is exactly the same as the one in source_path. | ||
# Invokes the given block if the file is changed. Use this block to restart a service, for instance. | ||
def ensure_file(source_path, dest_path, &on_change) | ||
dep dest_path do | ||
met? do | ||
raise "This file does not exist: #{source_path}" unless File.exists?(source_path) | ||
File.exists?(dest_path) && (Digest::MD5.file(source_path) == Digest::MD5.file(dest_path)) | ||
end | ||
meet do | ||
FileUtils.cp(source_path, dest_path) | ||
on_change.call if on_change | ||
end | ||
end | ||
end | ||
|
||
def ensure_rbenv | ||
ensure_package "git-core" | ||
dep "rbenv" do | ||
met? { in_path?("rbenv") } | ||
meet do | ||
# These instructions are from https://github.com/sstephenson/rbenv/wiki/Using-rbenv-in-Production | ||
shell "wget -q -O - https://raw.github.com/fesplugas/rbenv-installer/master/bin/rbenv-installer | bash" | ||
# We need to run rbenv init after install, which adjusts the path. If exec is causing us problems | ||
# down the road, we can perhaps simulate running rbenv init without execing. | ||
unless ARGV.include?("--forked-after-rbenv") # To guard against an infinite forking loop. | ||
exec "bash -c 'source ~/.bashrc; #{$0} --forked-after-rbenv'" # $0 is the current process's name. | ||
end | ||
end | ||
end | ||
end | ||
|
||
# ruby_version is a rbenv ruby version string like "1.9.2-p290". | ||
def ensure_rbenv_ruby(ruby_version) | ||
ensure_rbenv | ||
ensure_packages "curl", "build-essential", "libxslt1-dev", "libxml2-dev", "libssl-dev" | ||
|
||
dep "rbenv ruby #{ruby_version}" do | ||
met? { `which ruby`.include?("rbenv") && `ruby -v`.include?(ruby_version.gsub("-", "")) } | ||
meet do | ||
puts "Compiling Ruby will take a few minutes." | ||
shell "rbenv install #{ruby_version}" | ||
shell "rbenv rehash" | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module Terraform | ||
VERSION = "0.0.1" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# -*- encoding: utf-8 -*- | ||
$:.push File.expand_path("../lib", __FILE__) | ||
require "terraform/version" | ||
|
||
Gem::Specification.new do |s| | ||
s.name = "terraform" | ||
s.version = Terraform::VERSION | ||
s.authors = ["Phil Crosby"] | ||
s.email = ["phil.crosby@gmail.com"] | ||
s.homepage = "http://github.com/philc/terraform" | ||
s.summary = %q{Set up a cold, inhospitable system using Terraform.} | ||
# s.description = %q{TODO: Write a gem description} | ||
|
||
s.rubyforge_project = "terraform" | ||
|
||
s.files = `git ls-files`.split("\n") | ||
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") | ||
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } | ||
s.require_paths = ["lib"] | ||
end |