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.
- checksums.yaml +4 -4
- data/ansible/roles/mu-windows/README.md +33 -0
- data/ansible/roles/mu-windows/defaults/main.yml +2 -0
- data/ansible/roles/mu-windows/handlers/main.yml +2 -0
- data/ansible/roles/mu-windows/meta/main.yml +53 -0
- data/ansible/roles/mu-windows/tasks/main.yml +20 -0
- data/ansible/roles/mu-windows/tests/inventory +2 -0
- data/ansible/roles/mu-windows/tests/test.yml +5 -0
- data/ansible/roles/mu-windows/vars/main.yml +2 -0
- data/cloud-mu.gemspec +4 -2
- data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
- data/cookbooks/mu-tools/recipes/windows-client.rb +140 -144
- data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
- data/extras/image-generators/AWS/win2k12.yaml +16 -13
- data/extras/image-generators/AWS/win2k16.yaml +16 -13
- data/extras/image-generators/AWS/win2k19.yaml +19 -0
- data/modules/mu.rb +72 -9
- data/modules/mu/adoption.rb +14 -2
- data/modules/mu/cloud.rb +111 -10
- data/modules/mu/clouds/aws.rb +23 -7
- data/modules/mu/clouds/aws/container_cluster.rb +640 -692
- data/modules/mu/clouds/aws/dnszone.rb +49 -45
- data/modules/mu/clouds/aws/firewall_rule.rb +177 -214
- data/modules/mu/clouds/aws/role.rb +17 -8
- data/modules/mu/clouds/aws/search_domain.rb +1 -1
- data/modules/mu/clouds/aws/server.rb +734 -1027
- data/modules/mu/clouds/aws/userdata/windows.erb +2 -1
- data/modules/mu/clouds/aws/vpc.rb +297 -786
- data/modules/mu/clouds/aws/vpc_subnet.rb +286 -0
- data/modules/mu/clouds/google/bucket.rb +1 -1
- data/modules/mu/clouds/google/container_cluster.rb +21 -17
- data/modules/mu/clouds/google/function.rb +8 -2
- data/modules/mu/clouds/google/server.rb +102 -32
- data/modules/mu/clouds/google/vpc.rb +1 -1
- data/modules/mu/config.rb +12 -1
- data/modules/mu/config/server.yml +1 -0
- data/modules/mu/defaults/AWS.yaml +51 -28
- data/modules/mu/groomers/ansible.rb +54 -17
- data/modules/mu/groomers/chef.rb +13 -7
- data/modules/mu/master/ssl.rb +0 -1
- data/modules/mu/mommacat.rb +8 -0
- data/modules/tests/ecs.yaml +23 -0
- data/modules/tests/includes-and-params.yaml +2 -1
- data/modules/tests/server-with-scrub-muisms.yaml +1 -0
- data/modules/tests/win2k12.yaml +25 -0
- data/modules/tests/win2k16.yaml +25 -0
- data/modules/tests/win2k19.yaml +25 -0
- data/requirements.txt +1 -0
- metadata +50 -4
- data/extras/image-generators/AWS/windows.yaml +0 -18
- 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 "
|
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
|
-
|
39
|
+
@cloud_id = resp.vpc_id
|
40
|
+
@config['vpc_id'] = @cloud_id
|
39
41
|
|
40
|
-
|
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} (#{
|
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: [
|
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: [
|
55
|
+
values: [@cloud_id]
|
67
56
|
}
|
68
57
|
]
|
69
58
|
)
|
70
59
|
resp.route_tables.each { |rtb|
|
71
|
-
|
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
|
-
|
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:
|
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
|
-
|
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']
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
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
|
-
|
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:
|
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:
|
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
|
-
|
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
|
-
|
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:
|
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
|
-
|
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
|
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
|
-
#
|
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
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
]
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
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']
|
475
|
+
subnet['mu_name'] ||= @mu_name+"-"+subnet['name']
|
930
476
|
subnet['region'] = @config['region']
|
931
477
|
subnet['credentials'] = @config['credentials']
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
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.
|
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
|
959
|
-
resp.
|
960
|
-
subnet = {
|
961
|
-
|
962
|
-
|
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
|
-
|
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.
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
1497
|
-
|
1498
|
-
|
1499
|
-
|
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
|
-
|
1666
|
-
|
1667
|
-
|
1668
|
-
|
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
|
-
|
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
|
-
|
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.
|
1848
|
-
|
1849
|
-
|
1850
|
-
|
1851
|
-
|
1852
|
-
|
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
|
-
|
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.
|
1906
|
-
MU.
|
1907
|
-
|
1908
|
-
|
1909
|
-
|
1910
|
-
|
1911
|
-
|
1912
|
-
|
1913
|
-
|
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
|
-
|
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
|
-
|
2100
|
-
|
2101
|
-
|
2102
|
-
|
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
|
-
|
2151
|
-
|
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
|
-
|
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
|