cloud-mu 3.1.4 → 3.1.5

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/ansible/roles/mu-windows/README.md +33 -0
  3. data/ansible/roles/mu-windows/defaults/main.yml +2 -0
  4. data/ansible/roles/mu-windows/handlers/main.yml +2 -0
  5. data/ansible/roles/mu-windows/meta/main.yml +53 -0
  6. data/ansible/roles/mu-windows/tasks/main.yml +20 -0
  7. data/ansible/roles/mu-windows/tests/inventory +2 -0
  8. data/ansible/roles/mu-windows/tests/test.yml +5 -0
  9. data/ansible/roles/mu-windows/vars/main.yml +2 -0
  10. data/cloud-mu.gemspec +4 -2
  11. data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
  12. data/cookbooks/mu-tools/recipes/windows-client.rb +140 -144
  13. data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
  14. data/extras/image-generators/AWS/win2k12.yaml +16 -13
  15. data/extras/image-generators/AWS/win2k16.yaml +16 -13
  16. data/extras/image-generators/AWS/win2k19.yaml +19 -0
  17. data/modules/mu.rb +72 -9
  18. data/modules/mu/adoption.rb +14 -2
  19. data/modules/mu/cloud.rb +111 -10
  20. data/modules/mu/clouds/aws.rb +23 -7
  21. data/modules/mu/clouds/aws/container_cluster.rb +640 -692
  22. data/modules/mu/clouds/aws/dnszone.rb +49 -45
  23. data/modules/mu/clouds/aws/firewall_rule.rb +177 -214
  24. data/modules/mu/clouds/aws/role.rb +17 -8
  25. data/modules/mu/clouds/aws/search_domain.rb +1 -1
  26. data/modules/mu/clouds/aws/server.rb +734 -1027
  27. data/modules/mu/clouds/aws/userdata/windows.erb +2 -1
  28. data/modules/mu/clouds/aws/vpc.rb +297 -786
  29. data/modules/mu/clouds/aws/vpc_subnet.rb +286 -0
  30. data/modules/mu/clouds/google/bucket.rb +1 -1
  31. data/modules/mu/clouds/google/container_cluster.rb +21 -17
  32. data/modules/mu/clouds/google/function.rb +8 -2
  33. data/modules/mu/clouds/google/server.rb +102 -32
  34. data/modules/mu/clouds/google/vpc.rb +1 -1
  35. data/modules/mu/config.rb +12 -1
  36. data/modules/mu/config/server.yml +1 -0
  37. data/modules/mu/defaults/AWS.yaml +51 -28
  38. data/modules/mu/groomers/ansible.rb +54 -17
  39. data/modules/mu/groomers/chef.rb +13 -7
  40. data/modules/mu/master/ssl.rb +0 -1
  41. data/modules/mu/mommacat.rb +8 -0
  42. data/modules/tests/ecs.yaml +23 -0
  43. data/modules/tests/includes-and-params.yaml +2 -1
  44. data/modules/tests/server-with-scrub-muisms.yaml +1 -0
  45. data/modules/tests/win2k12.yaml +25 -0
  46. data/modules/tests/win2k16.yaml +25 -0
  47. data/modules/tests/win2k19.yaml +25 -0
  48. data/requirements.txt +1 -0
  49. metadata +50 -4
  50. data/extras/image-generators/AWS/windows.yaml +0 -18
  51. data/modules/tests/needwork/win2k12.yaml +0 -13
@@ -23,7 +23,7 @@ function log
23
23
  }
24
24
 
25
25
  function fetchSecret([string]$file){
26
- log "Fetching s3://<%= $mu.adminBucketName %>/$file to $tmp/$file"
26
+ log "aws.cmd --region $region s3 cp s3://<%= $mu.adminBucketName %>/$file $tmp/$file"
27
27
  aws.cmd --region $region s3 cp s3://<%= $mu.adminBucketName %>/$file $tmp/$file
28
28
  }
29
29
 
@@ -245,6 +245,7 @@ if($ingroup -ne $admin_username){
245
245
  net localgroup WinRMRemoteWMIUsers__ /add $admin_username
246
246
  }
247
247
 
248
+ importCert "$myname-winrm.crt" "root"
248
249
  $winrmcert = importCert "$myname-winrm.crt" "TrustedPeople"
249
250
  Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true
250
251
  Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name LocalAccountTokenFilterPolicy -Value 1
@@ -18,6 +18,7 @@ module MU
18
18
 
19
19
  # Creation of Virtual Private Clouds and associated artifacts (routes, subnets, etc).
20
20
  class VPC < MU::Cloud::VPC
21
+ require 'mu/clouds/aws/vpc_subnet'
21
22
 
22
23
  # Initialize this cloud resource object. Calling +super+ will invoke the initializer defined under {MU::Cloud}, which should set the attribtues listed in {MU::Cloud::PUBLIC_ATTRS} as well as applicable dependency shortcuts, like +@vpc+, for us.
23
24
  # @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
@@ -35,78 +36,40 @@ module MU
35
36
  def create
36
37
  MU.log "Creating VPC #{@mu_name}", details: @config
37
38
  resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_vpc(cidr_block: @config['ip_block']).vpc
38
- vpc_id = @config['vpc_id'] = resp.vpc_id
39
+ @cloud_id = resp.vpc_id
40
+ @config['vpc_id'] = @cloud_id
39
41
 
40
- MU::Cloud::AWS.createStandardTags(vpc_id, region: @config['region'], credentials: @config['credentials'])
41
- MU::Cloud::AWS.createTag(vpc_id, "Name", @mu_name, region: @config['region'], credentials: @config['credentials'])
42
-
43
- if @config['tags']
44
- @config['tags'].each { |tag|
45
- MU::Cloud::AWS.createTag(vpc_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
46
- }
47
- end
48
-
49
- if @config['optional_tags']
50
- MU::MommaCat.listOptionalTags.each { |key, value|
51
- MU::Cloud::AWS.createTag(vpc_id, key, value, region: @config['region'], credentials: @config['credentials'])
52
- }
53
- end
42
+ tag_me
54
43
 
55
44
  if resp.state != "available"
56
45
  begin
57
- MU.log "Waiting for VPC #{@mu_name} (#{vpc_id}) to be available", MU::NOTICE
46
+ MU.log "Waiting for VPC #{@mu_name} (#{@cloud_id}) to be available", MU::NOTICE
58
47
  sleep 5
59
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpcs(vpc_ids: [vpc_id]).vpcs.first
48
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpcs(vpc_ids: [@cloud_id]).vpcs.first
60
49
  end while resp.state != "available"
61
50
  # There's a default route table that comes with. Let's tag it.
62
51
  resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
63
52
  filters: [
64
53
  {
65
54
  name: "vpc-id",
66
- values: [vpc_id]
55
+ values: [@cloud_id]
67
56
  }
68
57
  ]
69
58
  )
70
59
  resp.route_tables.each { |rtb|
71
- MU::Cloud::AWS.createTag(rtb.route_table_id, "Name", @mu_name+"-#DEFAULTPRIV", region: @config['region'], credentials: @config['credentials'])
72
- if @config['tags']
73
- @config['tags'].each { |tag|
74
- MU::Cloud::AWS.createTag(rtb.route_table_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
75
- }
76
- end
77
-
78
- MU::Cloud::AWS.createStandardTags(rtb.route_table_id, region: @config['region'], credentials: @config['credentials'])
79
-
80
- if @config['optional_tags']
81
- MU::MommaCat.listOptionalTags.each { |key, value|
82
- MU::Cloud::AWS.createTag(rtb.route_table_id, key, value, region: @config['region'], credentials: @config['credentials'])
83
- }
84
- end
60
+ tag_me(rtb.route_table_id, @mu_name+"-#DEFAULTPRIV")
85
61
  }
86
62
  end
87
- @config['vpc_id'] = vpc_id
88
- @cloud_id = vpc_id
89
63
 
90
64
  if @config['create_internet_gateway']
91
65
  MU.log "Creating Internet Gateway #{@mu_name}"
92
66
  resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_internet_gateway
93
67
  internet_gateway_id = resp.internet_gateway.internet_gateway_id
94
68
  sleep 5
95
- MU::Cloud::AWS.createStandardTags(internet_gateway_id, region: @config['region'], credentials: @config['credentials'])
96
- MU::Cloud::AWS.createTag(internet_gateway_id, "Name", @mu_name, region: @config['region'], credentials: @config['credentials'])
97
- if @config['tags']
98
- @config['tags'].each { |tag|
99
- MU::Cloud::AWS.createTag(internet_gateway_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
100
- }
101
- end
102
69
 
103
- if @config['optional_tags']
104
- MU::MommaCat.listOptionalTags.each { |key, value|
105
- MU::Cloud::AWS.createTag(internet_gateway_id, key, value, region: @config['region'], credentials: @config['credentials'])
106
- }
107
- end
70
+ tag_me(internet_gateway_id)
108
71
 
109
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).attach_internet_gateway(vpc_id: vpc_id, internet_gateway_id: internet_gateway_id)
72
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).attach_internet_gateway(vpc_id: @cloud_id, internet_gateway_id: internet_gateway_id)
110
73
  @config['internet_gateway_id'] = internet_gateway_id
