terraform 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.markdown +24 -0
- data/Rakefile +1 -0
- data/lib/terraform.rb +10 -0
- data/lib/terraform/terraform_dsl.rb +125 -0
- data/lib/terraform/version.rb +3 -0
- data/terraform.gemspec +20 -0
- metadata +75 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Terraform is a small goal-oriented DSL for setting up a machine, similar in purpose to Chef and
|
2
|
+
Puppet. Its design is inspired by Babushka, but it's simpler and tailored specifically for provisioning a machine for a webapp.
|
3
|
+
|
4
|
+
Usage
|
5
|
+
-----
|
6
|
+
|
7
|
+
require "terraform_dsl"
|
8
|
+
include TerraformDsl
|
9
|
+
dep "my library" do
|
10
|
+
met? { (check if your dependency is met) }
|
11
|
+
meet { (install your dependency) }
|
12
|
+
end
|
13
|
+
|
14
|
+
A more detailed README is coming shortly.
|
15
|
+
|
16
|
+
Contribute
|
17
|
+
----------
|
18
|
+
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:
|
19
|
+
|
20
|
+
gem "terraform", :path => "~/p/terraform"
|
21
|
+
|
22
|
+
Credits
|
23
|
+
-------
|
24
|
+
Dmac -- thanks for the name!
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/terraform.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require "terraform/version"
|
2
|
+
require "fileutils"
|
3
|
+
|
4
|
+
module Terraform
|
5
|
+
# Writes the terraform_dsl.rb to the given file or directory.
|
6
|
+
def self.write_dsl_file(path)
|
7
|
+
path = File.join(path, "terraform_dsl.rb") if File.directory?(path)
|
8
|
+
FileUtils.cp(File.expand_path(File.join(File.dirname(__FILE__), "terraform/terraform_dsl.rb")), path)
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# This is small goal-oriented DSL for installing system components, similar in purpose to Chef and Puppet.
|
2
|
+
# Its design is inspired by Babushka but it's simpler and tailored specifically for provisioning a machine
|
3
|
+
# for a webapp.
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
#
|
7
|
+
# require "terraform_dsl"
|
8
|
+
# include TerraformDsl
|
9
|
+
# dep "my library" do
|
10
|
+
# met? { (check if your dependency is met) }
|
11
|
+
# meet { (install your dependency) }
|
12
|
+
# end
|
13
|
+
|
14
|
+
require "fileutils"
|
15
|
+
require "digest/md5"
|
16
|
+
|
17
|
+
module TerraformDsl
|
18
|
+
def dep(name)
|
19
|
+
@dependencies ||= []
|
20
|
+
# If a dep gets required or defined twice, only run it once.
|
21
|
+
return if @dependencies.find { |dep| dep[:name] == name }
|
22
|
+
@dependencies.push(@current_dependency = { :name => name })
|
23
|
+
yield
|
24
|
+
end
|
25
|
+
def met?(&block) @current_dependency[:met?] = block end
|
26
|
+
def meet(&block) @current_dependency[:meet] = block end
|
27
|
+
def in_path?(command) `which #{command}`.size > 0 end
|
28
|
+
def fail_and_exit(message) puts message; exit 1 end
|
29
|
+
|
30
|
+
# Runs a command and raises an exception if its exit status was nonzero.
|
31
|
+
# - silent: if false, log the command being run and its stdout. False by default.
|
32
|
+
# - check_exit_code: raises an error if the command had a non-zero exit code. True by default.
|
33
|
+
def shell(command, options = {})
|
34
|
+
silent = (options[:silent] != false)
|
35
|
+
puts command unless silent
|
36
|
+
output = `#{command}`
|
37
|
+
puts output unless output.empty? || silent
|
38
|
+
raise "#{command} had a failure exit status of #{$?.to_i}" unless $?.to_i == 0
|
39
|
+
true
|
40
|
+
end
|
41
|
+
|
42
|
+
def satisfy_dependencies
|
43
|
+
STDOUT.sync = true # Ensure that we flush logging output as we go along.
|
44
|
+
@dependencies.each do |dep|
|
45
|
+
unless dep[:met?].call
|
46
|
+
puts "* Dependency #{dep[:name]} is not met. Meeting it."
|
47
|
+
dep[:meet].call
|
48
|
+
fail_and_exit %Q("met?" for #{dep[:name]} is still false after running "meet".) unless dep[:met?].call
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# These are very common tasks which are needed by almost everyone, and so they're bundled with this DSL.
|
55
|
+
#
|
56
|
+
|
57
|
+
def package_installed?(package) `dpkg -s #{package} 2> /dev/null | grep Status`.match(/\sinstalled/) end
|
58
|
+
def install_package(package)
|
59
|
+
# Specify a noninteractive frontend, so dpkg won't prompt you for info. -q is quiet; -y is "answer yes".
|
60
|
+
shell "sudo DEBIAN_FRONTEND=noninteractive apt-get install -qy #{package}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def ensure_packages(*packages) packages.each { |package| ensure_package(package) } end
|
64
|
+
def ensure_package(package)
|
65
|
+
dep package do
|
66
|
+
met? { package_installed?(package) }
|
67
|
+
meet { install_package(package) }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def gem_installed?(gem) `gem list '#{gem}'`.include?(gem) end
|
72
|
+
|
73
|
+
def ensure_gem(gem)
|
74
|
+
dep gem do
|
75
|
+
met? { gem_installed?(gem) }
|
76
|
+
meet { shell "gem install #{gem} --no-ri --no-rdoc" }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Ensures the file at dest_path is exactly the same as the one in source_path.
|
81
|
+
# Invokes the given block if the file is changed. Use this block to restart a service, for instance.
|
82
|
+
def ensure_file(source_path, dest_path, &on_change)
|
83
|
+
dep dest_path do
|
84
|
+
met? do
|
85
|
+
raise "This file does not exist: #{source_path}" unless File.exists?(source_path)
|
86
|
+
File.exists?(dest_path) && (Digest::MD5.file(source_path) == Digest::MD5.file(dest_path))
|
87
|
+
end
|
88
|
+
meet do
|
89
|
+
FileUtils.cp(source_path, dest_path)
|
90
|
+
on_change.call if on_change
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def ensure_rbenv
|
96
|
+
ensure_package "git-core"
|
97
|
+
dep "rbenv" do
|
98
|
+
met? { in_path?("rbenv") }
|
99
|
+
meet do
|
100
|
+
# These instructions are from https://github.com/sstephenson/rbenv/wiki/Using-rbenv-in-Production
|
101
|
+
shell "wget -q -O - https://raw.github.com/fesplugas/rbenv-installer/master/bin/rbenv-installer | bash"
|
102
|
+
# We need to run rbenv init after install, which adjusts the path. If exec is causing us problems
|
103
|
+
# down the road, we can perhaps simulate running rbenv init without execing.
|
104
|
+
unless ARGV.include?("--forked-after-rbenv") # To guard against an infinite forking loop.
|
105
|
+
exec "bash -c 'source ~/.bashrc; #{$0} --forked-after-rbenv'" # $0 is the current process's name.
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# ruby_version is a rbenv ruby version string like "1.9.2-p290".
|
112
|
+
def ensure_rbenv_ruby(ruby_version)
|
113
|
+
ensure_rbenv
|
114
|
+
ensure_packages "curl", "build-essential", "libxslt1-dev", "libxml2-dev", "libssl-dev"
|
115
|
+
|
116
|
+
dep "rbenv ruby #{ruby_version}" do
|
117
|
+
met? { `which ruby`.include?("rbenv") && `ruby -v`.include?(ruby_version.gsub("-", "")) }
|
118
|
+
meet do
|
119
|
+
puts "Compiling Ruby will take a few minutes."
|
120
|
+
shell "rbenv install #{ruby_version}"
|
121
|
+
shell "rbenv rehash"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
data/terraform.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "terraform/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "terraform"
|
7
|
+
s.version = Terraform::VERSION
|
8
|
+
s.authors = ["Phil Crosby"]
|
9
|
+
s.email = ["phil.crosby@gmail.com"]
|
10
|
+
s.homepage = "http://github.com/philc/terraform"
|
11
|
+
s.summary = %q{Set up a cold, inhospitable system using Terraform.}
|
12
|
+
# s.description = %q{TODO: Write a gem description}
|
13
|
+
|
14
|
+
s.rubyforge_project = "terraform"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: terraform
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Phil Crosby
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-03-24 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description:
|
23
|
+
email:
|
24
|
+
- phil.crosby@gmail.com
|
25
|
+
executables: []
|
26
|
+
|
27
|
+
extensions: []
|
28
|
+
|
29
|
+
extra_rdoc_files: []
|
30
|
+
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
34
|
+
- README.markdown
|
35
|
+
- Rakefile
|
36
|
+
- lib/terraform.rb
|
37
|
+
- lib/terraform/terraform_dsl.rb
|
38
|
+
- lib/terraform/version.rb
|
39
|
+
- terraform.gemspec
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://github.com/philc/terraform
|
42
|
+
licenses: []
|
43
|
+
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
hash: 3
|
55
|
+
segments:
|
56
|
+
- 0
|
57
|
+
version: "0"
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
hash: 3
|
64
|
+
segments:
|
65
|
+
- 0
|
66
|
+
version: "0"
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project: terraform
|
70
|
+
rubygems_version: 1.6.2
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: Set up a cold, inhospitable system using Terraform.
|
74
|
+
test_files: []
|
75
|
+
|