terraform 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|