111
74
  end
112
75
 
@@ -165,236 +128,35 @@ module MU
165
128
  )
166
129
  end
167
130
 
168
- nat_gateways = []
169
- if !@config['subnets'].nil?
170
- allocation_ids = []
171
- subnetthreads = Array.new
172
- parent_thread_id = Thread.current.object_id
173
- azs = []
174
- @config['subnets'].each { |subnet|
175
- subnet_name = @config['name']+"-"+subnet['name']
176
- MU.log "Creating Subnet #{subnet_name} (#{subnet['ip_block']})", details: subnet
177
- azs = MU::Cloud::AWS.listAZs(region: @config['region'], credentials: @config['credentials']) if azs.size == 0
178
- if !subnet['availability_zone'].nil?
179
- az = subnet['availability_zone']
180
- else
181
- az = azs.pop
182
- end
183
-
184
- subnetthreads << Thread.new {
185
- MU.dupGlobals(parent_thread_id)
186
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_subnet(
187
- vpc_id: vpc_id,
188
- cidr_block: subnet['ip_block'],
189
- availability_zone: az
190
- ).subnet
191
- subnet_id = subnet['subnet_id'] = resp.subnet_id
192
- MU::Cloud::AWS.createStandardTags(subnet_id, region: @config['region'], credentials: @config['credentials'])
193
- MU::Cloud::AWS.createTag(subnet_id, "Name", @mu_name+"-"+subnet['name'], region: @config['region'], credentials: @config['credentials'])
194
- if @config['tags']
195
- @config['tags'].each { |tag|
196
- MU::Cloud::AWS.createTag(subnet_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
197
- }
198
- end
199
-
200
- if @config['optional_tags']
201
- MU::MommaCat.listOptionalTags.each { |key, value|
202
- MU::Cloud::AWS.createTag(subnet_id, key, value, region: @config['region'], credentials: @config['credentials'])
203
- }
204
- end
205
-
206
- retries = 0
207
- begin
208
- if resp.state != "available"
209
- begin
210
- MU.log "Waiting for Subnet #{subnet_name} (#{subnet_id}) to be available", MU::NOTICE if retries > 0 and (retries % 3) == 0
211
- sleep 5
212
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
213
- rescue Aws::EC2::Errors::InvalidSubnetIDNotFound => e
214
- sleep 10
215
- retry
216
- end while resp.state != "available"
217
- end
218
- rescue NoMethodError => e
219
- if retries <= 3
220
- MU.log "Got bogus Aws::EmptyResponse error on #{subnet_id} (retries used: #{retries}/3)", MU::WARN
221
- retries = retries + 1
222
- sleep 5
223
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
224
- retry
225
- else
226
- raise e
227
- end
228
- end
229
-
230
- if !subnet['route_table'].nil?
231
- routes = {}
232
- @config['route_tables'].each { |tbl|
233
- routes[tbl['name']] = tbl
234
- }
235
- if routes.nil? or routes[subnet['route_table']].nil?
236
- MU.log "Subnet #{subnet_name} references non-existent route #{subnet['route_table']}", MU::ERR, details: @deploy.deployment['vpcs']
237
- raise MuError, "deploy failure"
238
- end
239
- MU.log "Associating Route Table '#{subnet['route_table']}' (#{routes[subnet['route_table']]['route_table_id']}) with #{subnet_name}"
240
- retries = 0
241
- begin
242
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).associate_route_table(
243
- route_table_id: routes[subnet['route_table']]['route_table_id'],
244
- subnet_id: subnet_id
245
- )
246
- rescue Aws::EC2::Errors::InvalidRouteTableIDNotFound => e
247
- retries = retries + 1
248
- if retries < 10
249
- sleep 10
250
- retry
251
- else
252
- raise MuError, e.inspect
253
- end
254
- end
255
- end
256
- retries = 0
257
- begin
258
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
259
- rescue Aws::EC2::Errors::InvalidSubnetIDNotFound => e
260
- if retries < 10
261
- MU.log "Got #{e.inspect}, waiting and retrying", MU::WARN
262
- sleep 10
263
- retries = retries + 1
264
- retry
265
- end
266
- raise MuError, e.inspect, e.backtrace
267
- end
268
-
269
- if subnet['is_public'] && subnet['create_nat_gateway']
270
- MU::MommaCat.lock("nat-gateway-eipalloc")
271
- filters = [{name: "domain", values: ["vpc"]}]
272
- eips = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_addresses(filters: filters).addresses
273
- allocation_id = nil
274
- eips.each { |eip|
275
- next if !eip.association_id.nil? and !eip.association_id.empty?
276
- if (eip.private_ip_address.nil? || eip.private_ip_address.empty?) and MU::MommaCat.lock(eip.allocation_id, true, true)
277
- if !allocation_ids.include?(eip.allocation_id)
278
- allocation_id = eip.allocation_id
279
- break
280
- end
281
- end
282
- }
283
-
284
- if allocation_id.nil?
285
- allocation_id = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).allocate_address(domain: "vpc").allocation_id
286
- MU::MommaCat.lock(allocation_id, false, true)
287
- end
288
-
289
- allocation_ids << allocation_id
290
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_nat_gateway(
291
- subnet_id: subnet['subnet_id'],
292
- allocation_id: allocation_id,
293
- ).nat_gateway
294
-
295
- nat_gateway_id = resp.nat_gateway_id
296
- attempts = 0
297
- MU::MommaCat.unlock("nat-gateway-eipalloc")
298
- while resp.class.name != "Aws::EC2::Types::NatGateway" or resp.state == "pending"
299
- MU.log "Waiting for nat gateway #{nat_gateway_id} () to become available (EIP allocation: #{allocation_id})" if attempts % 5 == 0
300
- sleep 30
301
- begin
302
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_nat_gateways(nat_gateway_ids: [nat_gateway_id]).nat_gateways.first
303
- rescue Aws::EmptyStructure, NoMethodError
304
- sleep 5
305
- retry
306
- end
307
- if attempts > 30
308
- MU::MommaCat.unlock(allocation_id, true)
309
- raise MuError, "Timed out while waiting for NAT Gateway #{nat_gateway_id}: #{resp}"
310
- end
311
- attempts += 1
312
- end
313
- MU::MommaCat.unlock(allocation_id, true)
314
-
315
- raise MuError, "NAT Gateway failed #{nat_gateway_id}: #{resp}" if resp.state == "failed"
316
- nat_gateways << {'id' => nat_gateway_id, 'availability_zone' => subnet['availability_zone']}
317
- @tags.each_pair { |k, v|
318
- MU::Cloud::AWS.createTag(nat_gateway_id, k, v, region: @config['region'], credentials: @config['credentials'])
319
- }
320
- end
321
-
322
- if subnet.has_key?("map_public_ips")
323
- retries = 0
324
- begin
325
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_subnet_attribute(
326
- subnet_id: subnet_id,
327
- map_public_ip_on_launch: {
328
- value: subnet['map_public_ips'],
329
- }
330
- )
331
- rescue Aws::EC2::Errors::InvalidSubnetIDNotFound => e
332
- if retries < 10
333
- MU.log "Got #{e.inspect} while trying to enable map_public_ips on subnet, waiting and retrying", MU::WARN
334
- sleep 10
335
- retries += 1
336
- retry
337
- end
338
- raise MuError, "Got #{e.inspect}, #{e.backtrace} while trying to enable map_public_ips on subnet"
339
- end
340
- end
341
-
342
- if subnet["enable_traffic_logging"]
343
- loggroup = @deploy.findLitterMate(name: @config['name']+"loggroup", type: "logs")
344
- logrole = @deploy.findLitterMate(name: @config['name']+"logrole", type: "roles")
345
- MU.log "Enabling traffic logging on Subnet #{subnet_name} in VPC #{@mu_name} to log group #{loggroup.mu_name}"
346
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_flow_logs(
347
- resource_ids: [subnet_id],
348
- resource_type: "Subnet",
349
- traffic_type: subnet["traffic_type_to_log"],
350
- log_group_name: loggroup.mu_name,
351
- deliver_logs_permission_arn: logrole.cloudobj.arn
352
- )
353
- end
354
- }
355
- }
131
+ nat_gateways = create_subnets
356
132
 
