rivet 1.4.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|