chef-provisioning-aws 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +2 -0
- data/lib/chef/provider/aws_auto_scaling_group.rb +30 -41
- data/lib/chef/provider/aws_dhcp_options.rb +70 -0
- data/lib/chef/provider/aws_ebs_volume.rb +182 -34
- data/lib/chef/provider/aws_eip_address.rb +63 -60
- data/lib/chef/provider/aws_key_pair.rb +18 -27
- data/lib/chef/provider/aws_launch_configuration.rb +50 -0
- data/lib/chef/provider/aws_route_table.rb +122 -0
- data/lib/chef/provider/aws_s3_bucket.rb +42 -49
- data/lib/chef/provider/aws_security_group.rb +252 -59
- data/lib/chef/provider/aws_sns_topic.rb +10 -26
- data/lib/chef/provider/aws_sqs_queue.rb +16 -38
- data/lib/chef/provider/aws_subnet.rb +85 -32
- data/lib/chef/provider/aws_vpc.rb +163 -23
- data/lib/chef/provisioning/aws_driver.rb +18 -1
- data/lib/chef/provisioning/aws_driver/aws_provider.rb +206 -0
- data/lib/chef/provisioning/aws_driver/aws_resource.rb +186 -0
- data/lib/chef/provisioning/aws_driver/aws_resource_with_entry.rb +114 -0
- data/lib/chef/provisioning/aws_driver/driver.rb +317 -255
- data/lib/chef/provisioning/aws_driver/resources.rb +8 -5
- data/lib/chef/provisioning/aws_driver/super_lwrp.rb +45 -0
- data/lib/chef/provisioning/aws_driver/version.rb +1 -1
- data/lib/chef/resource/aws_auto_scaling_group.rb +15 -13
- data/lib/chef/resource/aws_dhcp_options.rb +57 -0
- data/lib/chef/resource/aws_ebs_volume.rb +20 -22
- data/lib/chef/resource/aws_eip_address.rb +50 -25
- data/lib/chef/resource/aws_image.rb +20 -0
- data/lib/chef/resource/aws_instance.rb +20 -0
- data/lib/chef/resource/aws_internet_gateway.rb +16 -0
- data/lib/chef/resource/aws_key_pair.rb +6 -10
- data/lib/chef/resource/aws_launch_configuration.rb +15 -0
- data/lib/chef/resource/aws_load_balancer.rb +16 -0
- data/lib/chef/resource/aws_network_interface.rb +16 -0
- data/lib/chef/resource/aws_route_table.rb +76 -0
- data/lib/chef/resource/aws_s3_bucket.rb +8 -18
- data/lib/chef/resource/aws_security_group.rb +49 -19
- data/lib/chef/resource/aws_sns_topic.rb +14 -15
- data/lib/chef/resource/aws_sqs_queue.rb +16 -14
- data/lib/chef/resource/aws_subnet.rb +87 -17
- data/lib/chef/resource/aws_vpc.rb +137 -15
- data/spec/integration/aws_security_group_spec.rb +55 -0
- data/spec/spec_helper.rb +8 -2
- data/spec/support/aws_support.rb +211 -0
- metadata +33 -10
- data/lib/chef/provider/aws_launch_config.rb +0 -43
- data/lib/chef/provider/aws_provider.rb +0 -22
- data/lib/chef/provisioning/aws_driver/aws_profile.rb +0 -73
- data/lib/chef/resource/aws_launch_config.rb +0 -14
- data/lib/chef/resource/aws_resource.rb +0 -10
- data/spec/chef_zero_rspec_helper.rb +0 -8
- data/spec/unit/provider/aws_subnet_spec.rb +0 -67
- data/spec/unit/resource/aws_subnet_spec.rb +0 -23
@@ -47,10 +47,11 @@ module AWSDriver
|
|
47
47
|
region = nil if region && region.empty?
|
48
48
|
|
49
49
|
credentials = profile_name ? aws_credentials[profile_name] : aws_credentials.default
|
50
|
-
@aws_config = AWS
|
50
|
+
@aws_config = AWS.config(
|
51
51
|
access_key_id: credentials[:aws_access_key_id],
|
52
52
|
secret_access_key: credentials[:aws_secret_access_key],
|
53
|
-
region: region || credentials[:region]
|
53
|
+
region: region || credentials[:region],
|
54
|
+
logger: Chef::Log.logger
|
54
55
|
)
|
55
56
|
end
|
56
57
|
|
@@ -60,50 +61,30 @@ module AWSDriver
|
|
60
61
|
|
61
62
|
# Load balancer methods
|
62
63
|
def allocate_load_balancer(action_handler, lb_spec, lb_options, machine_specs)
|
63
|
-
lb_options
|
64
|
-
if lb_options[:security_group_ids]
|
65
|
-
security_groups = ec2.security_groups.filter('group-id', lb_options[:security_group_ids]).to_a
|
66
|
-
elsif lb_options[:security_group_names]
|
67
|
-
security_groups = ec2.security_groups.filter('group-name', lb_options[:security_group_names]).to_a
|
68
|
-
else
|
69
|
-
security_groups = []
|
70
|
-
end
|
71
|
-
security_group_ids = security_groups.map { |sg| sg.id }
|
72
|
-
|
73
|
-
availability_zones = lb_options[:availability_zones] || []
|
74
|
-
subnets = lb_options[:subnets] || []
|
75
|
-
listeners = lb_options[:listeners]
|
76
|
-
scheme = lb_options[:scheme]
|
77
|
-
|
78
|
-
validate_listeners(listeners)
|
79
|
-
if !availability_zones.empty? && !subnets.empty?
|
80
|
-
raise "You cannot specify both `availability_zones` and `subnets`"
|
81
|
-
end
|
82
|
-
|
83
|
-
lb_optionals = {}
|
84
|
-
lb_optionals[:security_groups] = security_group_ids unless security_group_ids.empty?
|
85
|
-
lb_optionals[:availability_zones] = availability_zones unless availability_zones.empty?
|
86
|
-
lb_optionals[:subnets] = subnets unless subnets.empty?
|
87
|
-
lb_optionals[:listeners] = listeners if listeners
|
88
|
-
lb_optionals[:scheme] = scheme if scheme
|
64
|
+
lb_options = AWSResource.lookup_options(lb_options || {}, managed_entry_store: lb_spec.managed_entry_store, driver: self)
|
89
65
|
|
90
66
|
old_elb = nil
|
91
67
|
actual_elb = load_balancer_for(lb_spec)
|
92
|
-
if !actual_elb.exists?
|
68
|
+
if !actual_elb || !actual_elb.exists?
|
69
|
+
lb_options[:listeners] ||= get_listeners(:http)
|
70
|
+
if !lb_options[:subnets] && !lb_options[:availability_zones] && machine_specs
|
71
|
+
lb_options[:subnets] = machine_specs.map { |s| ec2.instances[s.reference['instance_id']].subnet }.uniq
|
72
|
+
end
|
73
|
+
|
93
74
|
perform_action = proc { |desc, &block| action_handler.perform_action(desc, &block) }
|
75
|
+
Chef::Log.debug "AWS Load Balancer options: #{lb_options.inspect}"
|
94
76
|
|
95
|
-
|
77
|
+
updates = [ "create load balancer #{lb_spec.name} in #{aws_config.region}" ]
|
78
|
+
updates << " enable availability zones #{lb_options[:availability_zones]}" if lb_options[:availability_zones]
|
79
|
+
updates << " attach subnets #{lb_options[:subnets].join(', ')}" if lb_options[:subnets]
|
80
|
+
updates << " with listeners #{lb_options[:listeners]}" if lb_options[:listeners]
|
81
|
+
updates << " with security groups #{lb_options[:security_groups]}" if lb_options[:security_groups]
|
96
82
|
|
97
|
-
updates = [ "Create load balancer #{lb_spec.name} in #{aws_config.region}" ]
|
98
|
-
updates << " enable availability zones #{availability_zones.join(', ')}" if availability_zones.size > 0
|
99
|
-
updates << " attach subnets #{subnets.join(', ')}" if subnets.size > 0
|
100
|
-
updates << " with listeners #{listeners.join(', ')}" if listeners && listeners.size > 0
|
101
|
-
updates << " with security groups #{security_group_names}" if security_group_names
|
102
83
|
|
103
84
|
action_handler.perform_action updates do
|
104
|
-
actual_elb = elb.load_balancers.create(lb_spec.name,
|
85
|
+
actual_elb = elb.load_balancers.create(lb_spec.name, lb_options)
|
105
86
|
|
106
|
-
lb_spec.
|
87
|
+
lb_spec.reference = {
|
107
88
|
'driver_url' => driver_url,
|
108
89
|
'driver_version' => Chef::Provisioning::AWSDriver::VERSION,
|
109
90
|
'allocated_at' => Time.now.utc.to_s,
|
@@ -117,24 +98,28 @@ module AWSDriver
|
|
117
98
|
end
|
118
99
|
|
119
100
|
# TODO: refactor this whole giant method into many smaller method calls
|
101
|
+
# TODO if we update scheme, we don't need to run any of the other updates.
|
102
|
+
# Also, if things aren't specified (such as machines / listeners), we
|
103
|
+
# need to grab them from the actual load balancer so we don't lose them.
|
104
|
+
# i.e. load_balancer 'blah' do
|
105
|
+
# lb_options: { scheme: 'other_scheme' }
|
106
|
+
# end
|
107
|
+
# TODO we will leak the actual_elb if we fail to finish creating it
|
120
108
|
# Update scheme - scheme is immutable once set, so if it is changing we need to delete the old
|
121
109
|
# ELB and create a new one
|
122
|
-
if scheme && scheme.downcase != actual_elb.scheme
|
123
|
-
desc = [" updating scheme to #{scheme}"]
|
110
|
+
if lb_options[:scheme] && lb_options[:scheme].downcase != actual_elb.scheme
|
111
|
+
desc = [" updating scheme to #{lb_options[:scheme]}"]
|
124
112
|
desc << " WARN: scheme is immutable, so deleting and re-creating the ELB"
|
125
113
|
perform_action.call(desc) do
|
126
114
|
old_elb = actual_elb
|
127
|
-
actual_elb = elb.load_balancers.create(lb_spec.name,
|
115
|
+
actual_elb = elb.load_balancers.create(lb_spec.name, lb_options)
|
128
116
|
end
|
129
117
|
end
|
130
118
|
|
131
119
|
# Update security groups
|
132
|
-
if
|
133
|
-
Chef::Log.debug("No Security Groups specified. Load_balancer[#{actual_elb.name}] cannot have " +
|
134
|
-
"empty Security Groups, so assuming it only currently has the default Security Group. No action taken.")
|
135
|
-
else
|
120
|
+
if lb_options[:security_groups]
|
136
121
|
current = actual_elb.security_group_ids
|
137
|
-
desired =
|
122
|
+
desired = lb_options[:security_groups]
|
138
123
|
if current != desired
|
139
124
|
perform_action.call(" updating security groups to #{desired.to_a}") do
|
140
125
|
elb.client.apply_security_groups_to_load_balancer(
|
@@ -145,148 +130,155 @@ module AWSDriver
|
|
145
130
|
end
|
146
131
|
end
|
147
132
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
# Users can switch from availability zones to subnets or vice versa. To ensure we do not
|
158
|
-
# unassign all (which causes an AWS error) we first add all available ones, then remove
|
159
|
-
# an unecessary ones
|
160
|
-
actual_zones_subnets = {}
|
161
|
-
actual_elb.subnets.each do |subnet|
|
162
|
-
actual_zones_subnets[subnet.id] = subnet.availability_zone.name
|
163
|
-
end
|
164
|
-
|
165
|
-
# Only 1 of subnet or AZ will be populated b/c of our check earlier
|
166
|
-
desired_subnets_zones = {}
|
167
|
-
availability_zones.each do |zone|
|
168
|
-
# If the user specifies availability zone, we find the default subnet for that
|
169
|
-
# AZ because this duplicates the create logic
|
170
|
-
zone = zone.downcase
|
171
|
-
filters = [
|
172
|
-
{:name => 'availabilityZone', :values => [zone]},
|
173
|
-
{:name => 'defaultForAz', :values => ['true']}
|
174
|
-
]
|
175
|
-
default_subnet = ec2.client.describe_subnets(:filters => filters)[:subnet_set]
|
176
|
-
if default_subnet.size != 1
|
177
|
-
raise "Could not find default subnet in availability zone #{zone}"
|
133
|
+
if lb_options[:availability_zones] || lb_options[:subnets]
|
134
|
+
# A subnet always belongs to an availability zone. When specifying a ELB spec, you can either
|
135
|
+
# specify subnets OR AZs but not both. You cannot specify multiple subnets in the same AZ.
|
136
|
+
# You must specify at least 1 subnet or AZ. On an update you cannot remove all subnets
|
137
|
+
# or AZs - it must belong to one.
|
138
|
+
if lb_options[:availability_zones] && lb_options[:subnets]
|
139
|
+
# We do this check here because there is no atomic call we can make to specify both
|
140
|
+
# subnets and AZs at the same time
|
141
|
+
raise "You cannot specify both `availability_zones` and `subnets`"
|
178
142
|
end
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
zone = subnet[:availability_zone].downcase
|
187
|
-
desired_subnets_zones[subnet[:subnet_id]] = zone
|
143
|
+
|
144
|
+
# Users can switch from availability zones to subnets or vice versa. To ensure we do not
|
145
|
+
# unassign all (which causes an AWS error) we first add all available ones, then remove
|
146
|
+
# an unecessary ones
|
147
|
+
actual_zones_subnets = {}
|
148
|
+
actual_elb.subnets.each do |subnet|
|
149
|
+
actual_zones_subnets[subnet.id] = subnet.availability_zone.name
|
188
150
|
end
|
189
|
-
end
|
190
151
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
)
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
152
|
+
# Only 1 of subnet or AZ will be populated b/c of our check earlier
|
153
|
+
desired_subnets_zones = {}
|
154
|
+
if lb_options[:availability_zones]
|
155
|
+
lb_options[:availability_zones].each do |zone|
|
156
|
+
# If the user specifies availability zone, we find the default subnet for that
|
157
|
+
# AZ because this duplicates the create logic
|
158
|
+
zone = zone.downcase
|
159
|
+
filters = [
|
160
|
+
{:name => 'availabilityZone', :values => [zone]},
|
161
|
+
{:name => 'defaultForAz', :values => ['true']}
|
162
|
+
]
|
163
|
+
default_subnet = ec2.client.describe_subnets(:filters => filters)[:subnet_set]
|
164
|
+
if default_subnet.size != 1
|
165
|
+
raise "Could not find default subnet in availability zone #{zone}"
|
166
|
+
end
|
167
|
+
default_subnet = default_subnet[0]
|
168
|
+
desired_subnets_zones[default_subnet[:subnet_id]] = zone
|
169
|
+
end
|
170
|
+
end
|
171
|
+
unless lb_options[:subnets] && lb_options[:subnets.empty?]
|
172
|
+
subnet_query = ec2.client.describe_subnets(:subnet_ids => lb_options[:subnets])[:subnet_set]
|
173
|
+
# AWS raises an error on an unknown subnet, but not an unknown AZ
|
174
|
+
subnet_query.each do |subnet|
|
175
|
+
zone = subnet[:availability_zone].downcase
|
176
|
+
desired_subnets_zones[subnet[:subnet_id]] = zone
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# We only bother attaching subnets, because doing this automatically attaches the AZ
|
181
|
+
attach_subnets = desired_subnets_zones.keys - actual_zones_subnets.keys
|
182
|
+
unless attach_subnets.empty?
|
183
|
+
action = " attach subnets #{attach_subnets.join(', ')}"
|
184
|
+
enable_zones = (desired_subnets_zones.map {|s,z| z if attach_subnets.include?(s)}).compact
|
185
|
+
action += " (availability zones #{enable_zones.join(', ')})"
|
186
|
+
perform_action.call(action) do
|
187
|
+
begin
|
188
|
+
elb.client.attach_load_balancer_to_subnets(
|
189
|
+
load_balancer_name: actual_elb.name,
|
190
|
+
subnets: attach_subnets
|
191
|
+
)
|
192
|
+
rescue AWS::ELB::Errors::InvalidConfigurationRequest
|
193
|
+
raise "You cannot currently move from 1 subnet to another in the same availability zone. " +
|
194
|
+
"Amazon does not have an atomic operation which allows this. You must create a new " +
|
195
|
+
"ELB with the correct subnets and move instances into it. Tried to attach subets " +
|
196
|
+
"#{attach_subnets.join(', ')} (availability zones #{enable_zones.join(', ')}) to " +
|
197
|
+
"existing ELB named #{actual_elb.name}"
|
198
|
+
end
|
209
199
|
end
|
210
200
|
end
|
211
|
-
end
|
212
201
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
202
|
+
detach_subnets = actual_zones_subnets.keys - desired_subnets_zones.keys
|
203
|
+
unless detach_subnets.empty?
|
204
|
+
action = " detach subnets #{detach_subnets.join(', ')}"
|
205
|
+
disable_zones = (actual_zones_subnets.map {|s,z| z if detach_subnets.include?(s)}).compact
|
206
|
+
action += " (availability zones #{disable_zones.join(', ')})"
|
207
|
+
perform_action.call(action) do
|
208
|
+
elb.client.detach_load_balancer_from_subnets(
|
209
|
+
load_balancer_name: actual_elb.name,
|
210
|
+
subnets: detach_subnets
|
211
|
+
)
|
212
|
+
end
|
223
213
|
end
|
224
214
|
end
|
225
215
|
|
226
216
|
# Update listeners - THIS IS NOT ATOMIC
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
if listener.instance_port != desired_listener[:instance_port]
|
240
|
-
immutable_updates << " update instance port from #{listener.instance_port.inspect} to #{desired_listener[:instance_port].inspect}"
|
241
|
-
end
|
242
|
-
if listener.instance_protocol != desired_listener[:instance_protocol].to_sym.downcase
|
243
|
-
immutable_updates << " update instance protocol from #{listener.instance_protocol.inspect} to #{desired_listener[:instance_protocol].inspect}"
|
244
|
-
end
|
245
|
-
if !immutable_updates.empty?
|
246
|
-
perform_action.call(immutable_updates) do
|
247
|
-
listener.delete
|
248
|
-
actual_elb.listeners.create(desired_listener)
|
217
|
+
if lb_options[:listeners]
|
218
|
+
add_listeners = {}
|
219
|
+
lb_options[:listeners].each { |l| add_listeners[l[:port]] = l }
|
220
|
+
actual_elb.listeners.each do |listener|
|
221
|
+
desired_listener = add_listeners.delete(listener.port)
|
222
|
+
if desired_listener
|
223
|
+
|
224
|
+
# listener.(port|protocol|instance_port|instance_protocol) are immutable for the life
|
225
|
+
# of the listener - must create a new one and delete old one
|
226
|
+
immutable_updates = []
|
227
|
+
if listener.protocol != desired_listener[:protocol].to_sym.downcase
|
228
|
+
immutable_updates << " update protocol from #{listener.protocol.inspect} to #{desired_listener[:protocol].inspect}"
|
249
229
|
end
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
230
|
+
if listener.instance_port != desired_listener[:instance_port]
|
231
|
+
immutable_updates << " update instance port from #{listener.instance_port.inspect} to #{desired_listener[:instance_port].inspect}"
|
232
|
+
end
|
233
|
+
if listener.instance_protocol != desired_listener[:instance_protocol].to_sym.downcase
|
234
|
+
immutable_updates << " update instance protocol from #{listener.instance_protocol.inspect} to #{desired_listener[:instance_protocol].inspect}"
|
235
|
+
end
|
236
|
+
if !immutable_updates.empty?
|
237
|
+
perform_action.call(immutable_updates) do
|
238
|
+
listener.delete
|
239
|
+
actual_elb.listeners.create(desired_listener)
|
240
|
+
end
|
241
|
+
elsif listener.server_certificate != desired_listener[:server_certificate]
|
242
|
+
# Server certificate is mutable - if no immutable changes required a full recreate, update cert
|
243
|
+
perform_action.call(" update server certificate from #{listener.server_certificate} to #{desired_listener[:server_certificate]}") do
|
244
|
+
listener.server_certificate = desired_listener[:server_certificate]
|
245
|
+
end
|
254
246
|
end
|
255
|
-
end
|
256
247
|
|
257
|
-
|
258
|
-
|
259
|
-
|
248
|
+
else
|
249
|
+
perform_action.call(" remove listener #{listener.port}") do
|
250
|
+
listener.delete
|
251
|
+
end
|
260
252
|
end
|
261
253
|
end
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
254
|
+
add_listeners.values.each do |listener|
|
255
|
+
updates = [ " add listener #{listener[:port]}" ]
|
256
|
+
updates << " set protocol to #{listener[:protocol].inspect}"
|
257
|
+
updates << " set instance port to #{listener[:instance_port].inspect}"
|
258
|
+
updates << " set instance protocol to #{listener[:instance_protocol].inspect}"
|
259
|
+
updates << " set server certificate to #{listener[:server_certificate]}" if listener[:server_certificate]
|
260
|
+
perform_action.call(updates) do
|
261
|
+
actual_elb.listeners.create(listener)
|
262
|
+
end
|
271
263
|
end
|
272
264
|
end
|
273
265
|
end
|
274
266
|
|
275
267
|
# Update instance list, but only if there are machines specified
|
276
|
-
actual_instance_ids = actual_elb.instances.map { |i| i.instance_id }
|
277
|
-
|
278
268
|
if machine_specs
|
279
|
-
|
280
|
-
|
281
|
-
|
269
|
+
actual_instance_ids = actual_elb.instances.map { |i| i.instance_id }
|
270
|
+
|
271
|
+
instances_to_add = machine_specs.select { |s| !actual_instance_ids.include?(s.reference['instance_id']) }
|
272
|
+
instance_ids_to_remove = actual_instance_ids - machine_specs.map { |s| s.reference['instance_id'] }
|
273
|
+
|
282
274
|
if instances_to_add.size > 0
|
283
275
|
perform_action.call(" add machines #{instances_to_add.map { |s| s.name }.join(', ')}") do
|
284
|
-
instance_ids_to_add = instances_to_add.map { |s| s.
|
276
|
+
instance_ids_to_add = instances_to_add.map { |s| s.reference['instance_id'] }
|
285
277
|
Chef::Log.debug("Adding instances #{instance_ids_to_add.join(', ')} to load balancer #{actual_elb.name} in region #{aws_config.region}")
|
286
278
|
actual_elb.instances.add(instance_ids_to_add)
|
287
279
|
end
|
288
280
|
end
|
289
|
-
|
281
|
+
|
290
282
|
if instance_ids_to_remove.size > 0
|
291
283
|
perform_action.call(" remove instances #{instance_ids_to_remove}") do
|
292
284
|
actual_elb.instances.remove(instance_ids_to_remove)
|
@@ -303,12 +295,12 @@ module AWSDriver
|
|
303
295
|
# Something went wrong before we could moved instances from the old ELB to the new one
|
304
296
|
# Don't delete the old ELB, but warn users there could now be 2 ELBs with the same name
|
305
297
|
unless old_elb.nil?
|
306
|
-
Chef::Log.warn("It is possible there are now 2 ELB instances - #{old_elb.
|
298
|
+
Chef::Log.warn("It is possible there are now 2 ELB instances - #{old_elb.name} and #{actual_elb.name}. " +
|
307
299
|
"Determine which is correct and manually clean up the other.")
|
308
300
|
end
|
309
301
|
end
|
310
302
|
|
311
|
-
def ready_load_balancer(action_handler, lb_spec, lb_options,
|
303
|
+
def ready_load_balancer(action_handler, lb_spec, lb_options, machine_spec)
|
312
304
|
end
|
313
305
|
|
314
306
|
def destroy_load_balancer(action_handler, lb_spec, lb_options)
|
@@ -327,27 +319,21 @@ module AWSDriver
|
|
327
319
|
end
|
328
320
|
|
329
321
|
# Image methods
|
330
|
-
def allocate_image(action_handler, image_spec, image_options, machine_spec)
|
322
|
+
def allocate_image(action_handler, image_spec, image_options, machine_spec, machine_options)
|
331
323
|
actual_image = image_for(image_spec)
|
332
324
|
if actual_image.nil? || !actual_image.exists? || actual_image.state == :failed
|
333
325
|
action_handler.perform_action "Create image #{image_spec.name} from machine #{machine_spec.name} with options #{image_options.inspect}" do
|
334
326
|
image_options[:name] ||= image_spec.name
|
335
|
-
image_options[:instance_id] ||= machine_spec.
|
327
|
+
image_options[:instance_id] ||= machine_spec.reference['instance_id']
|
336
328
|
image_options[:description] ||= "Image #{image_spec.name} created from machine #{machine_spec.name}"
|
337
329
|
Chef::Log.debug "AWS Image options: #{image_options.inspect}"
|
338
330
|
image = ec2.images.create(image_options.to_hash)
|
339
|
-
image_spec.
|
331
|
+
image_spec.reference = {
|
340
332
|
'driver_url' => driver_url,
|
341
333
|
'driver_version' => Chef::Provisioning::AWSDriver::VERSION,
|
342
334
|
'image_id' => image.id,
|
343
335
|
'allocated_at' => Time.now.to_i
|
344
336
|
}
|
345
|
-
image_spec.machine_options ||= {}
|
346
|
-
image_spec.machine_options.merge!({
|
347
|
-
:bootstrap_options => {
|
348
|
-
:image_id => image.id
|
349
|
-
}
|
350
|
-
})
|
351
337
|
end
|
352
338
|
end
|
353
339
|
end
|
@@ -368,10 +354,12 @@ module AWSDriver
|
|
368
354
|
|
369
355
|
def destroy_image(action_handler, image_spec, image_options)
|
370
356
|
actual_image = image_for(image_spec)
|
371
|
-
snapshots = snapshots_for(image_spec)
|
372
357
|
if actual_image.nil? || !actual_image.exists?
|
373
358
|
Chef::Log.warn "Image #{image_spec.name} doesn't exist"
|
374
359
|
else
|
360
|
+
snapshots = actual_image.block_device_mappings.map do |dev, opts|
|
361
|
+
ec2.snapshots[opts[:snapshot_id]]
|
362
|
+
end
|
375
363
|
action_handler.perform_action "De-registering image #{image_spec.name}" do
|
376
364
|
actual_image.deregister
|
377
365
|
end
|
@@ -420,7 +408,7 @@ EOD
|
|
420
408
|
sleep 5 while instance.status == :pending
|
421
409
|
# TODO add other tags identifying user / node url (same as fog)
|
422
410
|
instance.tags['Name'] = machine_spec.name
|
423
|
-
machine_spec.
|
411
|
+
machine_spec.reference = {
|
424
412
|
'driver_url' => driver_url,
|
425
413
|
'driver_version' => Chef::Provisioning::AWSDriver::VERSION,
|
426
414
|
'allocated_at' => Time.now.utc.to_s,
|
@@ -428,9 +416,9 @@ EOD
|
|
428
416
|
'image_id' => bootstrap_options[:image_id],
|
429
417
|
'instance_id' => instance.id
|
430
418
|
}
|
431
|
-
machine_spec.
|
419
|
+
machine_spec.reference['key_name'] = bootstrap_options[:key_name] if bootstrap_options[:key_name]
|
432
420
|
%w(is_windows ssh_username sudo use_private_ip_for_ssh ssh_gateway).each do |key|
|
433
|
-
machine_spec.
|
421
|
+
machine_spec.reference[key] = machine_options[key.to_sym] if machine_options[key.to_sym]
|
434
422
|
end
|
435
423
|
end
|
436
424
|
end
|
@@ -455,7 +443,7 @@ EOD
|
|
455
443
|
if instance.status != :running
|
456
444
|
wait_until_machine(action_handler, machine_spec, instance) { instance.status != :stopping }
|
457
445
|
if instance.status == :stopped
|
458
|
-
action_handler.perform_action "Start #{machine_spec.name} (#{machine_spec.
|
446
|
+
action_handler.perform_action "Start #{machine_spec.name} (#{machine_spec.reference['instance_id']}) in #{aws_config.region} ..." do
|
459
447
|
instance.start
|
460
448
|
end
|
461
449
|
end
|
@@ -473,19 +461,19 @@ EOD
|
|
473
461
|
machine_spec = Chef::Provisioning::ChefMachineSpec.get(name, chef_server)
|
474
462
|
end
|
475
463
|
|
476
|
-
machine_for(machine_spec, machine_spec.
|
464
|
+
machine_for(machine_spec, machine_spec.reference)
|
477
465
|
end
|
478
466
|
|
479
467
|
def destroy_machine(action_handler, machine_spec, machine_options)
|
480
468
|
instance = instance_for(machine_spec)
|
481
469
|
if instance && instance.exists?
|
482
470
|
# TODO do we need to wait_until(action_handler, machine_spec, instance) { instance.status != :shutting_down } ?
|
483
|
-
action_handler.perform_action "Terminate #{machine_spec.name} (#{machine_spec.
|
471
|
+
action_handler.perform_action "Terminate #{machine_spec.name} (#{machine_spec.reference['instance_id']}) in #{aws_config.region} ..." do
|
484
472
|
instance.terminate
|
485
|
-
machine_spec.
|
473
|
+
machine_spec.reference = nil
|
486
474
|
end
|
487
475
|
else
|
488
|
-
Chef::Log.warn "Instance #{machine_spec.
|
476
|
+
Chef::Log.warn "Instance #{machine_spec.reference['instance_id']} doesn't exist for #{machine_spec.name}"
|
489
477
|
end
|
490
478
|
|
491
479
|
strategy = convergence_strategy_for(machine_spec, machine_options)
|
@@ -500,6 +488,14 @@ EOD
|
|
500
488
|
@elb ||= AWS::ELB.new(config: aws_config)
|
501
489
|
end
|
502
490
|
|
491
|
+
def iam
|
492
|
+
@iam ||= AWS::IAM.new(config: aws_config)
|
493
|
+
end
|
494
|
+
|
495
|
+
def s3
|
496
|
+
@s3 ||= AWS::S3.new(config: aws_config)
|
497
|
+
end
|
498
|
+
|
503
499
|
def sns
|
504
500
|
@sns ||= AWS::SNS.new(config: aws_config)
|
505
501
|
end
|
@@ -508,15 +504,40 @@ EOD
|
|
508
504
|
@sqs ||= AWS::SQS.new(config: aws_config)
|
509
505
|
end
|
510
506
|
|
511
|
-
def s3
|
512
|
-
@s3 ||= AWS::S3.new(config: aws_config)
|
513
|
-
end
|
514
|
-
|
515
507
|
def auto_scaling
|
516
508
|
@auto_scaling ||= AWS::AutoScaling.new(config: aws_config)
|
517
509
|
end
|
518
510
|
|
519
|
-
|
511
|
+
def build_arn(partition: 'aws', service: nil, region: aws_config.region, account_id: self.account_id, resource: nil)
|
512
|
+
"arn:#{partition}:#{service}:#{region}:#{account_id}:#{resource}"
|
513
|
+
end
|
514
|
+
|
515
|
+
def parse_arn(arn)
|
516
|
+
parts = arn.split(':', 6)
|
517
|
+
{
|
518
|
+
partition: parts[1],
|
519
|
+
service: parts[2],
|
520
|
+
region: parts[3],
|
521
|
+
account_id: parts[4],
|
522
|
+
resource: parts[5]
|
523
|
+
}
|
524
|
+
end
|
525
|
+
|
526
|
+
def account_id
|
527
|
+
begin
|
528
|
+
# We've got an AWS account root credential or an IAM admin with access rights
|
529
|
+
current_user = iam.client.get_user
|
530
|
+
arn = current_user[:user][:arn]
|
531
|
+
rescue AWS::IAM::Errors::AccessDenied => e
|
532
|
+
# If we don't have access, the error message still tells us our account ID and user ...
|
533
|
+
# https://forums.aws.amazon.com/thread.jspa?messageID=394344
|
534
|
+
if e.to_s !~ /\b(arn:aws:iam::[0-9]{12}:\S*)/
|
535
|
+
raise "IAM error response for GetUser did not include user ARN. Can't retrieve account ID."
|
536
|
+
end
|
537
|
+
arn = $1
|
538
|
+
end
|
539
|
+
parse_arn(arn)[:account_id]
|
540
|
+
end
|
520
541
|
|
521
542
|
# For creating things like AWS keypairs exclusively
|
522
543
|
@@chef_default_lock = Mutex.new
|
@@ -528,7 +549,7 @@ EOD
|
|
528
549
|
raise "Instance for node #{machine_spec.name} has not been created!"
|
529
550
|
end
|
530
551
|
|
531
|
-
if machine_spec.
|
552
|
+
if machine_spec.reference['is_windows']
|
532
553
|
Chef::Provisioning::Machine::WindowsMachine.new(machine_spec, transport_for(machine_spec, machine_options, instance), convergence_strategy_for(machine_spec, machine_options))
|
533
554
|
else
|
534
555
|
Chef::Provisioning::Machine::UnixMachine.new(machine_spec, transport_for(machine_spec, machine_options, instance), convergence_strategy_for(machine_spec, machine_options))
|
@@ -551,6 +572,7 @@ EOD
|
|
551
572
|
Chef::Log.debug "Non-windows, not setting userdata"
|
552
573
|
end
|
553
574
|
|
575
|
+
bootstrap_options = AWSResource.lookup_options(bootstrap_options, managed_entry_store: machine_spec.managed_entry_store, driver: self)
|
554
576
|
Chef::Log.debug "AWS Bootstrap options: #{bootstrap_options.inspect}"
|
555
577
|
bootstrap_options
|
556
578
|
end
|
@@ -571,62 +593,36 @@ EOD
|
|
571
593
|
end
|
572
594
|
|
573
595
|
def load_balancer_for(lb_spec)
|
574
|
-
|
575
|
-
elb.load_balancers[lb_spec.name]
|
576
|
-
else
|
577
|
-
nil
|
578
|
-
end
|
596
|
+
Chef::Resource::AwsLoadBalancer.get_aws_object(lb_spec.name, driver: self, managed_entry_store: lb_spec.managed_entry_store, required: false)
|
579
597
|
end
|
580
598
|
|
581
599
|
def instance_for(machine_spec)
|
582
|
-
if machine_spec.
|
583
|
-
|
600
|
+
if machine_spec.reference
|
601
|
+
if machine_spec.reference['driver_url'] != driver_url
|
602
|
+
raise "Switching a machine's driver from #{machine_spec.reference['driver_url']} to #{driver_url} is not currently supported! Use machine :destroy and then re-create the machine on the new driver."
|
603
|
+
end
|
604
|
+
Chef::Resource::AwsInstance.get_aws_object(machine_spec.reference['instance_id'], driver: self, managed_entry_store: machine_spec.managed_entry_store, required: false)
|
584
605
|
end
|
585
606
|
end
|
586
607
|
|
587
608
|
def instances_for(machine_specs)
|
588
609
|
result = {}
|
589
|
-
machine_specs.each
|
590
|
-
if machine_spec.location && machine_spec.location['instance_id']
|
591
|
-
if machine_spec.location['driver_url'] != driver_url
|
592
|
-
raise "Switching a machine's driver from #{machine_spec.location['driver_url']} to #{driver_url} is not currently supported! Use machine :destroy and then re-create the machine on the new driver."
|
593
|
-
end
|
594
|
-
#returns nil if not found
|
595
|
-
result[machine_spec] = ec2.instances[machine_spec.location['instance_id']]
|
596
|
-
end
|
597
|
-
end
|
610
|
+
machine_specs.each { |machine_spec| result[machine_spec] = instance_for(machine_spec) }
|
598
611
|
result
|
599
612
|
end
|
600
613
|
|
601
614
|
def image_for(image_spec)
|
602
|
-
|
603
|
-
ec2.images[image_spec.location['image_id']]
|
604
|
-
end
|
605
|
-
end
|
606
|
-
|
607
|
-
def snapshots_for(image_spec)
|
608
|
-
if image_spec.location && image_spec.location['image_id']
|
609
|
-
actual_image = image_for(image_spec)
|
610
|
-
snapshots = []
|
611
|
-
actual_image.block_device_mappings.each do |dev, opts|
|
612
|
-
snapshots << ec2.snapshots[opts[:snapshot_id]]
|
613
|
-
end
|
614
|
-
snapshots
|
615
|
-
end
|
615
|
+
Chef::Resource::AwsImage.get_aws_object(image_spec.name, driver: self, managed_entry_store: image_spec.managed_entry_store, required: false)
|
616
616
|
end
|
617
617
|
|
618
618
|
def transport_for(machine_spec, machine_options, instance)
|
619
|
-
if machine_spec.
|
619
|
+
if machine_spec.reference['is_windows']
|
620
620
|
create_winrm_transport(machine_spec, machine_options, instance)
|
621
621
|
else
|
622
622
|
create_ssh_transport(machine_spec, machine_options, instance)
|
623
623
|
end
|
624
624
|
end
|
625
625
|
|
626
|
-
def compute_options
|
627
|
-
|
628
|
-
end
|
629
|
-
|
630
626
|
def aws_credentials
|
631
627
|
# Grab the list of possible credentials
|
632
628
|
@aws_credentials ||= if driver_options[:aws_credentials]
|
@@ -674,7 +670,7 @@ EOD
|
|
674
670
|
def create_winrm_transport(machine_spec, machine_options, instance)
|
675
671
|
remote_host = determine_remote_host(machine_spec, instance)
|
676
672
|
|
677
|
-
port = machine_spec.
|
673
|
+
port = machine_spec.reference['winrm_port'] || 5985
|
678
674
|
endpoint = "http://#{remote_host}:#{port}/wsman"
|
679
675
|
type = :plaintext
|
680
676
|
pem_bytes = get_private_key(instance.key_name)
|
@@ -685,7 +681,7 @@ EOD
|
|
685
681
|
decrypted_password = private_key.private_decrypt decoded
|
686
682
|
|
687
683
|
winrm_options = {
|
688
|
-
:user => machine_spec.
|
684
|
+
:user => machine_spec.reference['winrm_username'] || 'Administrator',
|
689
685
|
:pass => decrypted_password,
|
690
686
|
:disable_sspi => true,
|
691
687
|
:basic_auth_only => true
|
@@ -699,7 +695,7 @@ EOD
|
|
699
695
|
sleep_time = 10
|
700
696
|
max_wait_time = 900 # 15 minutes
|
701
697
|
encrypted_admin_password = nil
|
702
|
-
instance_id = machine_spec.
|
698
|
+
instance_id = machine_spec.reference['instance_id']
|
703
699
|
|
704
700
|
Chef::Log.info "waiting for #{machine_spec.name}'s admin password to be available..."
|
705
701
|
while time_elapsed < max_wait_time && encrypted_admin_password.nil?
|
@@ -720,12 +716,12 @@ EOD
|
|
720
716
|
|
721
717
|
def create_ssh_transport(machine_spec, machine_options, instance)
|
722
718
|
ssh_options = ssh_options_for(machine_spec, machine_options, instance)
|
723
|
-
username = machine_spec.
|
724
|
-
if machine_options.has_key?(:ssh_username) && machine_options[:ssh_username] != machine_spec.
|
725
|
-
Chef::Log.warn("Server #{machine_spec.name} was created with SSH username #{machine_spec.
|
719
|
+
username = machine_spec.reference['ssh_username'] || machine_options[:ssh_username] || default_ssh_username
|
720
|
+
if machine_options.has_key?(:ssh_username) && machine_options[:ssh_username] != machine_spec.reference['ssh_username']
|
721
|
+
Chef::Log.warn("Server #{machine_spec.name} was created with SSH username #{machine_spec.reference['ssh_username']} and machine_options specifies username #{machine_options[:ssh_username]}. Using #{machine_spec.reference['ssh_username']}. Please edit the node and change the chef_provisioning.reference.ssh_username attribute if you want to change it.")
|
726
722
|
end
|
727
723
|
options = {}
|
728
|
-
if machine_spec.
|
724
|
+
if machine_spec.reference[:sudo] || (!machine_spec.reference.has_key?(:sudo) && username != 'root')
|
729
725
|
options[:prefix] = 'sudo '
|
730
726
|
end
|
731
727
|
|
@@ -733,13 +729,13 @@ EOD
|
|
733
729
|
|
734
730
|
#Enable pty by default
|
735
731
|
options[:ssh_pty_enable] = true
|
736
|
-
options[:ssh_gateway] = machine_spec.
|
732
|
+
options[:ssh_gateway] = machine_spec.reference['ssh_gateway'] if machine_spec.reference.has_key?('ssh_gateway')
|
737
733
|
|
738
734
|
Chef::Provisioning::Transport::SSH.new(remote_host, username, ssh_options, options, config)
|
739
735
|
end
|
740
736
|
|
741
737
|
def determine_remote_host(machine_spec, instance)
|
742
|
-
if machine_spec.
|
738
|
+
if machine_spec.reference['use_private_ip_for_ssh']
|
743
739
|
instance.private_ip_address
|
744
740
|
elsif !instance.public_ip_address
|
745
741
|
Chef::Log.warn("Server #{machine_spec.name} has no public ip address. Using private ip '#{instance.private_ip_address}'. Set driver option 'use_private_ip_for_ssh' => true if this will always be the case ...")
|
@@ -768,10 +764,10 @@ EOD
|
|
768
764
|
raise "Server has key name '#{instance.key_name}', but the corresponding private key was not found locally. Check if the key is in Chef::Config.private_key_paths: #{Chef::Config.private_key_paths.join(', ')}"
|
769
765
|
end
|
770
766
|
result[:key_data] = [ key ]
|
771
|
-
elsif machine_spec.
|
772
|
-
key = get_private_key(machine_spec.
|
767
|
+
elsif machine_spec.reference['key_name']
|
768
|
+
key = get_private_key(machine_spec.reference['key_name'])
|
773
769
|
unless key
|
774
|
-
raise "Server was created with key name '#{machine_spec.
|
770
|
+
raise "Server was created with key name '#{machine_spec.reference['key_name']}', but the corresponding private key was not found locally. Check if the key is in Chef::Config.private_key_paths: #{Chef::Config.private_key_paths.join(', ')}"
|
775
771
|
end
|
776
772
|
result[:key_data] = [ key ]
|
777
773
|
elsif machine_options[:bootstrap_options] && machine_options[:bootstrap_options][:key_path]
|
@@ -780,7 +776,7 @@ EOD
|
|
780
776
|
result[:key_data] = [ get_private_key(machine_options[:bootstrap_options][:key_name]) ]
|
781
777
|
else
|
782
778
|
# TODO make a way to suggest other keys to try ...
|
783
|
-
raise "No key found to connect to #{machine_spec.name} (#{machine_spec.
|
779
|
+
raise "No key found to connect to #{machine_spec.name} (#{machine_spec.reference.inspect})!"
|
784
780
|
end
|
785
781
|
result
|
786
782
|
end
|
@@ -792,11 +788,11 @@ EOD
|
|
792
788
|
ohai_hints: { 'ec2' => '' })
|
793
789
|
|
794
790
|
# Defaults
|
795
|
-
if !machine_spec.
|
791
|
+
if !machine_spec.reference
|
796
792
|
return Chef::Provisioning::ConvergenceStrategy::NoConverge.new(convergence_options, config)
|
797
793
|
end
|
798
794
|
|
799
|
-
if machine_spec.
|
795
|
+
if machine_spec.reference['is_windows']
|
800
796
|
Chef::Provisioning::ConvergenceStrategy::InstallMsi.new(convergence_options, config)
|
801
797
|
elsif machine_options[:cached_installer] == true
|
802
798
|
Chef::Provisioning::ConvergenceStrategy::InstallCached.new(convergence_options, config)
|
@@ -816,11 +812,14 @@ EOD
|
|
816
812
|
max_wait_time = 120
|
817
813
|
if !yield(image)
|
818
814
|
action_handler.report_progress "waiting for #{image_spec.name} (#{image.id} on #{driver_url}) to be ready ..."
|
819
|
-
while time_elapsed <
|
815
|
+
while time_elapsed < max_wait_time && !yield(image)
|
820
816
|
action_handler.report_progress "been waiting #{time_elapsed}/#{max_wait_time} -- sleeping #{sleep_time} seconds for #{image_spec.name} (#{image.id} on #{driver_url}) to be ready ..."
|
821
817
|
sleep(sleep_time)
|
822
818
|
time_elapsed += sleep_time
|
823
819
|
end
|
820
|
+
unless yield(image)
|
821
|
+
raise "Image #{image.id} did not become ready within 120 seconds"
|
822
|
+
end
|
824
823
|
action_handler.report_progress "Image #{image_spec.name} is now ready"
|
825
824
|
end
|
826
825
|
end
|
@@ -837,11 +836,14 @@ EOD
|
|
837
836
|
if !yield(instance)
|
838
837
|
if action_handler.should_perform_actions
|
839
838
|
action_handler.report_progress "waiting for #{machine_spec.name} (#{instance.id} on #{driver_url}) to be ready ..."
|
840
|
-
while time_elapsed <
|
839
|
+
while time_elapsed < max_wait_time && !yield(instance)
|
841
840
|
action_handler.report_progress "been waiting #{time_elapsed}/#{max_wait_time} -- sleeping #{sleep_time} seconds for #{machine_spec.name} (#{instance.id} on #{driver_url}) to be ready ..."
|
842
841
|
sleep(sleep_time)
|
843
842
|
time_elapsed += sleep_time
|
844
843
|
end
|
844
|
+
unless yield(instance)
|
845
|
+
raise "Image #{instance.id} did not become ready within 120 seconds"
|
846
|
+
end
|
845
847
|
action_handler.report_progress "#{machine_spec.name} is now ready"
|
846
848
|
end
|
847
849
|
end
|
@@ -856,7 +858,7 @@ EOD
|
|
856
858
|
unless transport.available?
|
857
859
|
if action_handler.should_perform_actions
|
858
860
|
action_handler.report_progress "waiting for #{machine_spec.name} (#{instance.id} on #{driver_url}) to be connectable (transport up and running) ..."
|
859
|
-
while time_elapsed <
|
861
|
+
while time_elapsed < max_wait_time && !transport.available?
|
860
862
|
action_handler.report_progress "been waiting #{time_elapsed}/#{max_wait_time} -- sleeping #{sleep_time} seconds for #{machine_spec.name} (#{instance.id} on #{driver_url}) to be connectable ..."
|
861
863
|
sleep(sleep_time)
|
862
864
|
time_elapsed += sleep_time
|
@@ -868,8 +870,8 @@ EOD
|
|
868
870
|
end
|
869
871
|
|
870
872
|
def default_aws_keypair_name(machine_spec)
|
871
|
-
if machine_spec.
|
872
|
-
Gem::Version.new(machine_spec.
|
873
|
+
if machine_spec.reference &&
|
874
|
+
Gem::Version.new(machine_spec.reference['driver_version']) < Gem::Version.new('0.10')
|
873
875
|
'metal_default'
|
874
876
|
else
|
875
877
|
'chef_default'
|
@@ -908,8 +910,8 @@ EOD
|
|
908
910
|
yield machine_spec, actual_instance if block_given?
|
909
911
|
next
|
910
912
|
end
|
911
|
-
elsif machine_spec.
|
912
|
-
Chef::Log.warn "Machine #{machine_spec.name} (#{machine_spec.
|
913
|
+
elsif machine_spec.reference
|
914
|
+
Chef::Log.warn "Machine #{machine_spec.name} (#{machine_spec.reference['instance_id']} on #{driver_url}) no longer exists. Recreating ..."
|
913
915
|
end
|
914
916
|
|
915
917
|
bootstrap_options = bootstrap_options_for(action_handler, machine_spec, machine_options)
|
@@ -934,7 +936,7 @@ EOD
|
|
934
936
|
# Assign each one to a machine spec
|
935
937
|
machine_spec = machine_specs.pop
|
936
938
|
machine_options = specs_and_options[machine_spec]
|
937
|
-
machine_spec.
|
939
|
+
machine_spec.reference = {
|
938
940
|
'driver_url' => driver_url,
|
939
941
|
'driver_version' => Chef::Provisioning::AWSDriver::VERSION,
|
940
942
|
'allocated_at' => Time.now.utc.to_s,
|
@@ -943,9 +945,9 @@ EOD
|
|
943
945
|
'instance_id' => instance.id
|
944
946
|
}
|
945
947
|
instance.tags['Name'] = machine_spec.name
|
946
|
-
machine_spec.
|
948
|
+
machine_spec.reference['key_name'] = bootstrap_options[:key_name] if bootstrap_options[:key_name]
|
947
949
|
%w(is_windows ssh_username sudo use_private_ip_for_ssh ssh_gateway).each do |key|
|
948
|
-
machine_spec.
|
950
|
+
machine_spec.reference[key] = machine_options[key.to_sym] if machine_options[key.to_sym]
|
949
951
|
end
|
950
952
|
action_handler.performed_action "machine #{machine_spec.name} created as #{instance.id} on #{driver_url}"
|
951
953
|
|
@@ -969,19 +971,79 @@ EOD
|
|
969
971
|
end.to_a
|
970
972
|
end
|
971
973
|
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
974
|
+
def get_listeners(listeners)
|
975
|
+
case listeners
|
976
|
+
when Hash
|
977
|
+
listeners.map do |from, to|
|
978
|
+
from = get_listener(from)
|
979
|
+
from.delete(:instance_port)
|
980
|
+
from.delete(:instance_protocol)
|
981
|
+
to = get_listener(to)
|
982
|
+
to.delete(:port)
|
983
|
+
to.delete(:protocol)
|
984
|
+
to.merge(from)
|
981
985
|
end
|
986
|
+
when Array
|
987
|
+
listeners.map { |listener| get_listener(listener) }
|
988
|
+
when nil
|
989
|
+
nil
|
990
|
+
else
|
991
|
+
[ get_listener(listeners) ]
|
982
992
|
end
|
983
993
|
end
|
984
994
|
|
995
|
+
def get_listener(listener)
|
996
|
+
result = {}
|
997
|
+
|
998
|
+
case listener
|
999
|
+
when Hash
|
1000
|
+
result.merge!(listener)
|
1001
|
+
when Array
|
1002
|
+
result[:port] = listener[0] if listener.size >= 1
|
1003
|
+
result[:protocol] = listener[1] if listener.size >= 2
|
1004
|
+
when Symbol,String
|
1005
|
+
result[:protocol] = listener
|
1006
|
+
when Integer
|
1007
|
+
result[:port] = listener
|
1008
|
+
else
|
1009
|
+
raise "Invalid listener #{listener}"
|
1010
|
+
end
|
1011
|
+
|
1012
|
+
# If either port or protocol are set, set the other
|
1013
|
+
if result[:port] && !result[:protocol]
|
1014
|
+
result[:protocol] = PROTOCOL_DEFAULTS[result[:port]]
|
1015
|
+
elsif result[:protocol] && !result[:port]
|
1016
|
+
result[:port] = PORT_DEFAULTS[result[:protocol]]
|
1017
|
+
end
|
1018
|
+
if result[:instance_port] && !result[:instance_protocol]
|
1019
|
+
result[:instance_protocol] = PROTOCOL_DEFAULTS[result[:instance_port]]
|
1020
|
+
elsif result[:instance_protocol] && !result[:instance_port]
|
1021
|
+
result[:instance_port] = PORT_DEFAULTS[result[:instance_protocol]]
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
# If instance_port is still unset, copy port/protocol over
|
1025
|
+
result[:instance_port] ||= result[:port]
|
1026
|
+
result[:instance_protocol] ||= result[:protocol]
|
1027
|
+
|
1028
|
+
result
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
def default_instance_type
|
1032
|
+
't1.micro'
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
PORT_DEFAULTS = {
|
1036
|
+
:http => 80,
|
1037
|
+
:https => 443,
|
1038
|
+
}
|
1039
|
+
PROTOCOL_DEFAULTS = {
|
1040
|
+
25 => :tcp,
|
1041
|
+
80 => :http,
|
1042
|
+
443 => :https,
|
1043
|
+
465 => :ssl,
|
1044
|
+
587 => :tcp,
|
1045
|
+
}
|
1046
|
+
|
985
1047
|
end
|
986
1048
|
end
|
987
1049
|
end
|