357
- subnetthreads.each { |t|
358
- t.join
359
- }
360
-
361
- notify
362
- end
133
+ notify
363
134
 
364
135
  if !nat_gateways.empty?
365
136
  nat_gateways.each { |gateway|
366
137
  @config['subnets'].each { |subnet|
367
- if subnet['is_public'] == false && subnet['availability_zone'] == gateway['availability_zone']
368
- @config['route_tables'].each { |rtb|
369
- if rtb['name'] == subnet['route_table']
370
- rtb['routes'].each { |route|
371
- if route['gateway'] == '#NAT'
372
- route_config = {
373
- :route_table_id => rtb['route_table_id'],
374
- :destination_cidr_block => route['destination_network'],
375
- :nat_gateway_id => gateway['id']
376
- }
377
-
378
- MU.log "Creating route for #{route['destination_network']} through NAT gatway #{gateway['id']}", details: route_config
379
- nat_retries = 0
380
- begin
381
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(route_config)
382
- rescue Aws::EC2::Errors::InvalidNatGatewayIDNotFound => e
383
- if nat_retries < 5
384
- nat_retries += 1
385
- sleep 10
386
- retry
387
- else
388
- raise e
389
- end
390
- rescue Aws::EC2::Errors::RouteAlreadyExists => e
391
- MU.log "Attempt to create duplicate route to #{route['destination_network']} for #{gateway['id']} in #{rtb['route_table_id']}", MU::WARN
392
- end
393
- end
394
- }
395
- end
138
+ next if subnet['is_public'] != false or subnet['availability_zone'] != gateway['availability_zone']
139
+
140
+ @config['route_tables'].each { |rtb|
141
+ next if rtb['name'] != subnet['route_table']
142
+ rtb['routes'].each { |route|
143
+ next if route['gateway'] != '#NAT'
144
+ route_config = {
145
+ :route_table_id => rtb['route_table_id'],
146
+ :destination_cidr_block => route['destination_network'],
147
+ :nat_gateway_id => gateway['id']
148
+ }
149
+
150
+ MU.log "Creating route for #{route['destination_network']} through NAT gatway #{gateway['id']}", details: route_config
151
+ MU.retrier([Aws::EC2::Errors::InvalidNatGatewayIDNotFound], wait: 10, max: 5) {
152
+ begin
153
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(route_config)
154
+ rescue Aws::EC2::Errors::RouteAlreadyExists
155
+ MU.log "Attempt to create duplicate route to #{route['destination_network']} for #{gateway['id']} in #{rtb['route_table_id']}", MU::WARN
156
+ end
157
+ }
396
158
  }
397
- end
159
+ }
398
160
  }
399
161
  }
400
162
  end
@@ -402,14 +164,14 @@ module MU
402
164
  if @config['enable_dns_support']
403
165
  MU.log "Enabling DNS support in #{@mu_name}"
404
166
  MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_vpc_attribute(
405
- vpc_id: vpc_id,
167
+ vpc_id: @cloud_id,
406
168
  enable_dns_support: {value: @config['enable_dns_support']}
407
169
  )
408
170
  end
409
171
  if @config['enable_dns_hostnames']
410
172
  MU.log "Enabling DNS hostnames in #{@mu_name}"
411
173
  MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_vpc_attribute(
412
- vpc_id: vpc_id,
174
+ vpc_id: @cloud_id,
413
175
  enable_dns_hostnames: {value: @config['enable_dns_hostnames']}
414
176
  )
415
177
  end
@@ -438,29 +200,16 @@ module MU
438
200
  dhcp_configurations: dhcpopts
439
201
  )
440
202
  dhcpopt_id = resp.dhcp_options.dhcp_options_id
441
- MU::Cloud::AWS.createStandardTags(dhcpopt_id, region: @config['region'], credentials: @config['credentials'])
442
- MU::Cloud::AWS.createTag(dhcpopt_id, "Name", @mu_name, region: @config['region'], credentials: @config['credentials'])
443
-
444
- if @config['tags']
445
- @config['tags'].each { |tag|
446
- MU::Cloud::AWS.createTag(dhcpopt_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
447
- }
448
- end
203
+ tag_me(dhcpopt_id)
449
204
 
450
- if @config['optional_tags']
451
- MU::MommaCat.listOptionalTags.each { |key, value|
452
- MU::Cloud::AWS.createTag(dhcpopt_id, key, value, region: @config['region'], credentials: @config['credentials'])
453
- }
454
- end
455
-
456
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).associate_dhcp_options(dhcp_options_id: dhcpopt_id, vpc_id: vpc_id)
205
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).associate_dhcp_options(dhcp_options_id: dhcpopt_id, vpc_id: @cloud_id)
457
206
  end
458
207
  notify
459
208
 
460
209
  if !MU::Cloud::AWS.isGovCloud?(@config['region'])
461
210
  mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu", credentials: @config['credentials']).values.first
462
211
  if !mu_zone.nil?
463
- MU::Cloud::AWS::DNSZone.toggleVPCAccess(id: mu_zone.id, vpc_id: vpc_id, region: @config['region'], credentials: @config['credentials'])
212
+ MU::Cloud::AWS::DNSZone.toggleVPCAccess(id: mu_zone.id, vpc_id: @cloud_id, region: @config['region'], credentials: @config['credentials'])
464
213
  end
465
214
  end
466
215
  loadSubnets
@@ -471,9 +220,6 @@ module MU
471
220
  # Canonical Amazon Resource Number for this resource
472
221
  # @return [String]
473
222
  def arn
474
- puts @config['region']
475
- puts MU::Cloud::AWS.credToAcct(@config['credentials'])
476
- puts @cloud_id
477
223
  "arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":ec2:"+@config['region']+":"+MU::Cloud::AWS.credToAcct(@config['credentials'])+":vpc/"+@cloud_id
478
224
  end
479
225
 
@@ -490,202 +236,7 @@ module MU
490
236
  # Generate peering connections
491
237
  if !@config['peers'].nil? and @config['peers'].size > 0
