rivet 1.0.0
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 +2 -0
- data/.travis.yml +9 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +31 -0
- data/LICENSE +202 -0
- data/README.md +128 -0
- data/Rakefile +9 -0
- data/bin/rivet +43 -0
- data/lib/rivet/autoscale.rb +125 -0
- data/lib/rivet/aws_utils.rb +74 -0
- data/lib/rivet/bootstrap.rb +62 -0
- data/lib/rivet/client.rb +29 -0
- data/lib/rivet/deep_merge.rb +27 -0
- data/lib/rivet/launch_config.rb +90 -0
- data/lib/rivet/logger.rb +52 -0
- data/lib/rivet/utils.rb +68 -0
- data/lib/rivet/version.rb +4 -0
- data/lib/rivet.rb +18 -0
- data/rivet.gemspec +31 -0
- data/spec/rivet_bootstrap_spec.rb +69 -0
- data/spec/rivet_launch_config_spec.rb +37 -0
- data/spec/rivet_spec_setup.rb +62 -0
- data/spec/rivet_util_spec.rb +123 -0
- metadata +124 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
module Rivet
|
2
|
+
class Bootstrap
|
3
|
+
TEMPLATE_SUB_DIR = "bootstrap"
|
4
|
+
|
5
|
+
attr_reader :gems, :run_list, :template, :environment
|
6
|
+
attr_reader :template_path, :chef_command, :chef_organization
|
7
|
+
|
8
|
+
def initialize(bootstrap_definition = Hash.new)
|
9
|
+
ivars = [
|
10
|
+
'gems','run_list','template','environment',
|
11
|
+
'config_dir','chef_organization']
|
12
|
+
|
13
|
+
ivars.each do |i|
|
14
|
+
if bootstrap_definition.has_key?(i)
|
15
|
+
instance_variable_set("@#{i}",bootstrap_definition[i])
|
16
|
+
end
|
17
|
+
end unless bootstrap_definition.nil?
|
18
|
+
|
19
|
+
@config_dir ||= "."
|
20
|
+
@template ||= "default.erb"
|
21
|
+
|
22
|
+
set_calculated_attrs
|
23
|
+
end
|
24
|
+
|
25
|
+
def user_data
|
26
|
+
@user_data ||= generate_user_data
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def set_calculated_attrs
|
32
|
+
@template_path = File.join(@config_dir,TEMPLATE_SUB_DIR)
|
33
|
+
@chef_command = "/usr/bin/chef-client -j /etc/chef/first-boot.json -L /root/first_run.log -E #{@environment}"
|
34
|
+
@secret_file = File.join(@config_dir,"encrypted_data_bag_secret_#{@environment}")
|
35
|
+
@validation_key = File.new(File.join(@config_dir,"#{@chef_organization}-validator.pem")).read
|
36
|
+
end
|
37
|
+
|
38
|
+
def generate_user_data
|
39
|
+
config_content = "log_level :info\n"
|
40
|
+
config_content << "log_location STDOUT\n"
|
41
|
+
config_content << "environment #{environment}\n"
|
42
|
+
config_content << "chef_server_url 'https://api.opscode.com/organizations/#{chef_organization}'\n"
|
43
|
+
config_content << "validation_client_name '#{chef_organization}-validator'\n"
|
44
|
+
|
45
|
+
install_gems = String.new
|
46
|
+
|
47
|
+
gems.each do |gem|
|
48
|
+
if gem.size > 1
|
49
|
+
install_gems << "gem install #{gem[0]} -v #{gem[1]} --no-rdoc --no-ri\n"
|
50
|
+
else
|
51
|
+
install_gems << "gem install #{gem[0]} --no-rdoc --no-ri\n"
|
52
|
+
end
|
53
|
+
end unless gems.nil?
|
54
|
+
|
55
|
+
first_boot = { :run_list => @run_list.join(",") }.to_json unless @run_list.nil?
|
56
|
+
|
57
|
+
template = ERB.new File.new(File.join(@template_path,@template)).read
|
58
|
+
template.result(binding)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
data/lib/rivet/client.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rivet
|
2
|
+
class Client
|
3
|
+
def initialize
|
4
|
+
end
|
5
|
+
|
6
|
+
def run(options)
|
7
|
+
AwsUtils.set_aws_credentials(options[:profile])
|
8
|
+
Rivet::Log.level(options[:log_level])
|
9
|
+
Rivet::Utils.ensure_minimum_setup
|
10
|
+
|
11
|
+
group_def = Rivet::Utils.get_definition(options[:group])
|
12
|
+
|
13
|
+
Rivet::Utils.die "The #{options[:group]} definition doesn't exist" unless group_def
|
14
|
+
|
15
|
+
Rivet::Log.info("Checking #{options[:group]} autoscaling definition")
|
16
|
+
autoscale_def = Rivet::Autoscale.new(options[:group],group_def)
|
17
|
+
autoscale_def.show_differences
|
18
|
+
|
19
|
+
if options[:sync]
|
20
|
+
autoscale_def.sync
|
21
|
+
else
|
22
|
+
Rivet::Log.info("use the -s [--sync] flag to sync changes")
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Hash
|
2
|
+
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
3
|
+
#
|
4
|
+
# h1 = { x: { y: [4,5,6] }, z: [7,8,9] }
|
5
|
+
# h2 = { x: { y: [7,8,9] }, z: 'xyz' }
|
6
|
+
#
|
7
|
+
# h1.deep_merge(h2) #=> {x: {y: [7, 8, 9]}, z: "xyz"}
|
8
|
+
# h2.deep_merge(h1) #=> {x: {y: [4, 5, 6]}, z: [7, 8, 9]}
|
9
|
+
# h1.deep_merge(h2) { |key, old, new| Array.wrap(old) + Array.wrap(new) }
|
10
|
+
# #=> {:x=>{:y=>[4, 5, 6, 7, 8, 9]}, :z=>[7, 8, 9, "xyz"]}
|
11
|
+
def deep_merge(other_hash, &block)
|
12
|
+
dup.deep_merge!(other_hash, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Same as +deep_merge+, but modifies +self+.
|
16
|
+
def deep_merge!(other_hash, &block)
|
17
|
+
other_hash.each_pair do |k,v|
|
18
|
+
tv = self[k]
|
19
|
+
if tv.is_a?(Hash) && v.is_a?(Hash)
|
20
|
+
self[k] = tv.deep_merge(v, &block)
|
21
|
+
else
|
22
|
+
self[k] = block && tv ? block.call(k, tv, v) : v
|
23
|
+
end
|
24
|
+
end
|
25
|
+
self
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Rivet
|
2
|
+
class LaunchConfig
|
3
|
+
|
4
|
+
LC_ATTRIBUTES = ['key_name','image_id','instance_type','security_groups','bootstrap']
|
5
|
+
|
6
|
+
LC_ATTRIBUTES.each do |a|
|
7
|
+
attr_reader a.to_sym
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :id_prefix
|
11
|
+
|
12
|
+
def initialize(spec,id_prefix="rivet_")
|
13
|
+
@id_prefix = id_prefix
|
14
|
+
|
15
|
+
LC_ATTRIBUTES.each do |a|
|
16
|
+
|
17
|
+
if respond_to? "normalize_#{a}".to_sym
|
18
|
+
spec[a] = self.send("normalize_#{a.to_sym}",spec[a])
|
19
|
+
end
|
20
|
+
|
21
|
+
instance_variable_set("@#{a}",spec[a])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def user_data
|
26
|
+
@user_data ||= Bootstrap.new(bootstrap).user_data
|
27
|
+
end
|
28
|
+
|
29
|
+
def identity
|
30
|
+
@identity ||= generate_identity
|
31
|
+
end
|
32
|
+
|
33
|
+
def save
|
34
|
+
AwsUtils.verify_security_groups(security_groups)
|
35
|
+
|
36
|
+
lc_collection = AWS::AutoScaling.new().launch_configurations
|
37
|
+
|
38
|
+
if lc_collection[identity].exists?
|
39
|
+
Rivet::Log.info("Launch configuration #{identity} already exists in AWS")
|
40
|
+
else
|
41
|
+
options = { :key_pair => key_name, :security_groups => security_groups, :user_data => user_data}
|
42
|
+
Rivet::Log.info("Saving launch configuration #{identity} to AWS")
|
43
|
+
Rivet::Log.debug("Launch Config options:\n #{options.inspect}")
|
44
|
+
lc_collection.create(identity,image_id,instance_type, options)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
def build_identity_string
|
51
|
+
identity = LC_ATTRIBUTES.inject(String.new) do |accum,attribute|
|
52
|
+
if attribute != 'bootstrap'
|
53
|
+
attr_value = self.send(attribute.to_sym) ? self.send(attribute.to_sym) : "\0"
|
54
|
+
attr_value = attr_value.join("\t") if attr_value.respond_to?(:join)
|
55
|
+
accum << attribute.to_s
|
56
|
+
accum << Base64.encode64(attr_value)
|
57
|
+
else
|
58
|
+
accum << attribute.to_s
|
59
|
+
accum << Base64.encode64(user_data ? user_data : "\0")
|
60
|
+
end
|
61
|
+
accum
|
62
|
+
end
|
63
|
+
identity
|
64
|
+
end
|
65
|
+
|
66
|
+
def generate_identity
|
67
|
+
@id_prefix + Digest::SHA1.hexdigest(build_identity_string)
|
68
|
+
end
|
69
|
+
|
70
|
+
def old_generate_identity
|
71
|
+
identity = LC_ATTRIBUTES.inject({}) do |ident_hash,attribute|
|
72
|
+
if attribute != 'bootstrap'
|
73
|
+
Rivet::Log.debug("Adding #{attribute} : #{self.send(attribute.to_sym)} to identity hash for LaunchConfig")
|
74
|
+
ident_hash[attribute] = self.send(attribute.to_sym)
|
75
|
+
else
|
76
|
+
Rivet::Log.debug("Adding user_data to identity hash for LaunchConfig:\n#{user_data} ")
|
77
|
+
ident_hash[attribute] = user_data
|
78
|
+
end
|
79
|
+
ident_hash
|
80
|
+
end
|
81
|
+
@id_prefix + Digest::SHA1.hexdigest(Marshal::dump(identity))
|
82
|
+
end
|
83
|
+
|
84
|
+
def normalize_security_groups(groups)
|
85
|
+
groups.sort
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
data/lib/rivet/logger.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Rivet
|
2
|
+
|
3
|
+
module Log
|
4
|
+
|
5
|
+
def self.write(level,message)
|
6
|
+
@@log ||= SimpleLogger.instance
|
7
|
+
@@log.send(level.to_sym) { message }
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.info(message)
|
11
|
+
write('info',message)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.debug(message)
|
15
|
+
write('debug',message)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.fatal(message)
|
19
|
+
write('fatal',message)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.warn(message)
|
23
|
+
write('warn',message)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.level(level)
|
27
|
+
@@log ||= SimpleLogger.instance
|
28
|
+
@@log.level = level
|
29
|
+
end
|
30
|
+
|
31
|
+
class SimpleLogger< Logger
|
32
|
+
include Singleton
|
33
|
+
|
34
|
+
def initialize
|
35
|
+
@dev = Logger::LogDevice.new(STDOUT)
|
36
|
+
super @dev
|
37
|
+
@progname = "Rivet"
|
38
|
+
@formatter = proc do |sev,datetime,name,msg|
|
39
|
+
"[#{name}] [#{datetime}] [#{sev}]: #{msg}\n"
|
40
|
+
end
|
41
|
+
@datetime_format
|
42
|
+
end
|
43
|
+
|
44
|
+
def close
|
45
|
+
@dev.close
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
data/lib/rivet/utils.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
module Rivet
|
2
|
+
module Utils
|
3
|
+
AUTOSCALE_DIR = "autoscale"
|
4
|
+
|
5
|
+
def self.die(level = 'fatal',message)
|
6
|
+
Rivet::Log.write(level,message)
|
7
|
+
exit
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.ensure_minimum_setup
|
11
|
+
if Dir.exists?(AUTOSCALE_DIR)
|
12
|
+
true
|
13
|
+
else
|
14
|
+
Rivet::Log.info("Creating #{AUTOSCALE_DIR}")
|
15
|
+
Dir.mkdir(AUTOSCALE_DIR)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# This returns the merged definition given a group
|
20
|
+
|
21
|
+
def self.get_definition(group)
|
22
|
+
defaults = consume_defaults
|
23
|
+
group_def = load_definition(group)
|
24
|
+
if defaults && group_def
|
25
|
+
group_def = defaults.deep_merge(group_def)
|
26
|
+
end
|
27
|
+
group_def ? group_def : false
|
28
|
+
end
|
29
|
+
|
30
|
+
# Gobbles up the defaults file from YML, returns the hash or false if empty
|
31
|
+
|
32
|
+
def self.consume_defaults(autoscale_dir = AUTOSCALE_DIR)
|
33
|
+
defaults_file = File.join(autoscale_dir,"defaults.yml")
|
34
|
+
if File.exists?(defaults_file)
|
35
|
+
parsed = begin
|
36
|
+
Rivet::Log.debug("Consuming defaults from #{defaults_file}")
|
37
|
+
YAML.load(File.open(defaults_file))
|
38
|
+
rescue ArgumentError => e
|
39
|
+
Rivet::Log.fatal("Could not parse YAML from #{defaults_file}: #{e.message}")
|
40
|
+
end
|
41
|
+
parsed
|
42
|
+
else
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# This loads the given definition from it's YML file, returns the hash or
|
48
|
+
# false if empty
|
49
|
+
|
50
|
+
def self.load_definition(name)
|
51
|
+
definition_dir = File.join(AUTOSCALE_DIR,name)
|
52
|
+
conf_file = File.join(definition_dir,"conf.yml")
|
53
|
+
if Dir.exists?(definition_dir) && File.exists?(conf_file)
|
54
|
+
Rivet::Log.debug("Loading definition for #{name} from #{conf_file}")
|
55
|
+
parsed = begin
|
56
|
+
YAML.load(File.open(conf_file))
|
57
|
+
rescue
|
58
|
+
Rivet::Log.fatal("Could not parse YAML from #{conf_file}: #{e.message}")
|
59
|
+
end
|
60
|
+
parsed ? parsed : { }
|
61
|
+
else
|
62
|
+
false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
data/lib/rivet.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require 'base64'
|
3
|
+
require 'digest/sha1'
|
4
|
+
require 'erb'
|
5
|
+
require 'json'
|
6
|
+
require 'logger'
|
7
|
+
require 'optparse'
|
8
|
+
require 'singleton'
|
9
|
+
require 'yaml'
|
10
|
+
|
11
|
+
require_relative 'rivet/deep_merge'
|
12
|
+
require_relative 'rivet/logger'
|
13
|
+
require_relative 'rivet/utils'
|
14
|
+
require_relative 'rivet/aws_utils'
|
15
|
+
require_relative 'rivet/launch_config'
|
16
|
+
require_relative 'rivet/autoscale'
|
17
|
+
require_relative 'rivet/bootstrap'
|
18
|
+
require_relative 'rivet/client'
|
data/rivet.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib/',__FILE__)
|
4
|
+
$:.unshift lib unless $:.include?(lib)
|
5
|
+
require 'rivet/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'rivet'
|
9
|
+
spec.version = Rivet::VERSION
|
10
|
+
spec.licenses = ['Apache2']
|
11
|
+
spec.authors = ['Brian Bianco']
|
12
|
+
spec.email = ['brian.bianco@gmail.com']
|
13
|
+
spec.homepage = 'http://www.github.com/brianbianco/rivet'
|
14
|
+
spec.summary = %q{A tool for managing autoscaling groups}
|
15
|
+
spec.description = %q{Rivet allows you to define autoscaling groups and launch configurations as YAML and can SYNC that to AWS}
|
16
|
+
|
17
|
+
spec.required_ruby_version = '>= 1.9.1'
|
18
|
+
spec.required_rubygems_version = '>= 1.3.6'
|
19
|
+
|
20
|
+
spec.files = `git ls-files`.split($/)
|
21
|
+
spec.test_files = spec.files.grep(%r{^spec/})
|
22
|
+
|
23
|
+
spec.executables = %w(rivet)
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.add_dependency "aws-sdk", "~> 1.24.0"
|
27
|
+
spec.add_development_dependency "rake", ">= 10.1.0"
|
28
|
+
spec.add_development_dependency "rspec", "~> 2.14.1"
|
29
|
+
end
|
30
|
+
|
31
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require_relative './rivet_spec_setup'
|
2
|
+
|
3
|
+
include SpecHelpers
|
4
|
+
|
5
|
+
describe 'rivet bootstrap' do
|
6
|
+
let (:bootstrap) { Rivet::Bootstrap.new(SpecHelpers::AUTOSCALE_DEF['bootstrap']) }
|
7
|
+
let (:bootstrap_def) { SpecHelpers::AUTOSCALE_DEF['bootstrap'] }
|
8
|
+
|
9
|
+
tempdir_context 'with all necessary files in place' do
|
10
|
+
before do
|
11
|
+
|
12
|
+
|
13
|
+
validator_file = File.join(
|
14
|
+
bootstrap_def['config_dir'],
|
15
|
+
"#{bootstrap_def['environment']}-validator.pem")
|
16
|
+
|
17
|
+
template_dir = File.join(
|
18
|
+
bootstrap_def['config_dir'],
|
19
|
+
Rivet::Bootstrap::TEMPLATE_SUB_DIR)
|
20
|
+
|
21
|
+
template_file = File.join(template_dir,bootstrap_def['template'])
|
22
|
+
|
23
|
+
FileUtils.mkdir_p(bootstrap_def['config_dir'])
|
24
|
+
FileUtils.mkdir_p(template_dir)
|
25
|
+
File.open(template_file,'w') { |f| f.write(SpecHelpers::BOOTSTRAP_TEMPLATE) }
|
26
|
+
FileUtils.touch(validator_file)
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#user_data" do
|
30
|
+
it 'returns a string that contains the chef organization' do
|
31
|
+
org = bootstrap_def['organization']
|
32
|
+
bootstrap.user_data.should =~ /chef_server_url\s*.*#{org}.*/
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns a string that contains the environment' do
|
36
|
+
env = bootstrap_def['env']
|
37
|
+
bootstrap.user_data.should =~ /environment\s*.*#{env}.*/
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'returns a string that contains the run_list as json' do
|
41
|
+
run_list = { :run_list => bootstrap_def['run_list'].join(",") }.to_json
|
42
|
+
bootstrap.user_data.should =~ /#{run_list}/
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'returns a string that contains each gem to install' do
|
46
|
+
bootstrap_def['gems'].each do |g|
|
47
|
+
if g.size > 1
|
48
|
+
gem_regexp = /gem\s*install\s*#{g[0]}.*#{g[1]}/
|
49
|
+
else
|
50
|
+
gem_regexp = /gem\s*install\s*#{g[0]}/
|
51
|
+
end
|
52
|
+
bootstrap.user_data.should =~ gem_regexp
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative './rivet_spec_setup'
|
2
|
+
|
3
|
+
include SpecHelpers
|
4
|
+
|
5
|
+
describe "rivet launch config" do
|
6
|
+
let (:launch_config) { Rivet::LaunchConfig.new(SpecHelpers::AUTOSCALE_DEF) }
|
7
|
+
|
8
|
+
context "with a valid autoscale definition" do
|
9
|
+
before do
|
10
|
+
user_data_mock = double('user_data_mock')
|
11
|
+
user_data_mock.stub(:user_data).and_return("unit_test_user_data")
|
12
|
+
Rivet::Bootstrap.stub(:new).and_return(user_data_mock)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#build_identity_string" do
|
16
|
+
it "should return a valid identity_string" do
|
17
|
+
launch_config.send(:build_identity_string).should == SpecHelpers::AUTOSCALE_IDENTITY_STRING
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#identity" do
|
22
|
+
it "should return a deterministic identity" do
|
23
|
+
launch_config.identity.should == "rivet_#{Digest::SHA1.hexdigest(SpecHelpers::AUTOSCALE_IDENTITY_STRING)}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#normalize_security_groups" do
|
28
|
+
it "returns a sorted array of groups" do
|
29
|
+
unsorted_groups = ['group3','group1','group2']
|
30
|
+
sorted_groups = unsorted_groups.sort
|
31
|
+
returned_groups = launch_config.send(:normalize_security_groups,unsorted_groups)
|
32
|
+
returned_groups.should == sorted_groups
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'pathname'
|
5
|
+
require 'base64'
|
6
|
+
require_relative '../lib/rivet'
|
7
|
+
|
8
|
+
Rivet::Log.level(Logger::FATAL)
|
9
|
+
|
10
|
+
|
11
|
+
module SpecHelpers
|
12
|
+
|
13
|
+
|
14
|
+
BOOTSTRAP_TEMPLATE = '<%= install_gems %>'\
|
15
|
+
'<%= config_content %>'\
|
16
|
+
'<%= first_boot %>'\
|
17
|
+
"\n"\
|
18
|
+
'<%= chef_command %>'
|
19
|
+
|
20
|
+
|
21
|
+
AUTOSCALE_DEF = {
|
22
|
+
'min_size' => 1,
|
23
|
+
'max_size' => 3,
|
24
|
+
'region' => 'us-west-2',
|
25
|
+
'availability_zones' => ['a','b','c'],
|
26
|
+
'key_name' => 'UnitTests',
|
27
|
+
'instance_type' => 'm1.large',
|
28
|
+
'security_groups' => ['unit_tests1','unit_tests2'],
|
29
|
+
'image_id' => 'ami-12345678',
|
30
|
+
'bootstrap' => {
|
31
|
+
'chef_organization' => 'unit_tests',
|
32
|
+
'template' => 'default.erb',
|
33
|
+
'config_dir' => 'unit_tests',
|
34
|
+
'environment' => 'unit_tests',
|
35
|
+
'gems' => [ ['gem1','0.0.1'],['gem2','0.0.2'] ],
|
36
|
+
'run_list' => ['unit_tests']
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
AUTOSCALE_IDENTITY_STRING = "key_name#{Base64.encode64(AUTOSCALE_DEF['key_name'])}"\
|
41
|
+
"image_id#{Base64.encode64(AUTOSCALE_DEF['image_id'])}"\
|
42
|
+
"instance_type#{Base64.encode64(AUTOSCALE_DEF['instance_type'])}"\
|
43
|
+
"security_groups#{Base64.encode64(AUTOSCALE_DEF['security_groups'].join("\t"))}"\
|
44
|
+
"bootstrap#{Base64.encode64('unit_test_user_data')}"\
|
45
|
+
|
46
|
+
def tempdir_context(name, &block)
|
47
|
+
context name do
|
48
|
+
before do
|
49
|
+
@origin_dir = Dir.pwd
|
50
|
+
@temp_dir = ::Pathname.new(::File.expand_path(::Dir.mktmpdir))
|
51
|
+
Dir.chdir @temp_dir
|
52
|
+
end
|
53
|
+
|
54
|
+
after do
|
55
|
+
Dir.chdir @origin_dir
|
56
|
+
FileUtils.remove_entry(@temp_dir)
|
57
|
+
end
|
58
|
+
|
59
|
+
instance_eval &block
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require_relative './rivet_spec_setup'
|
2
|
+
|
3
|
+
include SpecHelpers
|
4
|
+
|
5
|
+
definition_name = "unit_test"
|
6
|
+
definition_dir = File.join(Rivet::Utils::AUTOSCALE_DIR,definition_name)
|
7
|
+
launch_config_params = ['ssh_key','instance_size','security_groups','ami','bootstrap']
|
8
|
+
|
9
|
+
defaults_hash = {
|
10
|
+
'min_size' => 0,
|
11
|
+
'max_size' => 0,
|
12
|
+
'region' => 'us-west-2',
|
13
|
+
'zones' => ['a','b','c'],
|
14
|
+
'key_name' => 'unit_tests',
|
15
|
+
'instance_type' => 'm1.large',
|
16
|
+
'security_groups' => ['unit_tests'],
|
17
|
+
'image_id' => 'ami-unit_tests',
|
18
|
+
'bootstrap' => {
|
19
|
+
'run_list' => ['role[unit_tests]']
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
unit_test_definition_hash = {
|
24
|
+
'min_size' => 1,
|
25
|
+
'max_size' => 5,
|
26
|
+
'bootstrap' => {
|
27
|
+
'run_list' => ['role[merging_test']
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
describe "rivet utils" do
|
32
|
+
tempdir_context "without an autoscaling directory" do
|
33
|
+
describe "ensure_minimum_setup" do
|
34
|
+
it "creates the autoscale directory if it doesn't exist" do
|
35
|
+
Rivet::Utils.ensure_minimum_setup
|
36
|
+
Dir.exists?(Rivet::Utils::AUTOSCALE_DIR).should be_true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
tempdir_context "with an autoscaling directory" do
|
42
|
+
before do
|
43
|
+
FileUtils.mkdir_p(Rivet::Utils::AUTOSCALE_DIR)
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "ensure_minimum_setup" do
|
47
|
+
it "should return true" do
|
48
|
+
Rivet::Utils.ensure_minimum_setup.should be_true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "consume_defaults" do
|
53
|
+
it "should return false" do
|
54
|
+
Rivet::Utils.consume_defaults.should be_false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "load_definition" do
|
59
|
+
it "should return false" do
|
60
|
+
Rivet::Utils.load_definition("unit_test").should be_false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "get_definition" do
|
65
|
+
it "should return false" do
|
66
|
+
Rivet::Utils.get_definition("unit_test")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "and with a group directory" do
|
71
|
+
before do
|
72
|
+
FileUtils.mkdir_p definition_dir
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "load_definition" do
|
76
|
+
it "should return false" do
|
77
|
+
Rivet::Utils.load_definition("unit_test").should be_false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "and with a conf.yml" do
|
82
|
+
before do
|
83
|
+
FileUtils.mkdir_p definition_dir
|
84
|
+
File.open(File.join(definition_dir,"conf.yml"),'w') do |f|
|
85
|
+
f.write(unit_test_definition_hash.to_yaml)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
describe "load_definition" do
|
89
|
+
it "returns a hash" do
|
90
|
+
loaded_def = Rivet::Utils.load_definition("unit_test")
|
91
|
+
unit_test_definition_hash.each_pair { |k,v| loaded_def.should include(k => v) }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
context "and with a defaults.yml" do
|
95
|
+
before do
|
96
|
+
File.open(File.join(Rivet::Utils::AUTOSCALE_DIR,"defaults.yml"),'w') do |f|
|
97
|
+
f.write(defaults_hash.to_yaml)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "consume_defaults" do
|
102
|
+
it "consume defaults returns a hash" do
|
103
|
+
results = Rivet::Utils.consume_defaults
|
104
|
+
defaults_hash.each_pair { |k,v| results.should include(k => v) }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "get_definition" do
|
109
|
+
it "returns a merged hash" do
|
110
|
+
result = Rivet::Utils.get_definition(definition_name)
|
111
|
+
merged_hash = defaults_hash.merge(unit_test_definition_hash)
|
112
|
+
result.should == defaults_hash.merge(unit_test_definition_hash)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|