rivet 1.4.0 → 2.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/.rubocop.yml +18 -0
- data/.travis.yml +3 -5
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +27 -35
- data/README.md +71 -46
- data/autoscale/defaults.rb +23 -0
- data/bin/rivet +24 -20
- data/example/autoscale/defaults.rb +22 -0
- data/example/autoscale/example_group.rb +10 -0
- data/lib/rivet/autoscale.rb +77 -89
- data/lib/rivet/aws_autoscale_wrapper.rb +82 -0
- data/lib/rivet/aws_utils.rb +10 -8
- data/lib/rivet/bootstrap.rb +13 -58
- data/lib/rivet/client.rb +26 -20
- data/lib/rivet/config.rb +87 -0
- data/lib/rivet/config_proxy.rb +28 -0
- data/lib/rivet/deep_merge.rb +3 -1
- data/lib/rivet/launch_config.rb +45 -34
- data/lib/rivet/logger.rb +3 -1
- data/lib/rivet/open_state.rb +44 -0
- data/lib/rivet/utils.rb +11 -46
- data/lib/rivet/version.rb +3 -1
- data/lib/rivet.rb +12 -6
- data/rivet.gemspec +1 -1
- data/spec/aws_autoscale_wrapper_spec.rb +123 -0
- data/spec/bootstrap_spec.rb +38 -0
- data/spec/config_proxy_spec.rb +34 -0
- data/spec/config_spec.rb +168 -0
- data/spec/launch_config_spec.rb +30 -0
- data/spec/open_state_spec.rb +67 -0
- data/spec/spec_setup.rb +112 -0
- data/spec/util_spec.rb +34 -0
- metadata +28 -12
- data/spec/rivet_bootstrap_spec.rb +0 -80
- data/spec/rivet_launch_config_spec.rb +0 -37
- data/spec/rivet_spec_setup.rb +0 -68
- data/spec/rivet_util_spec.rb +0 -108
data/lib/rivet/autoscale.rb
CHANGED
@@ -1,35 +1,46 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
module Rivet
|
2
4
|
class Autoscale
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
6
|
+
OPTIONS = [
|
7
|
+
:availability_zones,
|
8
|
+
:default_cooldown,
|
9
|
+
:desired_capacity,
|
10
|
+
:health_check_grace_period,
|
11
|
+
:health_check_type,
|
12
|
+
:launch_configuration,
|
13
|
+
:load_balancers,
|
14
|
+
:max_size,
|
15
|
+
:min_size,
|
16
|
+
:placement_group,
|
17
|
+
:subnets,
|
18
|
+
:tags,
|
19
|
+
:termination_policies
|
20
|
+
].each { |a| attr_reader a }
|
21
|
+
|
22
|
+
REQUIRED_OPTIONS = [
|
23
|
+
:availability_zones,
|
24
|
+
:launch_configuration,
|
25
|
+
:max_size,
|
26
|
+
:min_size
|
27
|
+
]
|
28
|
+
|
29
|
+
attr_reader :name
|
30
|
+
|
31
|
+
def initialize(config)
|
32
|
+
@name = config.name
|
33
|
+
@remote_group = AwsAutoscaleWrapper.new(@name)
|
34
|
+
@launch_config = LaunchConfig.new(config)
|
35
|
+
|
36
|
+
OPTIONS.each do |o|
|
37
|
+
if config.respond_to?(o)
|
38
|
+
instance_variable_set("@#{o}", config.send(o))
|
19
39
|
end
|
20
|
-
@tags = definition['tags']
|
21
|
-
else
|
22
|
-
@tags = []
|
23
|
-
end
|
24
|
-
@launch_config = LaunchConfig.new(definition)
|
25
|
-
|
26
|
-
# Normalizing zones to match what the SDK expects, E.G. "<region><zone>"
|
27
|
-
@availability_zones = definition['availability_zones'].map! do |zone|
|
28
|
-
definition['region'] + zone
|
29
40
|
end
|
30
41
|
|
31
|
-
# The launch_configuration attr exists
|
32
|
-
# the aws SDK refers to the launch configuration name as
|
42
|
+
# The launch_configuration attr exists because that is what
|
43
|
+
# the aws SDK refers to the launch configuration name as.
|
33
44
|
@launch_configuration = @launch_config.identity
|
34
45
|
end
|
35
46
|
|
@@ -46,110 +57,87 @@ module Rivet
|
|
46
57
|
end
|
47
58
|
|
48
59
|
def show_differences(level = 'info')
|
49
|
-
|
50
|
-
Rivet::Log.write(level, "Remote and local defintions match") unless differences?
|
51
|
-
|
60
|
+
Rivet::Log.write(level, 'Remote and local match') unless differences?
|
52
61
|
differences.each_pair do |attr, values|
|
53
62
|
Rivet::Log.write(level, "#{attr}:")
|
54
|
-
Rivet::Log.write(level, " remote: #{values[
|
55
|
-
Rivet::Log.write(level, " local: #{values[
|
63
|
+
Rivet::Log.write(level, " remote: #{values[:remote]}")
|
64
|
+
Rivet::Log.write(level, " local: #{values[:local]}")
|
56
65
|
end
|
66
|
+
Rivet::Log.write('debug', @launch_config.user_data)
|
57
67
|
end
|
58
68
|
|
59
69
|
def sync
|
60
70
|
if differences?
|
61
|
-
Rivet::Log.info
|
71
|
+
Rivet::Log.info "Syncing autoscale group changes to AWS for #{@name}"
|
62
72
|
autoscale = AWS::AutoScaling.new
|
63
73
|
group = autoscale.groups[@name]
|
64
74
|
|
65
75
|
@launch_config.save
|
66
76
|
create(options) unless group.exists?
|
67
77
|
|
68
|
-
Rivet::Log.debug
|
69
|
-
Rivet::Log.debug
|
78
|
+
Rivet::Log.debug 'Updating autoscaling group with the follow options'
|
79
|
+
Rivet::Log.debug options.inspect
|
70
80
|
|
81
|
+
# It's easier to just delete all the tags if there are changes and apply
|
82
|
+
# new ones, than ferret out exactly which ones should be removed.
|
83
|
+
if differences.has_key? :tags
|
84
|
+
group.delete_all_tags
|
85
|
+
end
|
71
86
|
group.update(options)
|
87
|
+
|
72
88
|
else
|
73
|
-
Rivet::Log.info
|
89
|
+
Rivet::Log.info "No autoscale differences to sync to AWS for #{@name}."
|
74
90
|
end
|
75
91
|
end
|
76
92
|
|
77
93
|
protected
|
78
94
|
|
79
|
-
def get_update_options
|
80
|
-
options = {}
|
81
|
-
differences.each_pair do |attribute, values|
|
82
|
-
options[attribute.to_sym] = values['local']
|
83
|
-
end
|
84
|
-
|
85
|
-
REQUIRED_FIELDS.each do |field|
|
86
|
-
unless options.has_key? field
|
87
|
-
options[field] = self.send(field)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
options
|
91
|
-
end
|
92
|
-
|
93
95
|
def get_differences
|
94
|
-
remote = get_remote
|
95
96
|
differences = {}
|
96
|
-
[:min_size, :max_size, :launch_configuration, :tags].each do |a|
|
97
|
-
if remote[a.to_s] != self.send(a)
|
98
|
-
differences[a.to_s] = { 'remote' => remote[a.to_s], 'local' => self.send(a) }
|
99
|
-
end
|
100
|
-
end
|
101
97
|
|
102
|
-
|
103
|
-
|
104
|
-
|
98
|
+
OPTIONS.each do |o|
|
99
|
+
remote_value = @remote_group.send(o)
|
100
|
+
local_value = send(o)
|
105
101
|
|
102
|
+
if (remote_value != local_value)
|
103
|
+
differences[o] = { :local => send(o), :remote => @remote_group.send(o) }
|
104
|
+
end
|
105
|
+
end
|
106
106
|
differences
|
107
107
|
end
|
108
108
|
|
109
|
-
def
|
110
|
-
|
111
|
-
remote_group = autoscale.groups[@name]
|
112
|
-
if remote_group.exists?
|
109
|
+
def get_update_options
|
110
|
+
options = {}
|
113
111
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
112
|
+
OPTIONS.each do |field|
|
113
|
+
local_value = self.send(field)
|
114
|
+
options[field] = local_value unless local_value.nil?
|
115
|
+
end
|
118
116
|
|
119
|
-
|
120
|
-
|
121
|
-
|
117
|
+
REQUIRED_OPTIONS.each do |field|
|
118
|
+
unless options.has_key? field
|
119
|
+
options[field] = self.send(field)
|
122
120
|
end
|
123
|
-
|
124
|
-
remote_hash['launch_configuration'] = remote_group.launch_configuration_name
|
125
|
-
|
126
|
-
# Normalize their AWS::Core::Data::List to a sorted array
|
127
|
-
remote_hash['availability_zones'] = remote_group.availability_zone_names.to_a.sort
|
128
|
-
|
129
|
-
remote_hash
|
130
|
-
else
|
131
|
-
{}
|
132
121
|
end
|
122
|
+
options
|
133
123
|
end
|
134
124
|
|
135
125
|
def create(options)
|
126
|
+
|
127
|
+
# When creating an autoscaling group passing empty arrays for subnets
|
128
|
+
# or some other fields can cause it to barf. Remove them first.
|
129
|
+
options.delete_if { |k, v| v.respond_to?(:'empty?') && v.empty? }
|
130
|
+
|
131
|
+
Rivet::Log.debug "Creating Autoscaling group #{@name} with the following options"
|
132
|
+
Rivet::Log.debug options
|
133
|
+
|
136
134
|
autoscale = AWS::AutoScaling.new
|
137
135
|
if autoscale.groups[@name].exists?
|
138
|
-
|
136
|
+
fail "Cannot create AutoScaling #{@name} group it already exists!"
|
139
137
|
else
|
140
138
|
autoscale.groups.create(@name, options)
|
141
139
|
end
|
142
140
|
end
|
143
141
|
|
144
|
-
def normalize_tag(tag)
|
145
|
-
normalized_tag = {}
|
146
|
-
tag.each_pair do |k, v|
|
147
|
-
unless (k == :resource_id || k == :resource_type)
|
148
|
-
normalized_tag[k.to_s] = v
|
149
|
-
end
|
150
|
-
end
|
151
|
-
normalized_tag
|
152
|
-
end
|
153
|
-
|
154
142
|
end
|
155
143
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Rivet
|
4
|
+
class AwsAutoscaleWrapper
|
5
|
+
|
6
|
+
OPTIONS = [
|
7
|
+
:availability_zones,
|
8
|
+
:default_cooldown,
|
9
|
+
:desired_capacity,
|
10
|
+
:health_check_grace_period,
|
11
|
+
:health_check_type,
|
12
|
+
:launch_configuration,
|
13
|
+
:load_balancers,
|
14
|
+
:max_size,
|
15
|
+
:min_size,
|
16
|
+
:placement_group,
|
17
|
+
:subnets,
|
18
|
+
:tags,
|
19
|
+
:termination_policies
|
20
|
+
].each { |a| attr_reader a }
|
21
|
+
|
22
|
+
attr_reader :name
|
23
|
+
|
24
|
+
def initialize(name)
|
25
|
+
Rivet::Log.debug "Initializing AWS Autoscale Wrapper for #{name}"
|
26
|
+
@name = name
|
27
|
+
@group = AWS::AutoScaling.new.groups[@name]
|
28
|
+
|
29
|
+
if @group.exists?
|
30
|
+
OPTIONS.each do |o|
|
31
|
+
normalize_method = "normalize_#{o}".to_sym
|
32
|
+
if respond_to?(normalize_method)
|
33
|
+
Rivet::Log.debug "Calling #{normalize_method} in AWS autoscale wrapper"
|
34
|
+
value = send(normalize_method)
|
35
|
+
else
|
36
|
+
value = @group.send(o)
|
37
|
+
end
|
38
|
+
instance_variable_set("@#{o}", value)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def normalize_launch_configuration
|
45
|
+
@group.launch_configuration_name
|
46
|
+
end
|
47
|
+
|
48
|
+
def normalize_load_balancers
|
49
|
+
@group.load_balancer_names.to_a.sort
|
50
|
+
end
|
51
|
+
|
52
|
+
def normalize_availability_zones
|
53
|
+
@group.availability_zone_names.to_a.sort
|
54
|
+
end
|
55
|
+
|
56
|
+
def normalize_tags
|
57
|
+
@group.tags.to_a.inject([]) do |normalized_tags, current|
|
58
|
+
normalized_tags << normalize_tag(current)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def normalize_subnets
|
63
|
+
@group.subnets.empty? ? nil : @group.subnets.map(&:id).sort
|
64
|
+
end
|
65
|
+
|
66
|
+
def normalize_termination_policies
|
67
|
+
@group.termination_policies.to_a.sort
|
68
|
+
end
|
69
|
+
|
70
|
+
protected
|
71
|
+
|
72
|
+
def normalize_tag(tag)
|
73
|
+
normalized_tag = {}
|
74
|
+
tag.each_pair do |k, v|
|
75
|
+
unless (k == :resource_id || k == :resource_type)
|
76
|
+
normalized_tag[k] = v
|
77
|
+
end
|
78
|
+
end
|
79
|
+
normalized_tag
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/rivet/aws_utils.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
module Rivet
|
2
4
|
module AwsUtils
|
3
5
|
|
4
6
|
def self.verify_security_groups(groups)
|
5
|
-
return false if groups.nil?
|
6
|
-
Rivet::Log.info
|
7
|
+
return false if groups.nil? || groups.all?{|g| g.match(/\Asg-[0-9a-f]{8}\z/) }
|
8
|
+
Rivet::Log.info "Verifying security groups: #{groups.join(",")}"
|
7
9
|
|
8
10
|
security_groups_collection = AWS::EC2.new.security_groups
|
9
11
|
filtered_groups = []
|
@@ -13,7 +15,7 @@ module Rivet
|
|
13
15
|
|
14
16
|
groups.each do |g|
|
15
17
|
unless filtered_groups.include?(g)
|
16
|
-
Rivet::Log.debug
|
18
|
+
Rivet::Log.debug "Creating security group #{g}"
|
17
19
|
security_groups_collection.create g
|
18
20
|
end
|
19
21
|
end
|
@@ -27,7 +29,7 @@ module Rivet
|
|
27
29
|
option_matcher = /(\w.*)=(\S.*)\s*/
|
28
30
|
aws_config = {}
|
29
31
|
|
30
|
-
File.open(ENV['AWS_CONFIG_FILE'],
|
32
|
+
File.open(ENV['AWS_CONFIG_FILE'], 'r').each_line do |line|
|
31
33
|
|
32
34
|
if line =~ profile_matcher
|
33
35
|
current_profile = line.match(profile_matcher)[2]
|
@@ -39,13 +41,13 @@ module Rivet
|
|
39
41
|
|
40
42
|
# Normalize the option name so it can be used with the AWS SDK
|
41
43
|
if results[1] =~ /^\S*aws_/
|
42
|
-
option = results[1].gsub(
|
44
|
+
option = results[1].gsub('aws_', '').to_sym
|
43
45
|
else
|
44
46
|
option = results[1].to_sym
|
45
47
|
end
|
46
48
|
|
47
49
|
value = results[2]
|
48
|
-
aws_config[current_profile].merge!({ option => value})
|
50
|
+
aws_config[current_profile].merge!({ option => value })
|
49
51
|
end
|
50
52
|
|
51
53
|
end
|
@@ -54,12 +56,12 @@ module Rivet
|
|
54
56
|
end
|
55
57
|
|
56
58
|
def self.set_aws_credentials(profile)
|
57
|
-
Rivet::Log.info
|
59
|
+
Rivet::Log.info "Settings AWS credentials to #{profile} profile"
|
58
60
|
settings = config_parser
|
59
61
|
aws_creds = nil
|
60
62
|
|
61
63
|
if settings && settings.has_key?(profile)
|
62
|
-
aws_creds = [:access_key_id
|
64
|
+
aws_creds = [:access_key_id, :secret_access_key, :region].inject({})do |accum, option|
|
63
65
|
if settings[profile].has_key?(option)
|
64
66
|
accum[option] = settings[profile][option]
|
65
67
|
end
|
data/lib/rivet/bootstrap.rb
CHANGED
@@ -1,25 +1,11 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
module Rivet
|
2
4
|
class Bootstrap
|
3
|
-
|
4
|
-
|
5
|
-
attr_reader :gems, :run_list, :template, :environment, :region, :name, :elastic_ip
|
6
|
-
attr_reader :template_path, :chef_command, :chef_organization, :chef_username
|
7
|
-
|
8
|
-
def initialize(bootstrap_definition = {})
|
9
|
-
ivars = [
|
10
|
-
'gems', 'run_list', 'template', 'environment', 'region', 'name', 'elastic_ip',
|
11
|
-
'config_dir', 'chef_command', 'chef_organization', 'chef_username']
|
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?
|
5
|
+
attr_reader :config
|
18
6
|
|
19
|
-
|
20
|
-
@
|
21
|
-
|
22
|
-
set_calculated_attrs
|
7
|
+
def initialize(config)
|
8
|
+
@config = config.bootstrap
|
23
9
|
end
|
24
10
|
|
25
11
|
def user_data
|
@@ -28,46 +14,15 @@ module Rivet
|
|
28
14
|
|
29
15
|
protected
|
30
16
|
|
31
|
-
def set_calculated_attrs
|
32
|
-
@template_path = File.join(@config_dir, TEMPLATE_SUB_DIR)
|
33
|
-
@secret_file = File.join(@config_dir, "encrypted_data_bag_secret_#{@environment}")
|
34
|
-
@validation_key = File.new(File.join(@config_dir, "#{@chef_organization}-validator.pem")).read
|
35
|
-
end
|
36
|
-
|
37
17
|
def generate_user_data
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
knife_content << "\n"
|
47
|
-
knife_content << "environment '#{environment}'\n"
|
48
|
-
knife_content << "log_level :info\n"
|
49
|
-
knife_content << "log_location STDOUT\n"
|
50
|
-
knife_content << "node_name \"\#{chef_username}\"\n"
|
51
|
-
knife_content << "client_key \"~/.chef/\#{chef_username}.pem\"\n"
|
52
|
-
knife_content << "chef_server_url \"https://api.opscode.com/organizations/\#{chef_organization}\"\n"
|
53
|
-
knife_content << "cache_type 'BasicFile'\n"
|
54
|
-
knife_content << "puts \"Using \#{environment} environment...\"\n"
|
55
|
-
|
56
|
-
install_gems = ''
|
57
|
-
|
58
|
-
gems.each do |g|
|
59
|
-
if g.size > 1
|
60
|
-
install_gems << "gem install #{g[0]} -v #{g[1]} --no-rdoc --no-ri\n"
|
61
|
-
else
|
62
|
-
install_gems << "gem install #{g[0]} --no-rdoc --no-ri\n"
|
63
|
-
end
|
64
|
-
end unless gems.nil?
|
65
|
-
|
66
|
-
first_boot = { :run_list => @run_list.flatten }.to_json unless @run_list.nil?
|
67
|
-
|
68
|
-
template = ERB.new File.new(File.join(@template_path, @template)).read
|
69
|
-
template.result(binding)
|
18
|
+
if config.respond_to?(:template)
|
19
|
+
Rivet::Log.debug "Rendering #{config.template}"
|
20
|
+
template = ERB.new(File.read(config.template))
|
21
|
+
template.result(config.instance_eval { binding })
|
22
|
+
else
|
23
|
+
Rivet::Log.debug 'No template provided, Rendering empty user-data'
|
24
|
+
''
|
25
|
+
end
|
70
26
|
end
|
71
|
-
|
72
27
|
end
|
73
28
|
end
|
data/lib/rivet/client.rb
CHANGED
@@ -1,35 +1,41 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
module Rivet
|
2
4
|
class Client
|
3
|
-
def initialize
|
4
|
-
end
|
5
|
-
|
6
5
|
def run(options)
|
7
|
-
AwsUtils.set_aws_credentials
|
8
|
-
Rivet::Log.level
|
6
|
+
AwsUtils.set_aws_credentials options.profile
|
7
|
+
Rivet::Log.level options.log_level
|
9
8
|
|
10
|
-
|
11
|
-
|
9
|
+
Rivet::Log.info "Using autoscale config path #{options.config_path}"
|
10
|
+
|
11
|
+
unless Dir.exists?(options.config_path)
|
12
|
+
Rivet::Utils.die 'The autoscale config path does not exist'
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
options
|
15
|
+
# Get config object for autoscaling group
|
16
|
+
config = Rivet::Utils.get_config(
|
17
|
+
options.group,
|
18
|
+
options.config_path)
|
17
19
|
|
18
|
-
unless
|
19
|
-
Rivet::Utils.
|
20
|
+
unless config
|
21
|
+
Rivet::Utils.list_groups(options.config_path)
|
22
|
+
Rivet::Utils.die "The #{options.group} autoscale definition doesn't exist"
|
20
23
|
end
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
+
config.validate
|
26
|
+
|
27
|
+
config = ConfigProxy.new(config)
|
25
28
|
|
26
|
-
|
27
|
-
|
29
|
+
Rivet::Log.info "Checking #{options.group} autoscaling definition"
|
30
|
+
|
31
|
+
autoscale_group = Rivet::Autoscale.new(config)
|
32
|
+
autoscale_group.show_differences
|
33
|
+
|
34
|
+
if options.sync
|
35
|
+
autoscale_group.sync
|
28
36
|
else
|
29
|
-
Rivet::Log.info
|
37
|
+
Rivet::Log.info 'use the -s [--sync] flag to sync changes'
|
30
38
|
end
|
31
|
-
|
32
39
|
end
|
33
|
-
|
34
40
|
end
|
35
41
|
end
|
data/lib/rivet/config.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Rivet
|
4
|
+
class Config < OpenState
|
5
|
+
attr_reader :name
|
6
|
+
attr_accessor :bootstrap
|
7
|
+
|
8
|
+
def self.from_file(dsl_file, load_path='.')
|
9
|
+
name = File.basename(dsl_file, '.rb')
|
10
|
+
data = Proc.new { eval(File.read(dsl_file)) }
|
11
|
+
new(name, load_path, &data)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(name, load_path='.', &block)
|
15
|
+
super()
|
16
|
+
@name = name
|
17
|
+
@path = load_path
|
18
|
+
@bootstrap = OpenState.new
|
19
|
+
@required_fields = {
|
20
|
+
:min_size => nil,
|
21
|
+
:max_size => nil,
|
22
|
+
:availability_zones => nil,
|
23
|
+
:default_cooldown => 300,
|
24
|
+
:desired_capacity => 0,
|
25
|
+
:health_check_grace_period => 0,
|
26
|
+
:health_check_type => :ec2,
|
27
|
+
:load_balancers => [],
|
28
|
+
:tags => [],
|
29
|
+
:termination_policies => ['Default']
|
30
|
+
}
|
31
|
+
instance_eval(&block) if block
|
32
|
+
end
|
33
|
+
|
34
|
+
def path(*args)
|
35
|
+
if args.size < 1
|
36
|
+
@path
|
37
|
+
else
|
38
|
+
File.join(@path, *args)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def normalize_availability_zones
|
43
|
+
availability_zones.map { |zone| region + zone }.sort
|
44
|
+
end
|
45
|
+
|
46
|
+
def normalize_security_groups
|
47
|
+
security_groups.sort
|
48
|
+
end
|
49
|
+
|
50
|
+
def normalize_load_balancers
|
51
|
+
load_balancers.sort
|
52
|
+
end
|
53
|
+
|
54
|
+
def normalize_subnets
|
55
|
+
subnets.sort
|
56
|
+
end
|
57
|
+
|
58
|
+
def normalize_tags
|
59
|
+
normalized_tags = []
|
60
|
+
tags.each do |t|
|
61
|
+
normalized_hash = {}
|
62
|
+
|
63
|
+
if t.has_key? :propagate_at_launch
|
64
|
+
normalized_hash[:propagate_at_launch] = t[:propagate_at_launch]
|
65
|
+
else
|
66
|
+
normalized_hash[:propagate_at_launch] = true
|
67
|
+
end
|
68
|
+
|
69
|
+
[:value, :key].each do |k|
|
70
|
+
if t.has_key? k
|
71
|
+
normalized_hash[k] = t[k]
|
72
|
+
else
|
73
|
+
normalized_hash[k] = nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
normalized_tags << normalized_hash
|
77
|
+
end
|
78
|
+
normalized_tags
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
def import(import_path)
|
84
|
+
lambda { eval(File.read(import_path)) }.call
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Rivet
|
4
|
+
class ConfigProxy < BasicObject
|
5
|
+
|
6
|
+
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
def send(m, *args)
|
11
|
+
if @config.respond_to?("normalize_#{m}".to_sym)
|
12
|
+
@config.send("normalize_#{m}".to_sym)
|
13
|
+
else
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def method_missing(m, *args, &block)
|
19
|
+
if @config.respond_to?("normalize_#{m}".to_sym)
|
20
|
+
@config.send("normalize_#{m}".to_sym)
|
21
|
+
elsif @config.respond_to? m
|
22
|
+
@config.send(m, *args, &block)
|
23
|
+
else
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/rivet/deep_merge.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
class Hash
|
2
4
|
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
3
5
|
#
|
@@ -14,7 +16,7 @@ class Hash
|
|
14
16
|
|
15
17
|
# Same as +deep_merge+, but modifies +self+.
|
16
18
|
def deep_merge!(other_hash, &block)
|
17
|
-
other_hash.each_pair do |k,v|
|
19
|
+
other_hash.each_pair do |k, v|
|
18
20
|
tv = self[k]
|
19
21
|
if tv.is_a?(Hash) && v.is_a?(Hash)
|
20
22
|
self[k] = tv.deep_merge(v, &block)
|