492
238
  @config['peers'].each { |peer|
493
- peer_obj = nil
494
- peer_id = nil
495
- peer['name'] ||= peer['vpc_name']
496
- peer['id'] ||= peer['vpc_id']
497
-
498
- # If we know this to be a sibling VPC elsewhere in our stack,
499
- # go fetch it, and fix it if we've been misconfigured with a
500
- # duplicate peering connection
501
- if peer['vpc']['name'] and !peer['account']
502
- peer_obj = @deploy.findLitterMate(name: peer['vpc']['name'], type: "vpcs")
503
- if peer_obj
504
- if peer_obj.config['peers']
505
- skipme = false
506
- peer_obj.config['peers'].each { |peerpeer|
507
- if peerpeer['vpc']['name'] == @config['name'] and
508
- (peer['vpc']['name'] <=> @config['name']) == -1
509
- skipme = true
510
- MU.log "VPCs #{peer['vpc']['name']} and #{@config['name']} both declare mutual peering connection, ignoring #{@config['name']}'s redundant declaration", MU::DEBUG
511
- # XXX and if deploy_id matches or is unset
512
- end
513
- }
514
- end
515
- next if skipme
516
- peer['account'] = MU::Cloud::AWS.credToAcct(peer_obj.credentials)
517
- peer['vpc']['id'] = peer_obj.cloud_id
518
- peer['vpc']['region'] ||= peer_obj.config['region']
519
- end
520
- end
521
-
522
- # If we still don't know our peer's vpc identifier, go fishing
523
- if !peer_obj
524
- tag_key, tag_value = peer['vpc']['tag'].split(/=/, 2) if !peer['vpc']['tag'].nil?
525
- if peer['vpc']['deploy_id'].nil? and peer['vpc']['id'].nil? and tag_key.nil?
526
- peer['vpc']['deploy_id'] = @deploy.deploy_id
527
- end
528
- peer_obj = MU::MommaCat.findStray(
529
- "AWS",
530
- "vpcs",
531
- deploy_id: peer['vpc']['deploy_id'],
532
- cloud_id: peer['vpc']['id'],
533
- # XXX we need a credentials argument here... maybe
534
- name: peer['vpc']['name'],
535
- tag_key: tag_key,
536
- tag_value: tag_value,
537
- dummy_ok: true,
538
- region: peer['vpc']['region']
539
- )
540
- MU.log "wtf", MU::ERR, details: peer if peer_obj.nil? or peer_obj.first.nil?
541
- raise MuError, "No result looking for #{@mu_name}'s peer VPCs (#{peer['vpc']})" if peer_obj.nil? or peer_obj.first.nil?
542
- peer_obj = peer_obj.first
543
- peer['account'] ||= MU::Cloud::AWS.credToAcct(peer_obj.credentials)
544
- peer['vpc']['id'] ||= peer_obj.cloud_id
545
- peer['vpc']['region'] ||= peer_obj.config['region']
546
- end
547
-
548
- peer_id = peer['vpc']['id']
549
- peer['account'] ||= MU::Cloud::AWS.account_number
550
-
551
- # See if the peering connection exists before we bother
552
- # creating it.
553
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
554
- filters: [
555
- {
556
- name: "requester-vpc-info.vpc-id",
557
- values: [@cloud_id]
558
- },
559
- {
560
- name: "accepter-vpc-info.vpc-id",
561
- values: [peer_id.to_s]
562
- }
563
- ]
564
- )
565
-
566
- peering_id = if !resp or !resp.vpc_peering_connections or
567
- resp.vpc_peering_connections.empty?
568
-
569
- MU.log "Setting peering connection from VPC #{@config['name']} (#{@cloud_id} in account #{MU::Cloud::AWS.credToAcct(@config['credentials'])}) to #{peer_id} in account #{peer['account']}", details: peer
570
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_vpc_peering_connection(
571
- vpc_id: @cloud_id,
572
- peer_vpc_id: peer_id,
573
- peer_owner_id: peer['account'],
574
- peer_region: peer['vpc']['region']
575
- )
576
- resp.vpc_peering_connection.vpc_peering_connection_id
577
- else
578
- resp.vpc_peering_connections.first.vpc_peering_connection_id
579
- end
580
-
581
- peering_name = @deploy.getResourceName(@config['name']+"-PEER-"+peer['vpc']['id'])
582
-
583
- MU::Cloud::AWS.createStandardTags(peering_id, region: @config['region'], credentials: @config['credentials'])
584
- MU::Cloud::AWS.createTag(peering_id, "Name", peering_name, region: @config['region'], credentials: @config['credentials'])
585
-
586
- if @config['optional_tags']
587
- MU::MommaCat.listOptionalTags.each { |key, value|
588
- MU::Cloud::AWS.createTag(peering_id, key, value, region: @config['region'], credentials: @config['credentials'])
589
- }
590
- end
591
-
592
- if @config['tags']
593
- @config['tags'].each { |tag|
594
- MU::Cloud::AWS.createTag(peering_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
595
- }
596
- end
597
-
598
- # Create routes to our new friend.
599
- MU::Cloud::AWS::VPC.listAllSubnetRouteTables(@cloud_id, region: @config['region'], credentials: @config['credentials']).each { |rtb_id|
600
- my_route_config = {
601
- :route_table_id => rtb_id,
602
- :destination_cidr_block => peer_obj.cloud_desc.cidr_block,
603
- :vpc_peering_connection_id => peering_id
604
- }
605
- rtbdesc = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
606
- route_table_ids: [rtb_id]
607
- ).route_tables.first
608
- already_exists = false
609
- rtbdesc.routes.each { |r|
610
- if r.destination_cidr_block == peer_obj.cloud_desc.cidr_block
611
- if r.vpc_peering_connection_id != peering_id
612
- MU.log "Attempt to create duplicate route to #{peer_obj.cloud_desc.cidr_block} from VPC #{@config['name']}", MU::ERR, details: r
613
- raise MuError, "Can't create route via #{peering_id}, a route to #{peer_obj.cloud_desc.cidr_block} already exists"
614
- else
615
- already_exists = true
616
- end
617
- end
618
- }
619
- next if already_exists
620
-
621
- MU.log "Creating peering route to #{peer_obj.cloud_desc.cidr_block} in #{peer['vpc']['region']} from VPC #{@config['name']} in #{@config['region']}"
622
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(my_route_config)
623
- } # MU::Cloud::AWS::VPC.listAllSubnetRouteTables
624
-
625
- begin
626
- cnxn = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
627
- vpc_peering_connection_ids: [peering_id]
628
- ).vpc_peering_connections.first
629
-
630
- if cnxn.status.code == "pending-acceptance"
631
- if ((!peer_obj.nil? and !peer_obj.deploydata.nil? and peer_obj.deploydata['auto_accept_peers']) or $MU_CFG['allow_invade_foreign_vpcs'])
632
- MU.log "Auto-accepting peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id}", MU::NOTICE
633
- begin
634
- MU::Cloud::AWS.ec2(region: peer['vpc']['region'], credentials: peer['account']).accept_vpc_peering_connection(
635
- vpc_peering_connection_id: peering_id,
636
- )
637
- if peer['account'] != MU::Cloud::AWS.credToAcct(@config['credentials'])
638
- # this seems to take a while across accounts
639
- sleep 5
640
- end
641
- cnxn = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
642
- vpc_peering_connection_ids: [peering_id]
643
- ).vpc_peering_connections.first
644
- rescue Aws::EC2::Errors::VpcPeeringConnectionAlreadyExists => e
645
- MU.log "Attempt to create duplicate peering connection to #{peer_id} from VPC #{@config['name']}", MU::WARN
646
- end
647
-
648
- # Create routes back from our new friend to us.
649
- MU::Cloud::AWS::VPC.listAllSubnetRouteTables(peer_id, region: peer['vpc']['region'], credentials: peer['account']).uniq.each { |rtb_id|
650
- peer_route_config = {
651
- :route_table_id => rtb_id,
652
- :destination_cidr_block => @config['ip_block'],
653
- :vpc_peering_connection_id => peering_id
654
- }
655
- begin
656
- resp = MU::Cloud::AWS.ec2(region: peer['vpc']['region'], credentials: peer['account']).create_route(peer_route_config)
657
- rescue Aws::EC2::Errors::RouteAlreadyExists => e
658
- rtbdesc = MU::Cloud::AWS.ec2(region: peer['vpc']['region'], credentials: peer['account']).describe_route_tables(
659
- route_table_ids: [rtb_id]
660
- ).route_tables.first
661
- rtbdesc.routes.each { |r|
662
- if r.destination_cidr_block == @config['ip_block']
663
- if r.vpc_peering_connection_id != peering_id
664
- MU.log "Attempt to create duplicate route to VPC #{@config['name']} (#{@config['ip_block']}) from peer VPC #{peer_id}'s route table #{rtb_id}", MU::ERR
665
- end
666
- end
667
- }
668
- end
669
- }
670
- else
671
- MU.log "VPC #{peer_id} is not managed by this Mu server or is not configured to auto-accept peering requests. You must accept the peering request for '#{@config['name']}' (#{@cloud_id}) by hand.", MU::WARN, details: "In the AWS Console, go to VPC => Peering Connections and look in the Actions drop-down. You can also set 'Invade Foreign VPCs' to 'true' using mu-configure to auto-accept all peering connections within this account, regardless of whether this Mu server owns the VPCs. This setting is per-user."
672
- end
673
- end
674
-
675
- if cnxn.status.code == "failed" or cnxn.status.code == "rejected" or cnxn.status.code == "expired" or cnxn.status.code == "deleted"
676
- MU.log "VPC peering connection from VPC #{@config['name']} (#{@cloud_id} in #{@config['region']}) to #{peer_id} in #{peer['vpc']['region']} #{cnxn.status.code}: #{cnxn.status.message}", MU::ERR
677
- begin
678
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).delete_vpc_peering_connection(
679
- vpc_peering_connection_id: peering_id
680
- )
681
- rescue Aws::EC2::Errors::InvalidStateTransition => e
682
- # XXX apparently this is normal?
683
- end
684
- raise MuError, "VPC peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id} #{cnxn.status.code}: #{cnxn.status.message}"
685
- end
686
-
687
- end while cnxn.status.code != "active" and !((peer_obj.nil? or peer_obj.deploydata.nil? or !peer_obj.deploydata['auto_accept_peers']) and cnxn.status.code == "pending-acceptance")
688
-
239
+ peerWith(peer)
689
240
  }
690
241
  end
691
242
 
@@ -837,12 +388,9 @@ MU.log "wtf", MU::ERR, details: peer if peer_obj.nil? or peer_obj.first.nil?
837
388
  if rtb_desc.associations
838
389
  rtb_desc.associations.each { |assoc|
839
390
  if assoc.subnet_id
840
- if associations[assoc.subnet_id] and associations[assoc.subnet_id] != rtb['name']
841
- MU.log "wait more than one route table association for #{assoc.subnet_id} what", MU::WARN, details: associations[assoc.subnet_id]+" => "+rtb['name']
842
- end
843
391
  associations[assoc.subnet_id] = rtb['name']
844
392
  elsif assoc.gateway_id
845
- MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_desc
393
+ MU.log " Saw a route table association I don't know how to adopt in #{@cloud_id}", MU::WARN, details: rtb_desc
846
394
  end
847
395
  }
848
396
  end
