-
Notifications
You must be signed in to change notification settings - Fork 10
/
terraform_dsl.rb
125 lines (112 loc) · 4.57 KB
/
terraform_dsl.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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: #{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: #{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 "file: #{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