@@ -902,20 +450,18 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
902
450
  # Describe subnets associated with this VPC. We'll compose identifying
903
451
  # information similar to what MU::Cloud.describe builds for first-class
904
452
  # resources.
905
- # XXX this is weaksauce. Subnets should be objects with their own methods
906
- # that work like first-class objects. How would we enforce that?
907
- # @return [Array<Hash>]: A list of cloud provider identifiers of subnets associated with this VPC.
453
+ # @return [Array<MU::Cloud::AWS::VPC::Subnet>]
908
454
  def loadSubnets
909
- if @cloud_id
910
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(
911
- filters: [
912
- { name: "vpc-id", values: [@cloud_id] }
913
- ]
914
- )
915
- if resp.nil? or resp.subnets.nil? or resp.subnets.size == 0
916
- MU.log "Got empty results when trying to list subnets in #{@cloud_id}", MU::WARN
917
- return []
918
- end
455
+ return [] if !@cloud_id
456
+
457
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(
458
+ filters: [
459
+ { name: "vpc-id", values: [@cloud_id] }
460
+ ]
461
+ )
462
+ if resp.nil? or resp.subnets.nil? or resp.subnets.empty?
463
+ MU.log "Got empty results when trying to list subnets in #{@cloud_id}", MU::WARN
464
+ return []
919
465
  end
920
466
 
921
467
  @subnetcachesemaphore.synchronize {
@@ -926,23 +472,21 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
926
472
  # metadata. Like ya do.
927
473
  if !@config.nil? and @config.has_key?("subnets")
928
474
  @config['subnets'].each { |subnet|
929
- subnet['mu_name'] = @mu_name+"-"+subnet['name'] if !subnet.has_key?("mu_name")
475
+ subnet['mu_name'] ||= @mu_name+"-"+subnet['name']
930
476
  subnet['region'] = @config['region']
931
477
  subnet['credentials'] = @config['credentials']
932
- if !resp.nil? and !resp.data.nil? and !resp.data.subnets.nil?
933
- resp.data.subnets.each { |desc|
934
- if desc.cidr_block == subnet["ip_block"]
935
- subnet["tags"] = MU.structToHash(desc.tags)
936
- subnet["cloud_id"] = desc.subnet_id
937
- break
938
- end
939
- }
940
- end
478
+ resp.subnets.each { |desc|
479
+ if desc.cidr_block == subnet["ip_block"]
480
+ subnet["tags"] = MU.structToHash(desc.tags)
481
+ subnet["cloud_id"] = desc.subnet_id
482
+ break
483
+ end
484
+ }
941
485
 
942
486
  if subnet["cloud_id"] and !ext_ids.include?(subnet["cloud_id"])
943
487
  @subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
944
488
  elsif !subnet["cloud_id"]
945
- resp.data.subnets.each { |desc|
489
+ resp.subnets.each { |desc|
946
490
  if desc.cidr_block == subnet["ip_block"]
947
491
  subnet['cloud_id'] = desc.subnet_id
948
492
  @subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
@@ -955,21 +499,21 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
955
499
 
956
500
  # Of course we might be loading up a dummy subnet object from a
957
501
  # foreign or non-Mu-created VPC and subnet. So make something up.
958
- if !resp.nil? and @subnets.empty?
959
- resp.data.subnets.each { |desc|
960
- subnet = {}
961
- subnet["ip_block"] = desc.cidr_block
962
- subnet["name"] = subnet["ip_block"].gsub(/[\.\/]/, "_")
502
+ if @subnets.empty?
503
+ resp.subnets.each { |desc|
504
+ subnet = {
505
+ "ip_block" => desc.cidr_block,
506
+ "tags" => MU.structToHash(desc.tags),
507
+ "cloud_id" => desc.subnet_id,
508
+ 'region' => @config['region'],
509
+ 'credentials' => @config['credentials'],
510
+ }
511
+ subnet['name'] = subnet["ip_block"].gsub(/[\.\/]/, "_")
963
512
  subnet['mu_name'] = @mu_name+"-"+subnet['name']
964
- subnet["tags"] = MU.structToHash(desc.tags)
965
- subnet["cloud_id"] = desc.subnet_id
966
- subnet['region'] = @config['region']
967
- subnet['credentials'] = @config['credentials']
968
- if !ext_ids.include?(desc.subnet_id)
969
- @subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
970
- end
513
+ @subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
971
514
  }
972
515
  end
516
+
973
517
  return @subnets
974
518
  }
975
519
  end
@@ -1138,14 +682,14 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1138
682
  MU::Cloud::AWS::VPC.update_route_tables_cache(my_subnets_key, region: MU.myRegion)
1139
683
  MU::Cloud::AWS::VPC.update_route_tables_cache(target_subnets_key, region: region, credentials: credentials)
1140
684
 
1141
- if MU::Cloud::AWS::VPC.have_route_peered_vpc?(my_subnets_key, target_subnets_key, instance_id)
685
+ if MU::Cloud::AWS::VPC.can_route_to_master_peer?(my_subnets_key, target_subnets_key, instance_id)
1142
686
  return true
1143
687
  else
1144
688
  # The cache can be out of date at times, check again without it
1145
689
  MU::Cloud::AWS::VPC.update_route_tables_cache(my_subnets_key, use_cache: false, region: MU.myRegion)
1146
690
  MU::Cloud::AWS::VPC.update_route_tables_cache(target_subnets_key, use_cache: false, region: region, credentials: credentials)
1147
691
 
1148
- return MU::Cloud::AWS::VPC.have_route_peered_vpc?(my_subnets_key, target_subnets_key, instance_id)
692
+ return MU::Cloud::AWS::VPC.can_route_to_master_peer?(my_subnets_key, target_subnets_key, instance_id)
1149
693
  end
1150
694
 
1151
695
  end
@@ -1184,7 +728,7 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1184
728
  # @param target_subnets_key [String]: The subnet/subnets on the other side of the peered VPC.
1185
729
  # @param instance_id [String]: The instance ID in the target subnet/subnets.
1186
730
  # @return [Boolean]
1187
- def self.have_route_peered_vpc?(source_subnets_key, target_subnets_key, instance_id)
731
+ def self.can_route_to_master_peer?(source_subnets_key, target_subnets_key, instance_id)
1188
732
  my_routes = []
1189
733
  vpc_peer_mapping = {}
1190
734
 
@@ -1289,17 +833,10 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1289
833
  end
1290
834
 
1291
835
  vpcs = []
1292
- retries = 0
1293
- begin
836
+ MU.retrier([Aws::EC2::Errors::InvalidVpcIDNotFound], wait: 5) {
1294
837
  resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_vpcs(filters: tagfilters, max_results: 1000).vpcs
1295
838
  vpcs = resp if !resp.empty?
1296
- rescue Aws::EC2::Errors::InvalidVpcIDNotFound
1297
- if retries < 5
1298
- sleep 5
1299
- retries += 1
1300
- retry
1301
- end
1302
- end
839
+ }
1303
840
 
1304
841
  if !vpcs.empty?
1305
842
  gwthreads = []
@@ -1492,17 +1029,11 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1492
1029
  if route['gateway'] == '#INTERNET'
1493
1030
  if table['name'] == subnet['route_table']
1494
1031
  subnet['is_public'] = true
1495
- if vpc['create_nat_gateway']
1496
- if vpc['nat_gateway_multi_az']
1497
- subnet['create_nat_gateway'] = true
1498
- else
1499
- if nat_gateway_added
1500
- subnet['create_nat_gateway'] = false
1501
- else
1502
- subnet['create_nat_gateway'] = true
1503
- nat_gateway_added = true
1504
- end
1505
- end
1032
+ if vpc['create_nat_gateway'] and (vpc['nat_gateway_multi_az'] or !nat_gateway_added)
1033
+ subnet['create_nat_gateway'] = true
1034
+ nat_gateway_added = true
1035
+ else
1036
+ subnet['create_nat_gateway'] = false
1506
1037
  end
1507
1038
  else
1508
1039
  subnet['is_public'] = false
@@ -1662,17 +1193,10 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1662
1193
 
1663
1194
  ifaces.each { |iface|
1664
1195
  if iface.vpc_id
1665
- default_sg_resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_security_groups(
1666
- filters: [
1667
- { name: "group-name", values: ["default"] },
1668
- { name: "vpc-id", values: [iface.vpc_id] }
1669
- ]
1670
- ).security_groups
1671
- if default_sg_resp and default_sg_resp.size == 1
1672
- default_sg = default_sg_resp.first.group_id
1673
- if iface.groups.size > 1 or
1674
- iface.groups.first.group_id != default_sg
1675
- MU.log "Removing extra security groups from ENI #{iface.network_interface_id}"
1196
+ default_sg = MU::Cloud::AWS::VPC.getDefaultSg(iface.vpc_id, region: region, credentials: credentials)
1197
+ if default_sg and (iface.groups.size > 1 or (iface.groups.size == 1 and iface.groups.first.group_id != default_sg))
1198
+ MU.log "Removing extra security groups from ENI #{iface.network_interface_id}"
1199
+ if !noop
1676
1200
  begin
1677
1201
  MU::Cloud::AWS.ec2(credentials: credentials, region: region).modify_network_interface_attribute(
1678
1202
  network_interface_id: iface.network_interface_id,
@@ -1693,6 +1217,10 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1693
1217
  rescue Aws::EC2::Errors::OperationNotPermitted => e
1694
1218
  MU.log "Can't detach #{iface.network_interface_id}: #{e.message}", MU::WARN, details: iface.attachment
1695
1219
  next
1220
+ rescue Aws::EC2::Errors::IncorrectState => e
1221
+ MU.log e.message, MU::WARN
1222
+ sleep 5
1223
+ retry
1696
1224
  rescue Aws::EC2::Errors::InvalidAttachmentIDNotFound => e
1697
1225
  # suits me just fine
1698
1226
  rescue Aws::EC2::Errors::AuthFailure => e
@@ -1719,9 +1247,169 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1719
1247
  }
1720
1248
  end
1721
1249
 
1250
+ # Fetch the group id of the +default+ security group for the given VPC
1251
+ # @param vpc_id [String]
1252
+ # @param region [String]
1253
+ # @param credentials [String]
1254
+ # @return [String]
1255
+ def self.getDefaultSg(vpc_id, region: MU.curRegion, credentials: nil)
1256
+ default_sg_resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_security_groups(
1257
+ filters: [
1258
+ { name: "group-name", values: ["default"] },
1259
+ { name: "vpc-id", values: [vpc_id] }
1260
+ ]
1261
+ ).security_groups
1262
+ if default_sg_resp and default_sg_resp.size == 1
1263
+ return default_sg_resp.first.group_id
1264
+ end
1265
+ nil
1266
+ end
1722
1267
 
1723
1268
  private
1724
1269
 
1270
+ def peerWith(peer)
1271
+ peer_ref = MU::Config::Ref.get(peer['vpc'])
1272
+ peer_obj = peer_ref.kitten
1273
+ peer_id = peer_ref.cloud_id
1274
+
1275
+ if peer_obj and peer_obj.config['peers']
1276
+ peer_obj.config['peers'].each { |peerpeer|
1277
+ if peerpeer['vpc']['name'] == @config['name'] and
1278
+ (peer['vpc']['name'] <=> @config['name']) == -1
1279
+ MU.log "VPCs #{peer['vpc']['name']} and #{@config['name']} both declare mutual peering connection, ignoring #{@config['name']}'s redundant declaration", MU::DEBUG
1280
+ return
1281
+ # XXX and if deploy_id matches or is unset
1282
+ end
1283
+ }
1284
+
1285
+ peer['account'] ||= MU::Cloud::AWS.credToAcct(peer_obj.credentials)
1286
+ end
1287
+
1288
+ peer['account'] ||= MU::Cloud::AWS.account_number
1289
+
1290
+ # See if the peering connection exists before we bother
1291
+ # creating it.
1292
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
1293
+ filters: [
1294
+ {
1295
+ name: "requester-vpc-info.vpc-id",
1296
+ values: [@cloud_id]
1297
+ },
1298
+ {
1299
+ name: "accepter-vpc-info.vpc-id",
1300
+ values: [peer_id.to_s]
1301
+ }
1302
+ ]
1303
+ )
1304
+
1305
+ peering_id = if !resp or !resp.vpc_peering_connections or
1306
+ resp.vpc_peering_connections.empty?
1307
+
1308
+ MU.log "Setting peering connection from VPC #{@config['name']} (#{@cloud_id} in account #{MU::Cloud::AWS.credToAcct(@config['credentials'])}) to #{peer_id} in account #{peer['account']}", details: peer
1309
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_vpc_peering_connection(
1310
+ vpc_id: @cloud_id,
1311
+ peer_vpc_id: peer_id,
1312
+ peer_owner_id: peer['account'],
1313
+ peer_region: peer_obj.config['region']
1314
+ )
1315
+ resp.vpc_peering_connection.vpc_peering_connection_id
1316
+ else
1317
+ resp.vpc_peering_connections.first.vpc_peering_connection_id
1318
+ end
1319
+
1320
+ peering_name = @deploy.getResourceName(@config['name']+"-PEER-"+peer_id)
1321
+
1322
+ tag_me(peering_id, peering_name)
1323
+
1324
+ # Create routes to our new friend.
1325
+ MU::Cloud::AWS::VPC.listAllSubnetRouteTables(@cloud_id, region: @config['region'], credentials: @config['credentials']).each { |rtb_id|
1326
+ my_route_config = {
1327
+ :route_table_id => rtb_id,
1328
+ :destination_cidr_block => peer_obj.cloud_desc.cidr_block,
1329
+ :vpc_peering_connection_id => peering_id
1330
+ }
1331
+ rtbdesc = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
1332
+ route_table_ids: [rtb_id]
1333
+ ).route_tables.first
1334
+ already_exists = false
1335
+ rtbdesc.routes.each { |r|
1336
+ if r.destination_cidr_block == peer_obj.cloud_desc.cidr_block
1337
+ if r.vpc_peering_connection_id != peering_id
1338
+ MU.log "Attempt to create duplicate route to #{peer_obj.cloud_desc.cidr_block} from VPC #{@config['name']}", MU::ERR, details: r
1339
+ raise MuError, "Can't create route via #{peering_id}, a route to #{peer_obj.cloud_desc.cidr_block} already exists"
1340
+ else
1341
+ already_exists = true
1342
+ end
1343
+ end
1344
+ }
1345
+ next if already_exists
1346
+
1347
+ MU.log "Creating peering route to #{peer_obj.cloud_desc.cidr_block} in #{peer['vpc']['region']} from VPC #{@config['name']} in #{@config['region']}"
1348
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(my_route_config)
1349
+ } # MU::Cloud::AWS::VPC.listAllSubnetRouteTables
1350
+
1351
+ can_auto_accept = ((!peer_obj.nil? and !peer_obj.deploydata.nil? and peer_obj.deploydata['auto_accept_peers']) or $MU_CFG['allow_invade_foreign_vpcs'])
1352
+
1353
+ cnxn = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
1354
+ vpc_peering_connection_ids: [peering_id]
1355
+ ).vpc_peering_connections.first
1356
+
1357
+ loop_if = Proc.new {
1358
+ cnxn = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
1359
+ vpc_peering_connection_ids: [peering_id]
1360
+ ).vpc_peering_connections.first
1361
+ ((can_auto_accept and cnxn.status.code == "pending-acceptance") or (cnxn.status.code != "active" and cnxn.status.code != "pending-acceptance"))
1362
+ }
1363
+
1364
+ MU.retrier(wait: 5, loop_if: loop_if, ignoreme: [Aws::EC2::Errors::VpcPeeringConnectionAlreadyExists, Aws::EC2::Errors::RouteAlreadyExists]) {
1365
+ if cnxn.status.code == "pending-acceptance"
1366
+ if can_auto_accept
1367
+ MU.log "Auto-accepting peering connection #{peering_id} from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id}", MU::NOTICE
1368
+ MU::Cloud::AWS.ec2(region: peer_obj.config['region'], credentials: peer['account']).accept_vpc_peering_connection(
1369
+ vpc_peering_connection_id: peering_id,
1370
+ )
1371
+
1372
+ # Create routes back from our new friend to us.
1373
+ MU::Cloud::AWS::VPC.listAllSubnetRouteTables(peer_id, region: peer_obj.config['region'], credentials: peer['account']).uniq.each { |rtb_id|
1374
+ peer_route_config = {
1375
+ :route_table_id => rtb_id,
1376
+ :destination_cidr_block => @config['ip_block'],
1377
+ :vpc_peering_connection_id => peering_id
1378
+ }
1379
+ resp = MU::Cloud::AWS.ec2(region: peer_obj.config['region'], credentials: peer['account']).create_route(peer_route_config)
1380
+ }
1381
+ else
1382
+ MU.log "VPC #{peer_id} is not managed by this Mu server or is not configured to auto-accept peering requests. You must accept the peering request for '#{@config['name']}' (#{@cloud_id}) by hand.", MU::WARN, details: "In the AWS Console, go to VPC => Peering Connections and look in the Actions drop-down. You can also set 'Invade Foreign VPCs' to 'true' using mu-configure to auto-accept all peering connections within this account, regardless of whether this Mu server owns the VPCs. This setting is per-user."
1383
+ end
1384
+ end
1385
+
1386
+ if ["failed", "rejected", "expired", "deleted"].include?(cnxn.status.code)
1387
+ MU.log "VPC peering connection from VPC #{@config['name']} (#{@cloud_id} in #{@config['region']}) to #{peer_id} in #{peer_obj.config['region']} #{cnxn.status.code}: #{cnxn.status.message}", MU::ERR
1388
+ begin
1389
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).delete_vpc_peering_connection(
1390
+ vpc_peering_connection_id: peering_id
1391
+ )
1392
+ rescue Aws::EC2::Errors::InvalidStateTransition
1393
+ # XXX apparently this is normal?
1394
+ end
1395
+ raise MuError, "VPC peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id} #{cnxn.status.code}: #{cnxn.status.message}"
1396
+ end
1397
+
1398
+ }
1399
+
1400
+ end
1401
+
1402
+ def tag_me(resource_id = @cloud_id, name = @mu_name)
1403
+ MU::Cloud::AWS.createStandardTags(
1404
+ resource_id,
1405
+ region: @config['region'],
1406
+ credentials: @config['credentials'],
1407
+ optional: @config['optional_tags'],
1408
+ nametag: name,
1409
+ othertags: @config['tags']
1410
+ )
1411
+ end
1412
+
1725
1413
  # Helper method for manufacturing route tables. Expect to be called from
1726
1414
  # {MU::Cloud::AWS::VPC#create} or {MU::Cloud::AWS::VPC#groom}.
1727
1415
  # @param rtb [Hash]: A route table description parsed through {MU::Config::BasketofKittens::vpcs::route_tables}.
@@ -1733,21 +1421,9 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1733
1421
  resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route_table(vpc_id: vpc_id).route_table
1734
1422
  route_table_id = rtb['route_table_id'] = resp.route_table_id
1735
1423
  sleep 5
1736
- MU::Cloud::AWS.createTag(route_table_id, "Name", vpc_name+"-"+rtb['name'].upcase, credentials: @config['credentials'])
1737
1424
 
1738
- if @config['tags']
1739
- @config['tags'].each { |tag|
1740
- MU::Cloud::AWS.createTag(route_table_id, tag['key'], tag['value'], credentials: @config['credentials'])
1741
- }
1742
- end
1743
-
1744
- if @config['optional_tags']
1745
- MU::MommaCat.listOptionalTags.each { |key, value|
1746
- MU::Cloud::AWS.createTag(route_table_id, key, value, region: @config['region'], credentials: @config['credentials'])
1747
- }
1748
- end
1425
+ tag_me(route_table_id, vpc_name+"-"+rtb['name'].upcase)
1749
1426
 
1750
- MU::Cloud::AWS.createStandardTags(route_table_id, credentials: @config['credentials'])
1751
1427
  rtb['routes'].each { |route|
1752
1428
  if route['nat_host_id'].nil? and route['nat_host_name'].nil?
1753
1429
  route_config = {
@@ -1840,36 +1516,25 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1840
1516
  ).nat_gateways
1841
1517
 
1842
1518
  threads = []
1843
- parent_thread_id = Thread.current.object_id
1519
+
1844
1520
  if !gateways.empty?
1845
1521
  gateways.each { |gateway|
1522
+ next if noop
1523
+ MU.log "Deleting NAT Gateway #{gateway.nat_gateway_id}"
1846
1524
  threads << Thread.new {
1847
- MU.dupGlobals(parent_thread_id)
1848
- MU.log "Deleting NAT Gateway #{gateway.nat_gateway_id}"
1849
- if !noop
1850
- begin
1851
- MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_nat_gateway(nat_gateway_id: gateway.nat_gateway_id)
1852
- resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_nat_gateways(nat_gateway_ids: [gateway.nat_gateway_id]).nat_gateways.first
1525
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_nat_gateway(nat_gateway_id: gateway.nat_gateway_id)
1526
+
1527
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_nat_gateways(nat_gateway_ids: [gateway.nat_gateway_id]).nat_gateways.first
1528
+
1529
+ loop_if = Proc.new {
1530
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_nat_gateways(nat_gateway_ids: [gateway.nat_gateway_id]).nat_gateways.first
1531
+ (resp.state != "deleted" and resp.state != "failed")
1532
+ }
1533
+
1534
+ MU.retrier([Aws::EmptyStructure, NoMethodError], ignoreme: [Aws::EC2::Errors::NatGatewayMalformed, Aws::EC2::Errors::NatGatewayNotFound], max: 50, loop_if: loop_if) { |retries, _wait|
1535
+ MU.log "Waiting for nat gateway #{gateway.nat_gateway_id} to delete" if retries % 3 == 0
1536
+ }
1853
1537
 
1854
- attempts = 0
1855
- while resp.state != "deleted" and resp.state != "failed"
1856
- MU.log "Waiting for nat gateway #{gateway.nat_gateway_id} to delete" if attempts % 2 == 0
1857
- sleep 30
1858
- begin
1859
- resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_nat_gateways(nat_gateway_ids: [gateway.nat_gateway_id]).nat_gateways.first
1860
- rescue Aws::EmptyStructure, NoMethodError
1861
- sleep 5
1862
- retry
1863
- rescue Aws::EC2::Errors::NatGatewayNotFound
1864
- MU.log "NAT gateway #{gateway.nat_gateway_id} already deleted", MU::NOTICE
1865
- end
1866
- MU.log "Timed out while waiting for NAT Gateway to delete #{gateway.nat_gateway_id}: #{resp}", MU::WARN if attempts > 50
1867
- attempts += 1
1868
- end
1869
- rescue Aws::EC2::Errors::NatGatewayMalformed
1870
- MU.log "NAT Gateway #{gateway.nat_gateway_id} was already deleted", MU::NOTICE
1871
- end
1872
- end
1873
1538
  }
1874
1539
  }
1875
1540
  end
@@ -1898,38 +1563,21 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1898
1563
  ).vpc_endpoints
1899
1564
 
1900
1565
  threads = []
1901
- parent_thread_id = Thread.current.object_id
1566
+
1902
1567
  if !vpc_endpoints.empty?
1903
1568
  vpc_endpoints.each { |endpoint|
1569
+ MU.log "Deleting VPC endpoint #{endpoint.vpc_endpoint_id}"
1570
+ next if noop
1904
1571
  threads << Thread.new {
1905
- MU.dupGlobals(parent_thread_id)
1906
- MU.log "Deleting VPC endpoint #{endpoint.vpc_endpoint_id}"
1907
- if !noop
1908
- begin
1909
- MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id])
1910
- resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id]).vpc_endpoints.first
1911
-
1912
- attempts = 0
1913
- while resp.state != "deleted"
1914
- MU.log "Waiting for VPC endpoint #{endpoint.vpc_endpoint_id} to delete" if attempts % 5 == 0
1915
- sleep 30
1916
- begin
1917
- resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id]).vpc_endpoints.first
1918
- rescue Aws::EmptyStructure, NoMethodError
1919
- sleep 5
1920
- retry
1921
- rescue Aws::EC2::Errors::InvalidVpcEndpointIdNotFound
1922
- MU.log "VPC endpoint #{endpoint.vpc_endpoint_id} already deleted", MU::NOTICE
1923
- end
1924
- MU.log "Timed out while waiting for VPC endpoint to delete #{endpoint.vpc_endpoint_id}: #{resp}", MU::WARN if attempts > 50
1925
- attempts += 1
1926
- end
1927
- rescue Aws::EC2::Errors::VpcEndpointIdMalformed
1928
- MU.log "VPC endpoint #{endpoint.vpc_endpoint_id} was already deleted", MU::NOTICE
1929
- rescue Aws::EC2::Errors::InvalidVpcEndpointIdNotFound
1930
- MU.log "VPC endpoint #{endpoint.vpc_endpoint_id} already deleted", MU::NOTICE
1931
- end
1932
- end
1572
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id])
1573
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id]).vpc_endpoints.first
1574
+ loop_if = Proc.new {
1575
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id]).vpc_endpoints.first
1576
+ resp.state != "deleted"
1577
+ }
1578
+ MU.retrier([Aws::EmptyStructure, NoMethodError], ignoreme: [Aws::EC2::Errors::InvalidVpcEndpointIdNotFound, Aws::EC2::Errors::VpcEndpointIdMalformed], max: 20, wait: 10, loop_if: loop_if) { |retries, _wait|
1579
+ MU.log "Waiting for VPC endpoint #{endpoint.vpc_endpoint_id} to delete" if retries % 5 == 0
1580
+ }
1933
1581
  }
1934
1582
  }
1935
1583
  end
@@ -2001,56 +1649,6 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
2001
1649
  end
2002
1650
  private_class_method :purge_routetables
2003
1651
 
2004
- # Remove all subnets associated with the currently loaded deployment.
2005
- # @param noop [Boolean]: If true, will only print what would be done
2006
- # @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
2007
- # @param region [String]: The cloud provider region
2008
- # @return [void]
2009
- def self.purge_subnets(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
2010
- resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_subnets(
2011
- filters: tagfilters
2012
- )
2013
- subnets = resp.data.subnets
2014
-
2015
- return if subnets.nil? or subnets.size == 0
2016
-
2017
- retries = 0
2018
- subnets.each { |subnet|
2019
- MU.log "Deleting Subnet #{subnet.subnet_id}"
2020
- begin
2021
- if subnet.state != "available"
2022
- MU.log "Waiting for #{subnet.subnet_id} to be in a removable state...", MU::NOTICE
2023
- sleep 30
2024
- else
2025
- MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_subnet(subnet_id: subnet.subnet_id) if !noop
2026
- end
2027
- rescue Aws::EC2::Errors::DependencyViolation => e
2028
- # We're often stuck waiting for an RDS database or something else
2029
- # that takes 5-ever to delete.
2030
- if retries < 19
2031
- loglevel = (retries > 0 and (retries % 3) == 0) ? MU::NOTICE : MU::DEBUG
2032
- MU.log "#{e.message} (retry #{retries.to_s}/20)", loglevel
2033
- if loglevel == MU::NOTICE
2034
- MU::Cloud::AWS::VPC.purge_interfaces(noop, [{name: "subnet-id", values: [subnet.subnet_id]}], region: region, credentials: credentials)
2035
- end
2036
- sleep 30
2037
- retries = retries + 1
2038
- retry
2039
- elsif retries < 20
2040
- MU.log "#{e.message} (final attempt)", MU::WARN
2041
- sleep 60
2042
- retries = retries + 1
2043
- retry
2044
- else
2045
- raise e
2046
- end
2047
- rescue Aws::EC2::Errors::InvalidSubnetIDNotFound
2048
- next
2049
- end while subnet.state != "available"
2050
- }
2051
- end
2052
- private_class_method :purge_subnets
2053
-
2054
1652
  # Remove all DHCP options sets associated with the currently loaded
2055
1653
  # deployment.
2056
1654
  # @param noop [Boolean]: If true, will only print what would be done
@@ -2088,7 +1686,7 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
2088
1686
  # @return [void]
2089
1687
  def self.purge_vpcs(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
2090
1688
  resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpcs(
2091
- filters: tagfilters
1689
+ filters: tagfilters
2092
1690
  )
2093
1691
 
2094
1692
  vpcs = resp.data.vpcs
@@ -2096,12 +1694,12 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
2096
1694
 
2097
1695
  vpcs.each { |vpc|
2098
1696
  my_peer_conns = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_peering_connections(
2099
- filters: [
2100
- {
2101
- name: "requester-vpc-info.vpc-id",
2102
- values: [vpc.vpc_id]
2103
- }
2104
- ]
1697
+ filters: [
1698
+ {
1699
+ name: "requester-vpc-info.vpc-id",
1700
+ values: [vpc.vpc_id]
1701
+ }
1702
+ ]
2105
1703
  ).vpc_peering_connections
2106
1704
  my_peer_conns.concat(MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_peering_connections(
2107
1705
  filters: [
@@ -2147,31 +1745,20 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
2147
1745
  end
2148
1746
  }
2149
1747
 
2150
- retries = 0
2151
- begin
1748
+ on_retry = Proc.new {
1749
+ MU::Cloud::AWS::FirewallRule.cleanup(
1750
+ noop: noop,
1751
+ region: region,
1752
+ credentials: credentials,
1753
+ flags: { "vpc_id" => vpc.vpc_id }
1754
+ )
1755
+ purge_gateways(noop, tagfilters, region: region, credentials: credentials)
1756
+ }
1757
+
1758
+ MU.retrier([Aws::EC2::Errors::DependencyViolation], ignoreme: [Aws::EC2::Errors::InvalidVpcIDNotFound], max: 20, on_retry: on_retry) {
2152
1759
  MU.log "Deleting VPC #{vpc.vpc_id}"
2153
1760
  MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_vpc(vpc_id: vpc.vpc_id) if !noop
2154
- rescue Aws::EC2::Errors::InvalidVpcIDNotFound
2155
- MU.log "VPC #{vpc.vpc_id} has already been deleted", MU::WARN
2156
- rescue Aws::EC2::Errors::DependencyViolation => e
2157
- if retries < 5
2158
- MU.log "#{vpc.vpc_id} in #{region} had hidden dependencies, will try to remove them", MU::NOTICE
2159
- retries += 1
2160
- # fry some common rogue resources
2161
- MU::Cloud::AWS::FirewallRule.cleanup(
2162
- noop: noop,
2163
- region: region,
2164
- credentials: credentials,
2165
- flags: { "vpc_id" => vpc.vpc_id }
2166
- )
2167
- purge_gateways(noop, tagfilters, region: region, credentials: credentials)
2168
- sleep 10
2169
- retry
2170
- else
2171
- MU.log "Failed to remove #{vpc.vpc_id} in #{region}: #{e.message}", MU::ERR
2172
- next
2173
- end
2174
- end
1761
+ }
2175
1762
 
2176
1763
  if !MU::Cloud::AWS.isGovCloud?(region)
2177
1764
  mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu", region: region, credentials: credentials).values.first
@@ -2183,82 +1770,6 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
2183
1770
  end
2184
1771
  private_class_method :purge_vpcs
2185
1772
 
2186
- # Subnets are almost a first-class resource. So let's kinda sorta treat
2187
- # them like one. This should only be invoked on objects that already
2188
- # exists in the cloud layer.
2189
- class Subnet < MU::Cloud::AWS::VPC
2190
-
2191
- attr_reader :cloud_id
2192
- attr_reader :ip_block
2193
- attr_reader :mu_name
2194
- attr_reader :name
2195
- attr_reader :az
2196
- attr_reader :cloud_desc
2197
-
2198
- # @param parent [MU::Cloud::AWS::VPC]: The parent VPC of this subnet.
2199
- # @param config [Hash<String>]:
2200
- def initialize(parent, config)
2201
- @parent = parent
2202
- @config = MU::Config.manxify(config)
2203
- @cloud_id = config['cloud_id']
2204
- @mu_name = config['mu_name']
2205
- @name = config['name']
2206
- @deploydata = config # This is a dummy for the sake of describe()
2207
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [@cloud_id]).subnets.first
2208
- @az = resp.availability_zone
2209
- @ip_block = resp.cidr_block
2210
- @cloud_desc = resp # XXX this really isn't the cloud implementation's business
2211
-
2212
- end
2213
-
2214
- # Return the cloud identifier for the default route of this subnet.
2215
- def defaultRoute
2216
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
2217
- filters: [{name: "association.subnet-id", values: [@cloud_id]}]
2218
- )
2219
- if resp.route_tables.size == 0 # use default route table for the VPC
2220
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
2221
- filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
2222
- )
2223
- end
2224
- resp.route_tables.each { |route_table|
2225
- route_table.routes.each { |route|
2226
- if route.destination_cidr_block =="0.0.0.0/0" and route.state != "blackhole"
2227
- return route.instance_id if !route.instance_id.nil?
2228
- return route.gateway_id if !route.gateway_id.nil?
2229
- return route.vpc_peering_connection_id if !route.vpc_peering_connection_id.nil?
2230
- return route.network_interface_id if !route.network_interface_id.nil?
2231
- end
2232
- }
2233
- }
2234
- return nil
2235
- end
2236
-
2237
- # Is this subnet privately-routable only, or public?
2238
- # @return [Boolean]
2239
- def private?
2240
- return false if @cloud_id.nil?
2241
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
2242
- filters: [{name: "association.subnet-id", values: [@cloud_id]}]
2243
- )
2244
- if resp.route_tables.size == 0 # use default route table for the VPC
2245
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
2246
- filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
2247
- )
2248
- end
2249
- resp.route_tables.each { |route_table|
2250
- route_table.routes.each { |route|
2251
- return false if !route.gateway_id.nil? and route.gateway_id != "local" # you can have an IgW and route it to a subset of IPs instead of 0.0.0.0/0
2252
- if route.destination_cidr_block == "0.0.0.0/0"
2253
- return true if !route.instance_id.nil?
2254
- return true if route.nat_gateway_id
2255
- end
2256
- }
2257
- }
2258
- return true
2259
- end
2260
- end
2261
-
2262
1773
  end #class
2263
1774
  end #class
2264
1775
  end