cloud-mu 3.1.3 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +15 -3
- data/ansible/roles/mu-windows/README.md +33 -0
- data/ansible/roles/mu-windows/defaults/main.yml +2 -0
- data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
- data/ansible/roles/mu-windows/files/config.xml +76 -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 +36 -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/bin/mu-adopt +21 -13
- data/bin/mu-azure-tests +57 -0
- data/bin/mu-cleanup +2 -4
- data/bin/mu-configure +52 -0
- data/bin/mu-deploy +3 -3
- data/bin/mu-findstray-tests +25 -0
- data/bin/mu-gen-docs +2 -4
- data/bin/mu-load-config.rb +4 -4
- data/bin/mu-node-manage +15 -16
- data/bin/mu-run-tests +147 -37
- data/cloud-mu.gemspec +22 -20
- data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
- data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
- data/cookbooks/mu-tools/libraries/helper.rb +3 -2
- data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
- data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
- data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
- data/cookbooks/mu-tools/recipes/eks.rb +2 -2
- data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
- data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
- data/cookbooks/mu-tools/recipes/windows-client.rb +163 -164
- data/cookbooks/mu-tools/resources/disk.rb +1 -1
- data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
- data/extras/clean-stock-amis +25 -19
- data/extras/generate-stock-images +1 -0
- data/extras/image-generators/AWS/win2k12.yaml +18 -13
- data/extras/image-generators/AWS/win2k16.yaml +18 -13
- data/extras/image-generators/AWS/win2k19.yaml +21 -0
- data/extras/image-generators/Google/centos6.yaml +1 -0
- data/extras/image-generators/Google/centos7.yaml +1 -1
- data/modules/mommacat.ru +6 -16
- data/modules/mu.rb +158 -111
- data/modules/mu/adoption.rb +404 -71
- data/modules/mu/cleanup.rb +221 -306
- data/modules/mu/cloud.rb +129 -1633
- data/modules/mu/cloud/database.rb +49 -0
- data/modules/mu/cloud/dnszone.rb +44 -0
- data/modules/mu/cloud/machine_images.rb +212 -0
- data/modules/mu/cloud/providers.rb +81 -0
- data/modules/mu/cloud/resource_base.rb +926 -0
- data/modules/mu/cloud/server.rb +40 -0
- data/modules/mu/cloud/server_pool.rb +1 -0
- data/modules/mu/cloud/ssh_sessions.rb +228 -0
- data/modules/mu/cloud/winrm_sessions.rb +237 -0
- data/modules/mu/cloud/wrappers.rb +169 -0
- data/modules/mu/config.rb +171 -1767
- data/modules/mu/config/alarm.rb +2 -6
- data/modules/mu/config/bucket.rb +32 -3
- data/modules/mu/config/cache_cluster.rb +2 -2
- data/modules/mu/config/cdn.rb +100 -0
- data/modules/mu/config/collection.rb +4 -4
- data/modules/mu/config/container_cluster.rb +9 -4
- data/modules/mu/config/database.rb +84 -105
- data/modules/mu/config/database.yml +1 -2
- data/modules/mu/config/dnszone.rb +10 -9
- data/modules/mu/config/doc_helpers.rb +516 -0
- data/modules/mu/config/endpoint.rb +5 -4
- data/modules/mu/config/firewall_rule.rb +103 -4
- data/modules/mu/config/folder.rb +4 -4
- data/modules/mu/config/function.rb +19 -10
- data/modules/mu/config/group.rb +4 -4
- data/modules/mu/config/habitat.rb +4 -4
- data/modules/mu/config/job.rb +89 -0
- data/modules/mu/config/loadbalancer.rb +60 -14
- data/modules/mu/config/log.rb +4 -4
- data/modules/mu/config/msg_queue.rb +4 -4
- data/modules/mu/config/nosqldb.rb +4 -4
- data/modules/mu/config/notifier.rb +10 -21
- data/modules/mu/config/ref.rb +411 -0
- data/modules/mu/config/role.rb +4 -4
- data/modules/mu/config/schema_helpers.rb +509 -0
- data/modules/mu/config/search_domain.rb +4 -4
- data/modules/mu/config/server.rb +98 -71
- data/modules/mu/config/server.yml +1 -0
- data/modules/mu/config/server_pool.rb +5 -9
- data/modules/mu/config/storage_pool.rb +1 -1
- data/modules/mu/config/tail.rb +200 -0
- data/modules/mu/config/user.rb +4 -4
- data/modules/mu/config/vpc.rb +71 -27
- data/modules/mu/config/vpc.yml +0 -1
- data/modules/mu/defaults/AWS.yaml +91 -68
- data/modules/mu/defaults/Azure.yaml +1 -0
- data/modules/mu/defaults/Google.yaml +3 -2
- data/modules/mu/deploy.rb +43 -26
- data/modules/mu/groomer.rb +17 -2
- data/modules/mu/groomers/ansible.rb +188 -41
- data/modules/mu/groomers/chef.rb +116 -55
- data/modules/mu/logger.rb +127 -148
- data/modules/mu/master.rb +410 -2
- data/modules/mu/master/chef.rb +3 -4
- data/modules/mu/master/ldap.rb +3 -3
- data/modules/mu/master/ssl.rb +12 -3
- data/modules/mu/mommacat.rb +218 -2612
- data/modules/mu/mommacat/daemon.rb +403 -0
- data/modules/mu/mommacat/naming.rb +473 -0
- data/modules/mu/mommacat/search.rb +495 -0
- data/modules/mu/mommacat/storage.rb +722 -0
- data/modules/mu/{clouds → providers}/README.md +1 -1
- data/modules/mu/{clouds → providers}/aws.rb +380 -122
- data/modules/mu/{clouds → providers}/aws/alarm.rb +7 -5
- data/modules/mu/{clouds → providers}/aws/bucket.rb +297 -59
- data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +37 -71
- data/modules/mu/providers/aws/cdn.rb +782 -0
- data/modules/mu/{clouds → providers}/aws/collection.rb +26 -25
- data/modules/mu/{clouds → providers}/aws/container_cluster.rb +724 -744
- data/modules/mu/providers/aws/database.rb +1744 -0
- data/modules/mu/{clouds → providers}/aws/dnszone.rb +88 -70
- data/modules/mu/providers/aws/endpoint.rb +1072 -0
- data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +220 -247
- data/modules/mu/{clouds → providers}/aws/folder.rb +8 -8
- data/modules/mu/{clouds → providers}/aws/function.rb +300 -142
- data/modules/mu/{clouds → providers}/aws/group.rb +31 -29
- data/modules/mu/{clouds → providers}/aws/habitat.rb +18 -15
- data/modules/mu/providers/aws/job.rb +466 -0
- data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +66 -56
- data/modules/mu/{clouds → providers}/aws/log.rb +17 -14
- data/modules/mu/{clouds → providers}/aws/msg_queue.rb +29 -19
- data/modules/mu/{clouds → providers}/aws/nosqldb.rb +114 -16
- data/modules/mu/{clouds → providers}/aws/notifier.rb +142 -65
- data/modules/mu/{clouds → providers}/aws/role.rb +158 -118
- data/modules/mu/{clouds → providers}/aws/search_domain.rb +201 -59
- data/modules/mu/{clouds → providers}/aws/server.rb +844 -1139
- data/modules/mu/{clouds → providers}/aws/server_pool.rb +74 -65
- data/modules/mu/{clouds → providers}/aws/storage_pool.rb +26 -44
- data/modules/mu/{clouds → providers}/aws/user.rb +24 -25
- data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +5 -4
- data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +2 -1
- data/modules/mu/{clouds → providers}/aws/vpc.rb +525 -931
- data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
- data/modules/mu/{clouds → providers}/azure.rb +29 -9
- data/modules/mu/{clouds → providers}/azure/container_cluster.rb +3 -8
- data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +18 -11
- data/modules/mu/{clouds → providers}/azure/habitat.rb +8 -6
- data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +5 -5
- data/modules/mu/{clouds → providers}/azure/role.rb +8 -10
- data/modules/mu/{clouds → providers}/azure/server.rb +97 -49
- data/modules/mu/{clouds → providers}/azure/user.rb +6 -8
- data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/vpc.rb +16 -21
- data/modules/mu/{clouds → providers}/cloudformation.rb +18 -7
- data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
- data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
- data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
- data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +5 -7
- data/modules/mu/{clouds → providers}/docker.rb +0 -0
- data/modules/mu/{clouds → providers}/google.rb +68 -30
- data/modules/mu/{clouds → providers}/google/bucket.rb +13 -15
- data/modules/mu/{clouds → providers}/google/container_cluster.rb +85 -78
- data/modules/mu/{clouds → providers}/google/database.rb +11 -21
- data/modules/mu/{clouds → providers}/google/firewall_rule.rb +15 -14
- data/modules/mu/{clouds → providers}/google/folder.rb +20 -17
- data/modules/mu/{clouds → providers}/google/function.rb +140 -168
- data/modules/mu/{clouds → providers}/google/group.rb +29 -34
- data/modules/mu/{clouds → providers}/google/habitat.rb +21 -22
- data/modules/mu/{clouds → providers}/google/loadbalancer.rb +19 -21
- data/modules/mu/{clouds → providers}/google/role.rb +94 -58
- data/modules/mu/{clouds → providers}/google/server.rb +243 -156
- data/modules/mu/{clouds → providers}/google/server_pool.rb +26 -45
- data/modules/mu/{clouds → providers}/google/user.rb +95 -31
- data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/google/vpc.rb +103 -79
- data/modules/tests/aws-jobs-functions.yaml +46 -0
- data/modules/tests/bucket.yml +4 -0
- data/modules/tests/centos6.yaml +15 -0
- data/modules/tests/centos7.yaml +15 -0
- data/modules/tests/centos8.yaml +12 -0
- data/modules/tests/ecs.yaml +23 -0
- data/modules/tests/eks.yaml +1 -1
- data/modules/tests/functions/node-function/lambda_function.js +10 -0
- data/modules/tests/functions/python-function/lambda_function.py +12 -0
- data/modules/tests/includes-and-params.yaml +2 -1
- data/modules/tests/microservice_app.yaml +288 -0
- data/modules/tests/rds.yaml +108 -0
- data/modules/tests/regrooms/aws-iam.yaml +201 -0
- data/modules/tests/regrooms/bucket.yml +19 -0
- data/modules/tests/regrooms/rds.yaml +123 -0
- data/modules/tests/server-with-scrub-muisms.yaml +2 -1
- data/modules/tests/super_complex_bok.yml +2 -2
- data/modules/tests/super_simple_bok.yml +3 -5
- data/modules/tests/win2k12.yaml +17 -5
- data/modules/tests/win2k16.yaml +25 -0
- data/modules/tests/win2k19.yaml +25 -0
- data/requirements.txt +1 -0
- data/spec/mu/clouds/azure_spec.rb +2 -2
- metadata +240 -154
- data/extras/image-generators/AWS/windows.yaml +0 -18
- data/modules/mu/clouds/aws/database.rb +0 -1985
- data/modules/mu/clouds/aws/endpoint.rb +0 -592
@@ -37,7 +37,7 @@ module MU
|
|
37
37
|
if !@config['use_if_exists']
|
38
38
|
raise MuError, "IAM user #{@mu_name} already exists and use_if_exists is false"
|
39
39
|
end
|
40
|
-
rescue Aws::IAM::Errors::NoSuchEntity
|
40
|
+
rescue Aws::IAM::Errors::NoSuchEntity
|
41
41
|
@config['path'] ||= "/"+@deploy.deploy_id+"/"
|
42
42
|
MU.log "Creating IAM user #{@config['path']}/#{@mu_name}"
|
43
43
|
tags = get_tag_params
|
@@ -109,7 +109,7 @@ module MU
|
|
109
109
|
# Create these if necessary, then append them to the list of
|
110
110
|
# attachable_policies
|
111
111
|
if @config['raw_policies']
|
112
|
-
pol_arns = MU::Cloud
|
112
|
+
pol_arns = MU::Cloud.resourceClass("AWS", "Role").manageRawPolicies(
|
113
113
|
@config['raw_policies'],
|
114
114
|
basename: @deploy.getResourceName(@config['name']),
|
115
115
|
credentials: @credentials
|
@@ -120,7 +120,7 @@ module MU
|
|
120
120
|
|
121
121
|
if @config['attachable_policies']
|
122
122
|
configured_policies = @config['attachable_policies'].map { |p|
|
123
|
-
|
123
|
+
if p.is_a?(MU::Config::Ref)
|
124
124
|
p.cloud_id
|
125
125
|
else
|
126
126
|
p = MU::Config::Ref.get(p)
|
@@ -135,7 +135,7 @@ module MU
|
|
135
135
|
attached_policies.each { |a|
|
136
136
|
if !configured_policies.include?(a.policy_arn)
|
137
137
|
MU.log "Removing IAM policy #{a.policy_arn} from user #{@mu_name}", MU::NOTICE
|
138
|
-
MU::Cloud
|
138
|
+
MU::Cloud.resourceClass("AWS", "Role").purgePolicy(a.policy_arn, @credentials)
|
139
139
|
else
|
140
140
|
configured_policies.delete(a.policy_arn)
|
141
141
|
end
|
@@ -151,7 +151,7 @@ module MU
|
|
151
151
|
end
|
152
152
|
|
153
153
|
if @config['inline_policies']
|
154
|
-
docs = MU::Cloud
|
154
|
+
docs = MU::Cloud.resourceClass("AWS", "Role").genPolicyDocument(@config['inline_policies'], deploy_obj: @deploy)
|
155
155
|
docs.each { |doc|
|
156
156
|
MU.log "Putting user policy #{doc.keys.first} to user #{@cloud_id} "
|
157
157
|
MU::Cloud::AWS.iam(credentials: @credentials).put_user_policy(
|
@@ -189,17 +189,17 @@ module MU
|
|
189
189
|
# Remove all users associated with the currently loaded deployment.
|
190
190
|
# @param noop [Boolean]: If true, will only print what would be done
|
191
191
|
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
192
|
-
# @param region [String]: The cloud provider region
|
193
192
|
# @return [void]
|
194
|
-
def self.cleanup(noop: false,
|
193
|
+
def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
|
194
|
+
MU.log "AWS::User.cleanup: need to support flags['known']", MU::DEBUG, details: flags
|
195
195
|
|
196
196
|
# XXX this doesn't belong here; maybe under roles, maybe as its own stupid first-class resource
|
197
197
|
resp = MU::Cloud::AWS.iam(credentials: credentials).list_policies(
|
198
|
-
path_prefix: "/"+
|
198
|
+
path_prefix: "/"+deploy_id+"/"
|
199
199
|
)
|
200
200
|
if resp and resp.policies
|
201
201
|
resp.policies.each { |policy|
|
202
|
-
MU.log "Deleting policy /#{
|
202
|
+
MU.log "Deleting policy /#{deploy_id}/#{policy.policy_name}"
|
203
203
|
if !noop
|
204
204
|
attachments = begin
|
205
205
|
MU::Cloud::AWS.iam(credentials: credentials).list_entities_for_policy(
|
@@ -257,7 +257,7 @@ module MU
|
|
257
257
|
}
|
258
258
|
retry
|
259
259
|
rescue ::Aws::IAM::Errors::NoSuchEntity
|
260
|
-
rescue
|
260
|
+
rescue StandardError => e
|
261
261
|
MU.log e.inspect, MU::ERR, details: policy
|
262
262
|
end
|
263
263
|
end
|
@@ -275,14 +275,17 @@ MU.log e.inspect, MU::ERR, details: policy
|
|
275
275
|
).tags
|
276
276
|
has_nodelete = false
|
277
277
|
has_ourdeploy = false
|
278
|
+
has_ourmaster = false
|
278
279
|
tags.each { |tag|
|
279
|
-
if tag.key == "MU-ID" and tag.value ==
|
280
|
+
if tag.key == "MU-ID" and tag.value == deploy_id
|
280
281
|
has_ourdeploy = true
|
282
|
+
elsif tag.key == "MU-MASTER-IP" and tag.value == MU.mu_public_ip
|
283
|
+
has_ourmaster = true
|
281
284
|
elsif tag.key == "MU-NO-DELETE" and tag.value == "true"
|
282
285
|
has_nodelete = true
|
283
286
|
end
|
284
287
|
}
|
285
|
-
if has_ourdeploy and !has_nodelete
|
288
|
+
if has_ourdeploy and !has_nodelete and (ignoremaster or has_ourmaster)
|
286
289
|
MU.log "Deleting IAM user #{u.path}#{u.user_name}"
|
287
290
|
if !@noop
|
288
291
|
begin
|
@@ -296,7 +299,7 @@ MU.log e.inspect, MU::ERR, details: policy
|
|
296
299
|
group_name: g.group_name
|
297
300
|
)
|
298
301
|
}
|
299
|
-
|
302
|
+
MU::Cloud::AWS.iam(credentials: credentials).get_login_profile(
|
300
303
|
user_name: u.user_name
|
301
304
|
)
|
302
305
|
MU.log "Deleting IAM login profile for #{u.user_name}"
|
@@ -381,7 +384,7 @@ MU.log e.inspect, MU::ERR, details: policy
|
|
381
384
|
# Reverse-map our cloud description into a runnable config hash.
|
382
385
|
# We assume that any values we have in +@config+ are placeholders, and
|
383
386
|
# calculate our own accordingly based on what's live in the cloud.
|
384
|
-
def toKitten(
|
387
|
+
def toKitten(**_args)
|
385
388
|
bok = {
|
386
389
|
"cloud" => "AWS",
|
387
390
|
"credentials" => @credentials,
|
@@ -428,7 +431,7 @@ MU.log e.inspect, MU::ERR, details: policy
|
|
428
431
|
resp.policy_names.each { |pol_name|
|
429
432
|
pol = MU::Cloud::AWS.iam(credentials: @credentials).get_user_policy(user_name: @cloud_id, policy_name: pol_name)
|
430
433
|
doc = JSON.parse(URI.decode(pol.policy_document))
|
431
|
-
bok["inline_policies"] = MU::Cloud
|
434
|
+
bok["inline_policies"] = MU::Cloud.resourceClass("AWS", "Role").doc2MuPolicies(pol.policy_name, doc, bok["inline_policies"])
|
432
435
|
}
|
433
436
|
end
|
434
437
|
|
@@ -457,12 +460,12 @@ MU.log e.inspect, MU::ERR, details: policy
|
|
457
460
|
end
|
458
461
|
|
459
462
|
# Cloud-specific configuration properties.
|
460
|
-
# @param
|
463
|
+
# @param _config [MU::Config]: The calling MU::Config object
|
461
464
|
# @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
|
462
|
-
def self.schema(
|
465
|
+
def self.schema(_config)
|
463
466
|
toplevel_required = []
|
464
467
|
polschema = MU::Config::Role.schema["properties"]["policies"]
|
465
|
-
polschema.deep_merge!(MU::Cloud
|
468
|
+
polschema.deep_merge!(MU::Cloud.resourceClass("AWS", "Role").condition_schema)
|
466
469
|
|
467
470
|
schema = {
|
468
471
|
"inline_policies" => polschema,
|
@@ -514,7 +517,7 @@ style long name, like +IAMTESTS-DEV-2018112815-IS-USER-FOO+"
|
|
514
517
|
# If we're attaching some managed policies, make sure all of the ones
|
515
518
|
# that should already exist do indeed exist
|
516
519
|
if user['attachable_policies']
|
517
|
-
ok = false if !MU::Cloud
|
520
|
+
ok = false if !MU::Cloud.resourceClass("AWS", "Role").validateAttachablePolicies(
|
518
521
|
user['attachable_policies'],
|
519
522
|
credentials: user['credentials'],
|
520
523
|
region: user['region']
|
@@ -527,7 +530,7 @@ style long name, like +IAMTESTS-DEV-2018112815-IS-USER-FOO+"
|
|
527
530
|
if configurator.haveLitterMate?(group, "groups")
|
528
531
|
need_dependency = true
|
529
532
|
else
|
530
|
-
found = MU::Cloud
|
533
|
+
found = MU::Cloud.resourceClass("AWS", "Group").find(cloud_id: group)
|
531
534
|
if found.nil? or found.empty? or (configurator.updating and
|
532
535
|
found.values.first.group.path == "/"+configurator.updating+"/")
|
533
536
|
groupdesc = {
|
@@ -539,11 +542,7 @@ style long name, like +IAMTESTS-DEV-2018112815-IS-USER-FOO+"
|
|
539
542
|
end
|
540
543
|
|
541
544
|
if need_dependency
|
542
|
-
user
|
543
|
-
user["dependencies"] << {
|
544
|
-
"type" => "group",
|
545
|
-
"name" => group
|
546
|
-
}
|
545
|
+
MU::Config.addDependency(user, group, "group")
|
547
546
|
end
|
548
547
|
}
|
549
548
|
end
|
File without changes
|
@@ -42,7 +42,7 @@ if ping -c 5 8.8.8.8 > /dev/null; then
|
|
42
42
|
<% if !$mu.skipApplyUpdates %>
|
43
43
|
set +e
|
44
44
|
if [ ! -f /.mu-installer-ran-updates ];then
|
45
|
-
|
45
|
+
echo "Applying package updates" > /etc/nologin
|
46
46
|
apt-get --fix-missing -y upgrade
|
47
47
|
touch /.mu-installer-ran-updates
|
48
48
|
if [ $? -eq 0 ]
|
@@ -58,7 +58,7 @@ if ping -c 5 8.8.8.8 > /dev/null; then
|
|
58
58
|
else
|
59
59
|
echo "FAILED PACKAGE UPDATE" >&2
|
60
60
|
fi
|
61
|
-
|
61
|
+
rm -f /etc/nologin
|
62
62
|
fi
|
63
63
|
<% end %>
|
64
64
|
elif [ -x /usr/bin/yum ];then
|
@@ -94,7 +94,7 @@ if ping -c 5 8.8.8.8 > /dev/null; then
|
|
94
94
|
<% if !$mu.skipApplyUpdates %>
|
95
95
|
set +e
|
96
96
|
if [ ! -f /.mu-installer-ran-updates ];then
|
97
|
-
|
97
|
+
echo "Applying package updates" > /etc/nologin
|
98
98
|
kernel_update=`yum list updates | grep kernel`
|
99
99
|
yum -y update
|
100
100
|
touch /.mu-installer-ran-updates
|
@@ -108,7 +108,7 @@ if ping -c 5 8.8.8.8 > /dev/null; then
|
|
108
108
|
else
|
109
109
|
echo "FAILED PACKAGE UPDATE" >&2
|
110
110
|
fi
|
111
|
-
|
111
|
+
rm -f /etc/nologin
|
112
112
|
fi
|
113
113
|
<% end %>
|
114
114
|
fi
|
@@ -116,6 +116,7 @@ else
|
|
116
116
|
/bin/logger "***** Unable to verify internet connectivity, skipping package updates from userdata"
|
117
117
|
touch /.mu-installer-ran-updates
|
118
118
|
fi
|
119
|
+
rm -f /etc/nologin
|
119
120
|
|
120
121
|
AWSCLI='command -v aws'
|
121
122
|
PIP='command -v pip'
|
@@ -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/providers/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::MommaCat.createTag(vpc_id, "Name", @mu_name, region: @config['region'], credentials: @config['credentials'])
|
42
|
-
|
43
|
-
if @config['tags']
|
44
|
-
@config['tags'].each { |tag|
|
45
|
-
MU::MommaCat.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::MommaCat.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::MommaCat.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::MommaCat.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::MommaCat.createTag(internet_gateway_id, "Name", @mu_name, region: @config['region'], credentials: @config['credentials'])
|
97
|
-
if @config['tags']
|
98
|
-
@config['tags'].each { |tag|
|
99
|
-
MU::MommaCat.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::MommaCat.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,237 +128,35 @@ module MU
|
|
165
128
|
)
|
166
129
|
end
|
167
130
|
|
168
|
-
nat_gateways =
|
169
|
-
if !@config['subnets'].nil?
|
170
|
-
allocation_ids = []
|
171
|
-
subnet_semaphore = Mutex.new
|
172
|
-
subnetthreads = Array.new
|
173
|
-
parent_thread_id = Thread.current.object_id
|
174
|
-
azs = []
|
175
|
-
@config['subnets'].each { |subnet|
|
176
|
-
subnet_name = @config['name']+"-"+subnet['name']
|
177
|
-
MU.log "Creating Subnet #{subnet_name} (#{subnet['ip_block']})", details: subnet
|
178
|
-
azs = MU::Cloud::AWS.listAZs(region: @config['region'], credentials: @config['credentials']) if azs.size == 0
|
179
|
-
if !subnet['availability_zone'].nil?
|
180
|
-
az = subnet['availability_zone']
|
181
|
-
else
|
182
|
-
az = azs.pop
|
183
|
-
end
|
184
|
-
|
185
|
-
subnetthreads << Thread.new {
|
186
|
-
MU.dupGlobals(parent_thread_id)
|
187
|
-
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_subnet(
|
188
|
-
vpc_id: vpc_id,
|
189
|
-
cidr_block: subnet['ip_block'],
|
190
|
-
availability_zone: az
|
191
|
-
).subnet
|
192
|
-
subnet_id = subnet['subnet_id'] = resp.subnet_id
|
193
|
-
MU::Cloud::AWS.createStandardTags(subnet_id, region: @config['region'], credentials: @config['credentials'])
|
194
|
-
MU::MommaCat.createTag(subnet_id, "Name", @mu_name+"-"+subnet['name'], region: @config['region'], credentials: @config['credentials'])
|
195
|
-
if @config['tags']
|
196
|
-
@config['tags'].each { |tag|
|
197
|
-
MU::MommaCat.createTag(subnet_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
|
198
|
-
}
|
199
|
-
end
|
200
|
-
|
201
|
-
if @config['optional_tags']
|
202
|
-
MU::MommaCat.listOptionalTags.each { |key, value|
|
203
|
-
MU::MommaCat.createTag(subnet_id, key, value, region: @config['region'], credentials: @config['credentials'])
|
204
|
-
}
|
205
|
-
end
|
206
|
-
|
207
|
-
retries = 0
|
208
|
-
begin
|
209
|
-
if resp.state != "available"
|
210
|
-
begin
|
211
|
-
MU.log "Waiting for Subnet #{subnet_name} (#{subnet_id}) to be available", MU::NOTICE if retries > 0 and (retries % 3) == 0
|
212
|
-
sleep 5
|
213
|
-
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
|
214
|
-
rescue Aws::EC2::Errors::InvalidSubnetIDNotFound => e
|
215
|
-
sleep 10
|
216
|
-
retry
|
217
|
-
end while resp.state != "available"
|
218
|
-
end
|
219
|
-
rescue NoMethodError => e
|
220
|
-
if retries <= 3
|
221
|
-
MU.log "Got bogus Aws::EmptyResponse error on #{subnet_id} (retries used: #{retries}/3)", MU::WARN
|
222
|
-
retries = retries + 1
|
223
|
-
sleep 5
|
224
|
-
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
|
225
|
-
retry
|
226
|
-
else
|
227
|
-
raise e
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
if !subnet['route_table'].nil?
|
232
|
-
routes = {}
|
233
|
-
@config['route_tables'].each { |tbl|
|
234
|
-
routes[tbl['name']] = tbl
|
235
|
-
}
|
236
|
-
if routes.nil? or routes[subnet['route_table']].nil?
|
237
|
-
MU.log "Subnet #{subnet_name} references non-existent route #{subnet['route_table']}", MU::ERR, details: @deploy.deployment['vpcs']
|
238
|
-
raise MuError, "deploy failure"
|
239
|
-
end
|
240
|
-
MU.log "Associating Route Table '#{subnet['route_table']}' (#{routes[subnet['route_table']]['route_table_id']}) with #{subnet_name}"
|
241
|
-
retries = 0
|
242
|
-
begin
|
243
|
-
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).associate_route_table(
|
244
|
-
route_table_id: routes[subnet['route_table']]['route_table_id'],
|
245
|
-
subnet_id: subnet_id
|
246
|
-
)
|
247
|
-
rescue Aws::EC2::Errors::InvalidRouteTableIDNotFound => e
|
248
|
-
retries = retries + 1
|
249
|
-
if retries < 10
|
250
|
-
sleep 10
|
251
|
-
retry
|
252
|
-
else
|
253
|
-
raise MuError, e.inspect
|
254
|
-
end
|
255
|
-
end
|
256
|
-
end
|
257
|
-
retries = 0
|
258
|
-
begin
|
259
|
-
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
|
260
|
-
rescue Aws::EC2::Errors::InvalidSubnetIDNotFound => e
|
261
|
-
if retries < 10
|
262
|
-
MU.log "Got #{e.inspect}, waiting and retrying", MU::WARN
|
263
|
-
sleep 10
|
264
|
-
retries = retries + 1
|
265
|
-
retry
|
266
|
-
end
|
267
|
-
raise MuError, e.inspect, e.backtrace
|
268
|
-
end
|
269
|
-
|
270
|
-
if subnet['is_public'] && subnet['create_nat_gateway']
|
271
|
-
MU::MommaCat.lock("nat-gateway-eipalloc")
|
272
|
-
filters = [{name: "domain", values: ["vpc"]}]
|
273
|
-
eips = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_addresses(filters: filters).addresses
|
274
|
-
allocation_id = nil
|
275
|
-
eips.each { |eip|
|
276
|
-
next if !eip.association_id.nil? and !eip.association_id.empty?
|
277
|
-
if (eip.private_ip_address.nil? || eip.private_ip_address.empty?) and MU::MommaCat.lock(eip.allocation_id, true, true)
|
278
|
-
if !allocation_ids.include?(eip.allocation_id)
|
279
|
-
allocation_id = eip.allocation_id
|
280
|
-
break
|
281
|
-
end
|
282
|
-
end
|
283
|
-
}
|
131
|
+
nat_gateways = create_subnets
|
284
132
|
|
285
|
-
|
286
|
-
allocation_id = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).allocate_address(domain: "vpc").allocation_id
|
287
|
-
MU::MommaCat.lock(allocation_id, false, true)
|
288
|
-
end
|
289
|
-
|
290
|
-
allocation_ids << allocation_id
|
291
|
-
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_nat_gateway(
|
292
|
-
subnet_id: subnet['subnet_id'],
|
293
|
-
allocation_id: allocation_id,
|
294
|
-
).nat_gateway
|
295
|
-
|
296
|
-
nat_gateway_id = resp.nat_gateway_id
|
297
|
-
attempts = 0
|
298
|
-
MU::MommaCat.unlock("nat-gateway-eipalloc")
|
299
|
-
while resp.class.name != "Aws::EC2::Types::NatGateway" or resp.state == "pending"
|
300
|
-
MU.log "Waiting for nat gateway #{nat_gateway_id} () to become available (EIP allocation: #{allocation_id})" if attempts % 5 == 0
|
301
|
-
sleep 30
|
302
|
-
begin
|
303
|
-
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_nat_gateways(nat_gateway_ids: [nat_gateway_id]).nat_gateways.first
|
304
|
-
rescue Aws::EmptyStructure, NoMethodError
|
305
|
-
sleep 5
|
306
|
-
retry
|
307
|
-
end
|
308
|
-
if attempts > 30
|
309
|
-
MU::MommaCat.unlock(allocation_id, true)
|
310
|
-
raise MuError, "Timed out while waiting for NAT Gateway #{nat_gateway_id}: #{resp}"
|
311
|
-
end
|
312
|
-
attempts += 1
|
313
|
-
end
|
314
|
-
MU::MommaCat.unlock(allocation_id, true)
|
315
|
-
|
316
|
-
raise MuError, "NAT Gateway failed #{nat_gateway_id}: #{resp}" if resp.state == "failed"
|
317
|
-
nat_gateways << {'id' => nat_gateway_id, 'availability_zone' => subnet['availability_zone']}
|
318
|
-
@tags.each_pair { |k, v|
|
319
|
-
MU::MommaCat.createTag(nat_gateway_id, k, v, region: @config['region'], credentials: @config['credentials'])
|
320
|
-
}
|
321
|
-
end
|
322
|
-
|
323
|
-
if subnet.has_key?("map_public_ips")
|
324
|
-
retries = 0
|
325
|
-
begin
|
326
|
-
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_subnet_attribute(
|
327
|
-
subnet_id: subnet_id,
|
328
|
-
map_public_ip_on_launch: {
|
329
|
-
value: subnet['map_public_ips'],
|
330
|
-
}
|
331
|
-
)
|
332
|
-
rescue Aws::EC2::Errors::InvalidSubnetIDNotFound => e
|
333
|
-
if retries < 10
|
334
|
-
MU.log "Got #{e.inspect} while trying to enable map_public_ips on subnet, waiting and retrying", MU::WARN
|
335
|
-
sleep 10
|
336
|
-
retries += 1
|
337
|
-
retry
|
338
|
-
end
|
339
|
-
raise MuError, "Got #{e.inspect}, #{e.backtrace} while trying to enable map_public_ips on subnet"
|
340
|
-
end
|
341
|
-
end
|
342
|
-
|
343
|
-
if subnet["enable_traffic_logging"]
|
344
|
-
loggroup = @deploy.findLitterMate(name: @config['name']+"loggroup", type: "logs")
|
345
|
-
logrole = @deploy.findLitterMate(name: @config['name']+"logrole", type: "roles")
|
346
|
-
MU.log "Enabling traffic logging on Subnet #{subnet_name} in VPC #{@mu_name} to log group #{loggroup.mu_name}"
|
347
|
-
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_flow_logs(
|
348
|
-
resource_ids: [subnet_id],
|
349
|
-
resource_type: "Subnet",
|
350
|
-
traffic_type: subnet["traffic_type_to_log"],
|
351
|
-
log_group_name: loggroup.mu_name,
|
352
|
-
deliver_logs_permission_arn: logrole.cloudobj.arn
|
353
|
-
)
|
354
|
-
end
|
355
|
-
}
|
356
|
-
}
|
357
|
-
|
358
|
-
subnetthreads.each { |t|
|
359
|
-
t.join
|
360
|
-
}
|
361
|
-
|
362
|
-
notify
|
363
|
-
end
|
133
|
+
notify
|
364
134
|
|
365
135
|
if !nat_gateways.empty?
|
366
136
|
nat_gateways.each { |gateway|
|
367
137
|
@config['subnets'].each { |subnet|
|
368
|
-
if subnet['is_public']
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
else
|
389
|
-
raise e
|
390
|
-
end
|
391
|
-
rescue Aws::EC2::Errors::RouteAlreadyExists => e
|
392
|
-
MU.log "Attempt to create duplicate route to #{route['destination_network']} for #{gateway['id']} in #{rtb['route_table_id']}", MU::WARN
|
393
|
-
end
|
394
|
-
end
|
395
|
-
}
|
396
|
-
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
|
+
}
|
397
158
|
}
|
398
|
-
|
159
|
+
}
|
399
160
|
}
|
400
161
|
}
|
401
162
|
end
|
@@ -403,14 +164,14 @@ module MU
|
|
403
164
|
if @config['enable_dns_support']
|
404
165
|
MU.log "Enabling DNS support in #{@mu_name}"
|
405
166
|
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_vpc_attribute(
|
406
|
-
vpc_id:
|
167
|
+
vpc_id: @cloud_id,
|
407
168
|
enable_dns_support: {value: @config['enable_dns_support']}
|
408
169
|
)
|
409
170
|
end
|
410
171
|
if @config['enable_dns_hostnames']
|
411
172
|
MU.log "Enabling DNS hostnames in #{@mu_name}"
|
412
173
|
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_vpc_attribute(
|
413
|
-
vpc_id:
|
174
|
+
vpc_id: @cloud_id,
|
414
175
|
enable_dns_hostnames: {value: @config['enable_dns_hostnames']}
|
415
176
|
)
|
416
177
|
end
|
@@ -439,29 +200,16 @@ module MU
|
|
439
200
|
dhcp_configurations: dhcpopts
|
440
201
|
)
|
441
202
|
dhcpopt_id = resp.dhcp_options.dhcp_options_id
|
442
|
-
|
443
|
-
MU::MommaCat.createTag(dhcpopt_id, "Name", @mu_name, region: @config['region'], credentials: @config['credentials'])
|
444
|
-
|
445
|
-
if @config['tags']
|
446
|
-
@config['tags'].each { |tag|
|
447
|
-
MU::MommaCat.createTag(dhcpopt_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
|
448
|
-
}
|
449
|
-
end
|
203
|
+
tag_me(dhcpopt_id)
|
450
204
|
|
451
|
-
|
452
|
-
MU::MommaCat.listOptionalTags.each { |key, value|
|
453
|
-
MU::MommaCat.createTag(dhcpopt_id, key, value, region: @config['region'], credentials: @config['credentials'])
|
454
|
-
}
|
455
|
-
end
|
456
|
-
|
457
|
-
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)
|
458
206
|
end
|
459
207
|
notify
|
460
208
|
|
461
209
|
if !MU::Cloud::AWS.isGovCloud?(@config['region'])
|
462
210
|
mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu", credentials: @config['credentials']).values.first
|
463
211
|
if !mu_zone.nil?
|
464
|
-
MU::Cloud
|
212
|
+
MU::Cloud.resourceClass("AWS", "DNSZone").toggleVPCAccess(id: mu_zone.id, vpc_id: @cloud_id, region: @config['region'], credentials: @config['credentials'])
|
465
213
|
end
|
466
214
|
end
|
467
215
|
loadSubnets
|
@@ -472,9 +220,6 @@ module MU
|
|
472
220
|
# Canonical Amazon Resource Number for this resource
|
473
221
|
# @return [String]
|
474
222
|
def arn
|
475
|
-
puts @config['region']
|
476
|
-
puts MU::Cloud::AWS.credToAcct(@config['credentials'])
|
477
|
-
puts @cloud_id
|
478
223
|
"arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":ec2:"+@config['region']+":"+MU::Cloud::AWS.credToAcct(@config['credentials'])+":vpc/"+@cloud_id
|
479
224
|
end
|
480
225
|
|
@@ -491,202 +236,7 @@ module MU
|
|
491
236
|
# Generate peering connections
|
492
237
|
if !@config['peers'].nil? and @config['peers'].size > 0
|
493
238
|
@config['peers'].each { |peer|
|
494
|
-
|
495
|
-
peer_id = nil
|
496
|
-
peer['name'] ||= peer['vpc_name']
|
497
|
-
peer['id'] ||= peer['vpc_id']
|
498
|
-
|
499
|
-
# If we know this to be a sibling VPC elsewhere in our stack,
|
500
|
-
# go fetch it, and fix it if we've been misconfigured with a
|
501
|
-
# duplicate peering connection
|
502
|
-
if peer['vpc']['name'] and !peer['account']
|
503
|
-
peer_obj = @deploy.findLitterMate(name: peer['vpc']['name'], type: "vpcs")
|
504
|
-
if peer_obj
|
505
|
-
if peer_obj.config['peers']
|
506
|
-
skipme = false
|
507
|
-
peer_obj.config['peers'].each { |peerpeer|
|
508
|
-
if peerpeer['vpc']['name'] == @config['name'] and
|
509
|
-
(peer['vpc']['name'] <=> @config['name']) == -1
|
510
|
-
skipme = true
|
511
|
-
MU.log "VPCs #{peer['vpc']['name']} and #{@config['name']} both declare mutual peering connection, ignoring #{@config['name']}'s redundant declaration", MU::DEBUG
|
512
|
-
# XXX and if deploy_id matches or is unset
|
513
|
-
end
|
514
|
-
}
|
515
|
-
end
|
516
|
-
next if skipme
|
517
|
-
peer['account'] = MU::Cloud::AWS.credToAcct(peer_obj.credentials)
|
518
|
-
peer['vpc']['id'] = peer_obj.cloud_id
|
519
|
-
peer['vpc']['region'] ||= peer_obj.config['region']
|
520
|
-
end
|
521
|
-
end
|
522
|
-
|
523
|
-
# If we still don't know our peer's vpc identifier, go fishing
|
524
|
-
if !peer_obj
|
525
|
-
tag_key, tag_value = peer['vpc']['tag'].split(/=/, 2) if !peer['vpc']['tag'].nil?
|
526
|
-
if peer['vpc']['deploy_id'].nil? and peer['vpc']['id'].nil? and tag_key.nil?
|
527
|
-
peer['vpc']['deploy_id'] = @deploy.deploy_id
|
528
|
-
end
|
529
|
-
peer_obj = MU::MommaCat.findStray(
|
530
|
-
"AWS",
|
531
|
-
"vpcs",
|
532
|
-
deploy_id: peer['vpc']['deploy_id'],
|
533
|
-
cloud_id: peer['vpc']['id'],
|
534
|
-
# XXX we need a credentials argument here... maybe
|
535
|
-
name: peer['vpc']['name'],
|
536
|
-
tag_key: tag_key,
|
537
|
-
tag_value: tag_value,
|
538
|
-
dummy_ok: true,
|
539
|
-
region: peer['vpc']['region']
|
540
|
-
)
|
541
|
-
MU.log "wtf", MU::ERR, details: peer if peer_obj.nil? or peer_obj.first.nil?
|
542
|
-
raise MuError, "No result looking for #{@mu_name}'s peer VPCs (#{peer['vpc']})" if peer_obj.nil? or peer_obj.first.nil?
|
543
|
-
peer_obj = peer_obj.first
|
544
|
-
peer['account'] ||= MU::Cloud::AWS.credToAcct(peer_obj.credentials)
|
545
|
-
peer['vpc']['id'] ||= peer_obj.cloud_id
|
546
|
-
peer['vpc']['region'] ||= peer_obj.config['region']
|
547
|
-
end
|
548
|
-
|
549
|
-
peer_id = peer['vpc']['id']
|
550
|
-
peer['account'] ||= MU::Cloud::AWS.account_number
|
551
|
-
|
552
|
-
# See if the peering connection exists before we bother
|
553
|
-
# creating it.
|
554
|
-
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
|
555
|
-
filters: [
|
556
|
-
{
|
557
|
-
name: "requester-vpc-info.vpc-id",
|
558
|
-
values: [@cloud_id]
|
559
|
-
},
|
560
|
-
{
|
561
|
-
name: "accepter-vpc-info.vpc-id",
|
562
|
-
values: [peer_id.to_s]
|
563
|
-
}
|
564
|
-
]
|
565
|
-
)
|
566
|
-
|
567
|
-
peering_id = if !resp or !resp.vpc_peering_connections or
|
568
|
-
resp.vpc_peering_connections.empty?
|
569
|
-
|
570
|
-
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
|
571
|
-
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_vpc_peering_connection(
|
572
|
-
vpc_id: @cloud_id,
|
573
|
-
peer_vpc_id: peer_id,
|
574
|
-
peer_owner_id: peer['account'],
|
575
|
-
peer_region: peer['vpc']['region']
|
576
|
-
)
|
577
|
-
resp.vpc_peering_connection.vpc_peering_connection_id
|
578
|
-
else
|
579
|
-
resp.vpc_peering_connections.first.vpc_peering_connection_id
|
580
|
-
end
|
581
|
-
|
582
|
-
peering_name = @deploy.getResourceName(@config['name']+"-PEER-"+peer['vpc']['id'])
|
583
|
-
|
584
|
-
MU::Cloud::AWS.createStandardTags(peering_id, region: @config['region'], credentials: @config['credentials'])
|
585
|
-
MU::MommaCat.createTag(peering_id, "Name", peering_name, region: @config['region'], credentials: @config['credentials'])
|
586
|
-
|
587
|
-
if @config['optional_tags']
|
588
|
-
MU::MommaCat.listOptionalTags.each { |key, value|
|
589
|
-
MU::MommaCat.createTag(peering_id, key, value, region: @config['region'], credentials: @config['credentials'])
|
590
|
-
}
|
591
|
-
end
|
592
|
-
|
593
|
-
if @config['tags']
|
594
|
-
@config['tags'].each { |tag|
|
595
|
-
MU::MommaCat.createTag(peering_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
|
596
|
-
}
|
597
|
-
end
|
598
|
-
|
599
|
-
# Create routes to our new friend.
|
600
|
-
MU::Cloud::AWS::VPC.listAllSubnetRouteTables(@cloud_id, region: @config['region'], credentials: @config['credentials']).each { |rtb_id|
|
601
|
-
my_route_config = {
|
602
|
-
:route_table_id => rtb_id,
|
603
|
-
:destination_cidr_block => peer_obj.cloud_desc.cidr_block,
|
604
|
-
:vpc_peering_connection_id => peering_id
|
605
|
-
}
|
606
|
-
rtbdesc = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
|
607
|
-
route_table_ids: [rtb_id]
|
608
|
-
).route_tables.first
|
609
|
-
already_exists = false
|
610
|
-
rtbdesc.routes.each { |r|
|
611
|
-
if r.destination_cidr_block == peer_obj.cloud_desc.cidr_block
|
612
|
-
if r.vpc_peering_connection_id != peering_id
|
613
|
-
MU.log "Attempt to create duplicate route to #{peer_obj.cloud_desc.cidr_block} from VPC #{@config['name']}", MU::ERR, details: r
|
614
|
-
raise MuError, "Can't create route via #{peering_id}, a route to #{peer_obj.cloud_desc.cidr_block} already exists"
|
615
|
-
else
|
616
|
-
already_exists = true
|
617
|
-
end
|
618
|
-
end
|
619
|
-
}
|
620
|
-
next if already_exists
|
621
|
-
|
622
|
-
MU.log "Creating peering route to #{peer_obj.cloud_desc.cidr_block} in #{peer['vpc']['region']} from VPC #{@config['name']} in #{@config['region']}"
|
623
|
-
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(my_route_config)
|
624
|
-
} # MU::Cloud::AWS::VPC.listAllSubnetRouteTables
|
625
|
-
|
626
|
-
begin
|
627
|
-
cnxn = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
|
628
|
-
vpc_peering_connection_ids: [peering_id]
|
629
|
-
).vpc_peering_connections.first
|
630
|
-
|
631
|
-
if cnxn.status.code == "pending-acceptance"
|
632
|
-
if ((!peer_obj.nil? and !peer_obj.deploydata.nil? and peer_obj.deploydata['auto_accept_peers']) or $MU_CFG['allow_invade_foreign_vpcs'])
|
633
|
-
MU.log "Auto-accepting peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id}", MU::NOTICE
|
634
|
-
begin
|
635
|
-
MU::Cloud::AWS.ec2(region: peer['vpc']['region'], credentials: peer['account']).accept_vpc_peering_connection(
|
636
|
-
vpc_peering_connection_id: peering_id,
|
637
|
-
)
|
638
|
-
if peer['account'] != MU::Cloud::AWS.credToAcct(@config['credentials'])
|
639
|
-
# this seems to take a while across accounts
|
640
|
-
sleep 5
|
641
|
-
end
|
642
|
-
cnxn = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
|
643
|
-
vpc_peering_connection_ids: [peering_id]
|
644
|
-
).vpc_peering_connections.first
|
645
|
-
rescue Aws::EC2::Errors::VpcPeeringConnectionAlreadyExists => e
|
646
|
-
MU.log "Attempt to create duplicate peering connection to #{peer_id} from VPC #{@config['name']}", MU::WARN
|
647
|
-
end
|
648
|
-
|
649
|
-
# Create routes back from our new friend to us.
|
650
|
-
MU::Cloud::AWS::VPC.listAllSubnetRouteTables(peer_id, region: peer['vpc']['region'], credentials: peer['account']).uniq.each { |rtb_id|
|
651
|
-
peer_route_config = {
|
652
|
-
:route_table_id => rtb_id,
|
653
|
-
:destination_cidr_block => @config['ip_block'],
|
654
|
-
:vpc_peering_connection_id => peering_id
|
655
|
-
}
|
656
|
-
begin
|
657
|
-
resp = MU::Cloud::AWS.ec2(region: peer['vpc']['region'], credentials: peer['account']).create_route(peer_route_config)
|
658
|
-
rescue Aws::EC2::Errors::RouteAlreadyExists => e
|
659
|
-
rtbdesc = MU::Cloud::AWS.ec2(region: peer['vpc']['region'], credentials: peer['account']).describe_route_tables(
|
660
|
-
route_table_ids: [rtb_id]
|
661
|
-
).route_tables.first
|
662
|
-
rtbdesc.routes.each { |r|
|
663
|
-
if r.destination_cidr_block == @config['ip_block']
|
664
|
-
if r.vpc_peering_connection_id != peering_id
|
665
|
-
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
|
666
|
-
end
|
667
|
-
end
|
668
|
-
}
|
669
|
-
end
|
670
|
-
}
|
671
|
-
else
|
672
|
-
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."
|
673
|
-
end
|
674
|
-
end
|
675
|
-
|
676
|
-
if cnxn.status.code == "failed" or cnxn.status.code == "rejected" or cnxn.status.code == "expired" or cnxn.status.code == "deleted"
|
677
|
-
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
|
678
|
-
begin
|
679
|
-
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).delete_vpc_peering_connection(
|
680
|
-
vpc_peering_connection_id: peering_id
|
681
|
-
)
|
682
|
-
rescue Aws::EC2::Errors::InvalidStateTransition => e
|
683
|
-
# XXX apparently this is normal?
|
684
|
-
end
|
685
|
-
raise MuError, "VPC peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id} #{cnxn.status.code}: #{cnxn.status.message}"
|
686
|
-
end
|
687
|
-
|
688
|
-
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")
|
689
|
-
|
239
|
+
peerWith(peer)
|
690
240
|
}
|
691
241
|
end
|
692
242
|
|
@@ -713,7 +263,7 @@ MU.log "wtf", MU::ERR, details: peer if peer_obj.nil? or peer_obj.first.nil?
|
|
713
263
|
route_config[:instance_id] = nat_instance.cloud_id
|
714
264
|
|
715
265
|
MU.log "Creating route for #{route['destination_network']} through NAT host #{nat_instance.cloud_id}", details: route_config
|
716
|
-
|
266
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(route_config)
|
717
267
|
end
|
718
268
|
}
|
719
269
|
|
@@ -756,7 +306,7 @@ MU.log "wtf", MU::ERR, details: peer if peer_obj.nil? or peer_obj.first.nil?
|
|
756
306
|
map[vpc.vpc_id] = vpc
|
757
307
|
}
|
758
308
|
return map
|
759
|
-
rescue Aws::EC2::Errors::InvalidVpcIDNotFound
|
309
|
+
rescue Aws::EC2::Errors::InvalidVpcIDNotFound
|
760
310
|
end
|
761
311
|
else
|
762
312
|
resp = MU::Cloud::AWS.ec2(region: args[:region], credentials: args[:credentials]).describe_vpcs
|
@@ -774,7 +324,7 @@ MU.log "wtf", MU::ERR, details: peer if peer_obj.nil? or peer_obj.first.nil?
|
|
774
324
|
# Reverse-map our cloud description into a runnable config hash.
|
775
325
|
# We assume that any values we have in +@config+ are placeholders, and
|
776
326
|
# calculate our own accordingly based on what's live in the cloud.
|
777
|
-
def toKitten(
|
327
|
+
def toKitten(**_args)
|
778
328
|
bok = {
|
779
329
|
"cloud" => "AWS",
|
780
330
|
"credentials" => @config['credentials'],
|
@@ -838,12 +388,9 @@ MU.log "wtf", MU::ERR, details: peer if peer_obj.nil? or peer_obj.first.nil?
|
|
838
388
|
if rtb_desc.associations
|
839
389
|
rtb_desc.associations.each { |assoc|
|
840
390
|
if assoc.subnet_id
|
841
|
-
if associations[assoc.subnet_id] and associations[assoc.subnet_id] != rtb['name']
|
842
|
-
MU.log "wait more than one route table association for #{assoc.subnet_id} what", MU::WARN, details: associations[assoc.subnet_id]+" => "+rtb['name']
|
843
|
-
end
|
844
391
|
associations[assoc.subnet_id] = rtb['name']
|
845
392
|
elsif assoc.gateway_id
|
846
|
-
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
|
847
394
|
end
|
848
395
|
}
|
849
396
|
end
|
@@ -903,20 +450,18 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
903
450
|
# Describe subnets associated with this VPC. We'll compose identifying
|
904
451
|
# information similar to what MU::Cloud.describe builds for first-class
|
905
452
|
# resources.
|
906
|
-
#
|
907
|
-
# that work like first-class objects. How would we enforce that?
|
908
|
-
# @return [Array<Hash>]: A list of cloud provider identifiers of subnets associated with this VPC.
|
453
|
+
# @return [Array<MU::Cloud::AWS::VPC::Subnet>]
|
909
454
|
def loadSubnets
|
910
|
-
if
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
]
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
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 []
|
920
465
|
end
|
921
466
|
|
922
467
|
@subnetcachesemaphore.synchronize {
|
@@ -927,23 +472,21 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
927
472
|
# metadata. Like ya do.
|
928
473
|
if !@config.nil? and @config.has_key?("subnets")
|
929
474
|
@config['subnets'].each { |subnet|
|
930
|
-
subnet['mu_name']
|
475
|
+
subnet['mu_name'] ||= @mu_name+"-"+subnet['name']
|
931
476
|
subnet['region'] = @config['region']
|
932
477
|
subnet['credentials'] = @config['credentials']
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
}
|
941
|
-
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
|
+
}
|
942
485
|
|
943
486
|
if subnet["cloud_id"] and !ext_ids.include?(subnet["cloud_id"])
|
944
487
|
@subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
|
945
488
|
elsif !subnet["cloud_id"]
|
946
|
-
resp.
|
489
|
+
resp.subnets.each { |desc|
|
947
490
|
if desc.cidr_block == subnet["ip_block"]
|
948
491
|
subnet['cloud_id'] = desc.subnet_id
|
949
492
|
@subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
|
@@ -956,21 +499,21 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
956
499
|
|
957
500
|
# Of course we might be loading up a dummy subnet object from a
|
958
501
|
# foreign or non-Mu-created VPC and subnet. So make something up.
|
959
|
-
if
|
960
|
-
resp.
|
961
|
-
subnet = {
|
962
|
-
|
963
|
-
|
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(/[\.\/]/, "_")
|
964
512
|
subnet['mu_name'] = @mu_name+"-"+subnet['name']
|
965
|
-
|
966
|
-
subnet["cloud_id"] = desc.subnet_id
|
967
|
-
subnet['region'] = @config['region']
|
968
|
-
subnet['credentials'] = @config['credentials']
|
969
|
-
if !ext_ids.include?(desc.subnet_id)
|
970
|
-
@subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
|
971
|
-
end
|
513
|
+
@subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
|
972
514
|
}
|
973
515
|
end
|
516
|
+
|
974
517
|
return @subnets
|
975
518
|
}
|
976
519
|
end
|
@@ -983,13 +526,14 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
983
526
|
def findNat(nat_cloud_id: nil, nat_filter_key: nil, nat_filter_value: nil, region: MU.curRegion, credentials: nil)
|
984
527
|
# Discard the nat_cloud_id if it's an AWS instance ID
|
985
528
|
nat_cloud_id = nil if nat_cloud_id && nat_cloud_id.start_with?("i-")
|
529
|
+
credentials ||= @credentials
|
986
530
|
|
987
531
|
if @gateways.nil?
|
988
532
|
@gateways =
|
989
533
|
if nat_cloud_id
|
990
|
-
MU::Cloud::AWS.ec2(region: region, credentials:
|
534
|
+
MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_nat_gateways(nat_gateway_ids: [nat_cloud_id])
|
991
535
|
elsif nat_filter_key && nat_filter_value
|
992
|
-
MU::Cloud::AWS.ec2(region: region, credentials:
|
536
|
+
MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_nat_gateways(
|
993
537
|
filter: [
|
994
538
|
{
|
995
539
|
name: nat_filter_key,
|
@@ -1014,8 +558,8 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1014
558
|
|
1015
559
|
deploy_id = nil
|
1016
560
|
nat_name = nat_name.to_s if !nat_name.nil? and nat_name.class.to_s == "MU::Config::Tail"
|
1017
|
-
nat_ip = nat_ip.to_s if !nat_ip.nil? and nat_ip.class.to_s == "MU::Config::Tail"
|
1018
561
|
nat_cloud_id = nat_cloud_id.to_s if !nat_cloud_id.nil? and nat_cloud_id.class.to_s == "MU::Config::Tail"
|
562
|
+
nat_ip = nat_ip.to_s if !nat_ip.nil? and nat_ip.class.to_s == "MU::Config::Tail"
|
1019
563
|
nat_tag_key = nat_tag_key.to_s if !nat_tag_key.nil? and nat_tag_key.class.to_s == "MU::Config::Tail"
|
1020
564
|
nat_tag_value = nat_tag_value.to_s if !nat_tag_value.nil? and nat_tag_value.class.to_s == "MU::Config::Tail"
|
1021
565
|
|
@@ -1042,8 +586,8 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1042
586
|
found.each { |nat|
|
1043
587
|
# Try some AWS-specific criteria
|
1044
588
|
cloud_desc = nat.cloud_desc
|
1045
|
-
if !
|
1046
|
-
(cloud_desc.private_ip_address ==
|
589
|
+
if !nat_ip.nil? and
|
590
|
+
(cloud_desc.private_ip_address == nat_ip or cloud_desc.public_ip_address == nat_ip)
|
1047
591
|
return nat
|
1048
592
|
elsif cloud_desc.vpc_id == @cloud_id
|
1049
593
|
# XXX Strictly speaking we could have different NATs in different
|
@@ -1090,7 +634,7 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1090
634
|
if instance.nil?
|
1091
635
|
begin
|
1092
636
|
instance = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_instances(instance_ids: [instance_id]).reservations.first.instances.first
|
1093
|
-
rescue NoMethodError, Aws::EC2::Errors::InvalidInstanceIDNotFound
|
637
|
+
rescue NoMethodError, Aws::EC2::Errors::InvalidInstanceIDNotFound
|
1094
638
|
MU.log "Failed to identify instance #{instance_id} in MU::Cloud::AWS::VPC.getInstanceSubnets", MU::WARN
|
1095
639
|
return []
|
1096
640
|
end
|
@@ -1133,20 +677,19 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1133
677
|
my_subnets = MU::Cloud::AWS::VPC.getInstanceSubnets(instance: MU.myCloudDescriptor)
|
1134
678
|
target_subnets = MU::Cloud::AWS::VPC.getInstanceSubnets(instance: target_instance, region: region, credentials: credentials)
|
1135
679
|
|
1136
|
-
resp = nil
|
1137
680
|
my_subnets_key = my_subnets.join(",")
|
1138
681
|
target_subnets_key = target_subnets.join(",")
|
1139
682
|
MU::Cloud::AWS::VPC.update_route_tables_cache(my_subnets_key, region: MU.myRegion)
|
1140
683
|
MU::Cloud::AWS::VPC.update_route_tables_cache(target_subnets_key, region: region, credentials: credentials)
|
1141
684
|
|
1142
|
-
if MU::Cloud::AWS::VPC.
|
685
|
+
if MU::Cloud::AWS::VPC.can_route_to_master_peer?(my_subnets_key, target_subnets_key, instance_id)
|
1143
686
|
return true
|
1144
687
|
else
|
1145
688
|
# The cache can be out of date at times, check again without it
|
1146
689
|
MU::Cloud::AWS::VPC.update_route_tables_cache(my_subnets_key, use_cache: false, region: MU.myRegion)
|
1147
690
|
MU::Cloud::AWS::VPC.update_route_tables_cache(target_subnets_key, use_cache: false, region: region, credentials: credentials)
|
1148
691
|
|
1149
|
-
return MU::Cloud::AWS::VPC.
|
692
|
+
return MU::Cloud::AWS::VPC.can_route_to_master_peer?(my_subnets_key, target_subnets_key, instance_id)
|
1150
693
|
end
|
1151
694
|
|
1152
695
|
end
|
@@ -1185,7 +728,7 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1185
728
|
# @param target_subnets_key [String]: The subnet/subnets on the other side of the peered VPC.
|
1186
729
|
# @param instance_id [String]: The instance ID in the target subnet/subnets.
|
1187
730
|
# @return [Boolean]
|
1188
|
-
def self.
|
731
|
+
def self.can_route_to_master_peer?(source_subnets_key, target_subnets_key, instance_id)
|
1189
732
|
my_routes = []
|
1190
733
|
vpc_peer_mapping = {}
|
1191
734
|
|
@@ -1279,30 +822,39 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1279
822
|
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
1280
823
|
# @param region [String]: The cloud provider region
|
1281
824
|
# @return [void]
|
1282
|
-
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
825
|
+
def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
826
|
+
MU.log "AWS::VPC.cleanup: need to support flags['known']", MU::DEBUG, details: flags
|
827
|
+
|
1283
828
|
tagfilters = [
|
1284
|
-
{name: "tag:MU-ID", values: [
|
829
|
+
{name: "tag:MU-ID", values: [deploy_id]}
|
1285
830
|
]
|
1286
831
|
if !ignoremaster
|
1287
832
|
tagfilters << {name: "tag:MU-MASTER-IP", values: [MU.mu_public_ip]}
|
1288
833
|
end
|
1289
834
|
|
1290
835
|
vpcs = []
|
1291
|
-
|
1292
|
-
begin
|
836
|
+
MU.retrier([Aws::EC2::Errors::InvalidVpcIDNotFound], wait: 5) {
|
1293
837
|
resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_vpcs(filters: tagfilters, max_results: 1000).vpcs
|
1294
838
|
vpcs = resp if !resp.empty?
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
839
|
+
}
|
840
|
+
|
841
|
+
# resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
|
842
|
+
# filters: [
|
843
|
+
# {
|
844
|
+
# name: "requester-vpc-info.vpc-id",
|
845
|
+
# values: [@cloud_id]
|
846
|
+
# },
|
847
|
+
# {
|
848
|
+
# name: "accepter-vpc-info.vpc-id",
|
849
|
+
# values: [peer_id.to_s]
|
850
|
+
# }
|
851
|
+
# ]
|
852
|
+
# )
|
1302
853
|
|
1303
854
|
if !vpcs.empty?
|
1304
855
|
gwthreads = []
|
1305
856
|
vpcs.each { |vpc|
|
857
|
+
purge_peering_connections(noop, vpc.vpc_id, region: region, credentials: credentials)
|
1306
858
|
# NAT gateways don't have any tags, and we can't assign them a name. Lets find them based on a VPC ID
|
1307
859
|
gwthreads << Thread.new {
|
1308
860
|
purge_nat_gateways(noop, vpc_id: vpc.vpc_id, region: region, credentials: credentials)
|
@@ -1322,17 +874,17 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1322
874
|
purge_vpcs(noop, tagfilters, region: region, credentials: credentials)
|
1323
875
|
purge_dhcpopts(noop, tagfilters, region: region, credentials: credentials)
|
1324
876
|
|
1325
|
-
unless noop
|
1326
|
-
MU::Cloud::AWS.iam.list_roles.roles.each{ |role|
|
1327
|
-
match_string = "#{
|
1328
|
-
}
|
1329
|
-
end
|
877
|
+
# unless noop
|
878
|
+
# MU::Cloud::AWS.iam.list_roles.roles.each{ |role|
|
879
|
+
# match_string = "#{deploy_id}.*TRAFFIC-LOG"
|
880
|
+
# }
|
881
|
+
# end
|
1330
882
|
end
|
1331
883
|
|
1332
884
|
# Cloud-specific configuration properties.
|
1333
|
-
# @param
|
885
|
+
# @param _config [MU::Config]: The calling MU::Config object
|
1334
886
|
# @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
|
1335
|
-
def self.schema(
|
887
|
+
def self.schema(_config)
|
1336
888
|
toplevel_required = []
|
1337
889
|
# Flow Logs can be declared at the VPC level or the subnet level
|
1338
890
|
flowlogs = {
|
@@ -1378,11 +930,7 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1378
930
|
logdesc["tags"] = vpc["tags"] if !vpc["tags"].nil?
|
1379
931
|
# logdesc["optional_tags"] = vpc["optional_tags"] if !vpc["optional_tags"].nil?
|
1380
932
|
configurator.insertKitten(logdesc, "logs")
|
1381
|
-
vpc['
|
1382
|
-
vpc['dependencies'] << {
|
1383
|
-
"type" => "log",
|
1384
|
-
"name" => vpc['name']+"loggroup"
|
1385
|
-
}
|
933
|
+
MU::Config.addDependency(vpc, vpc['name']+"loggroup", "log")
|
1386
934
|
|
1387
935
|
roledesc = {
|
1388
936
|
"name" => vpc['name']+"logrole",
|
@@ -1420,15 +968,10 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1420
968
|
roledesc["tags"] = vpc["tags"] if !vpc["tags"].nil?
|
1421
969
|
roledesc["optional_tags"] = vpc["optional_tags"] if !vpc["optional_tags"].nil?
|
1422
970
|
configurator.insertKitten(roledesc, "roles")
|
1423
|
-
vpc['
|
1424
|
-
vpc['dependencies'] << {
|
1425
|
-
"type" => "role",
|
1426
|
-
"name" => vpc['name']+"logrole"
|
1427
|
-
}
|
971
|
+
MU::Config.addDependency(vpc, vpc['name']+"logrole", "role")
|
1428
972
|
end
|
1429
973
|
|
1430
974
|
subnet_routes = Hash.new
|
1431
|
-
public_routes = Array.new
|
1432
975
|
|
1433
976
|
if vpc['subnets']
|
1434
977
|
vpc['subnets'].each { |subnet|
|
@@ -1476,10 +1019,7 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1476
1019
|
subnet_routes[table['name']].each { |subnet|
|
1477
1020
|
nat_routes[subnet] = route['nat_host_name']
|
1478
1021
|
}
|
1479
|
-
vpc['
|
1480
|
-
"type" => "server",
|
1481
|
-
"name" => route['nat_host_name']
|
1482
|
-
}
|
1022
|
+
MU::Config.addDependency(vpc, route['nat_host_name'], "server", no_create_wait: true)
|
1483
1023
|
elsif route['gateway'] == '#NAT'
|
1484
1024
|
vpc['create_nat_gateway'] = true
|
1485
1025
|
private_rtbs << table['name']
|
@@ -1492,17 +1032,11 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1492
1032
|
if route['gateway'] == '#INTERNET'
|
1493
1033
|
if table['name'] == subnet['route_table']
|
1494
1034
|
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
|
1035
|
+
if vpc['create_nat_gateway'] and (vpc['nat_gateway_multi_az'] or !nat_gateway_added)
|
1036
|
+
subnet['create_nat_gateway'] = true
|
1037
|
+
nat_gateway_added = true
|
1038
|
+
else
|
1039
|
+
subnet['create_nat_gateway'] = false
|
1506
1040
|
end
|
1507
1041
|
else
|
1508
1042
|
subnet['is_public'] = false
|
@@ -1600,9 +1134,11 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1600
1134
|
@my_visible_cidrs[subnets]
|
1601
1135
|
end
|
1602
1136
|
|
1603
|
-
private
|
1604
1137
|
|
1605
1138
|
# List the route tables for each subnet in the given VPC
|
1139
|
+
# @param vpc_id [String]:
|
1140
|
+
# @param region [String]:
|
1141
|
+
# @param credentials [String]:
|
1606
1142
|
def self.listAllSubnetRouteTables(vpc_id, region: MU.curRegion, credentials: nil)
|
1607
1143
|
resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_subnets(
|
1608
1144
|
filters: [
|
@@ -1645,6 +1181,299 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1645
1181
|
return table_ids.uniq
|
1646
1182
|
end
|
1647
1183
|
|
1184
|
+
# Remove all network interfaces associated with the currently loaded deployment.
|
1185
|
+
# @param noop [Boolean]: If true, will only print what would be done
|
1186
|
+
# @param filters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
|
1187
|
+
# @param region [String]: The cloud provider region
|
1188
|
+
# @return [void]
|
1189
|
+
def self.purge_interfaces(noop = false, filters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
|
1190
|
+
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_network_interfaces(
|
1191
|
+
filters: filters
|
1192
|
+
)
|
1193
|
+
ifaces = resp.data.network_interfaces
|
1194
|
+
|
1195
|
+
return if ifaces.nil? or ifaces.size == 0
|
1196
|
+
|
1197
|
+
ifaces.each { |iface|
|
1198
|
+
if iface.vpc_id
|
1199
|
+
default_sg = MU::Cloud::AWS::VPC.getDefaultSg(iface.vpc_id, region: region, credentials: credentials)
|
1200
|
+
if default_sg and (iface.groups.size > 1 or (iface.groups.size == 1 and iface.groups.first.group_id != default_sg))
|
1201
|
+
MU.log "Removing extra security groups from ENI #{iface.network_interface_id}"
|
1202
|
+
if !noop
|
1203
|
+
begin
|
1204
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).modify_network_interface_attribute(
|
1205
|
+
network_interface_id: iface.network_interface_id,
|
1206
|
+
groups: [default_sg]
|
1207
|
+
)
|
1208
|
+
rescue ::Aws::EC2::Errors::AuthFailure
|
1209
|
+
MU.log "Permission denied attempting to trim Security Group list for #{iface.network_interface_id}", MU::WARN, details: iface.groups.map { |g| g.group_name }.join(",")+" => default"
|
1210
|
+
end
|
1211
|
+
end
|
1212
|
+
end
|
1213
|
+
end
|
1214
|
+
begin
|
1215
|
+
if iface.attachment and iface.attachment.status == "attached"
|
1216
|
+
MU.log "Detaching Network Interface #{iface.network_interface_id} from #{iface.attachment.instance_owner_id}"
|
1217
|
+
tried_lbs = false
|
1218
|
+
begin
|
1219
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).detach_network_interface(attachment_id: iface.attachment.attachment_id) if !noop
|
1220
|
+
rescue Aws::EC2::Errors::OperationNotPermitted => e
|
1221
|
+
MU.log "Can't detach #{iface.network_interface_id}: #{e.message}", MU::WARN, details: iface.attachment
|
1222
|
+
next
|
1223
|
+
rescue Aws::EC2::Errors::IncorrectState => e
|
1224
|
+
MU.log e.message, MU::WARN
|
1225
|
+
sleep 5
|
1226
|
+
retry
|
1227
|
+
rescue Aws::EC2::Errors::InvalidAttachmentIDNotFound => e
|
1228
|
+
# suits me just fine
|
1229
|
+
rescue Aws::EC2::Errors::AuthFailure => e
|
1230
|
+
if !tried_lbs and iface.attachment.instance_owner_id == "amazon-elb"
|
1231
|
+
MU::Cloud.resourceClass("AWS", "LoadBalancer").cleanup(
|
1232
|
+
noop: noop,
|
1233
|
+
region: region,
|
1234
|
+
credentials: credentials,
|
1235
|
+
flags: {"vpc_id" => iface.vpc_id}
|
1236
|
+
)
|
1237
|
+
tried_lbs = true
|
1238
|
+
retry
|
1239
|
+
end
|
1240
|
+
MU.log e.message, MU::ERR, details: iface.attachment
|
1241
|
+
end
|
1242
|
+
end
|
1243
|
+
MU.log "Deleting Network Interface #{iface.network_interface_id}"
|
1244
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_network_interface(network_interface_id: iface.network_interface_id) if !noop
|
1245
|
+
rescue Aws::EC2::Errors::InvalidNetworkInterfaceIDNotFound
|
1246
|
+
# ok then!
|
1247
|
+
rescue Aws::EC2::Errors::InvalidParameterValue => e
|
1248
|
+
MU.log e.message, MU::ERR, details: iface
|
1249
|
+
end
|
1250
|
+
}
|
1251
|
+
end
|
1252
|
+
|
1253
|
+
# Fetch the group id of the +default+ security group for the given VPC
|
1254
|
+
# @param vpc_id [String]
|
1255
|
+
# @param region [String]
|
1256
|
+
# @param credentials [String]
|
1257
|
+
# @return [String]
|
1258
|
+
def self.getDefaultSg(vpc_id, region: MU.curRegion, credentials: nil)
|
1259
|
+
default_sg_resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_security_groups(
|
1260
|
+
filters: [
|
1261
|
+
{ name: "group-name", values: ["default"] },
|
1262
|
+
{ name: "vpc-id", values: [vpc_id] }
|
1263
|
+
]
|
1264
|
+
).security_groups
|
1265
|
+
if default_sg_resp and default_sg_resp.size == 1
|
1266
|
+
return default_sg_resp.first.group_id
|
1267
|
+
end
|
1268
|
+
nil
|
1269
|
+
end
|
1270
|
+
|
1271
|
+
# Try to locate the default VPC for a region, and return a BoK-style
|
1272
|
+
# config fragment for something that might want to live in it.
|
1273
|
+
def self.defaultVpc(region, credentials)
|
1274
|
+
cfg_fragment = nil
|
1275
|
+
MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_vpcs.vpcs.each { |vpc|
|
1276
|
+
if vpc.is_default
|
1277
|
+
cfg_fragment = {
|
1278
|
+
"id" => vpc.vpc_id,
|
1279
|
+
"cloud" => "AWS",
|
1280
|
+
"region" => region,
|
1281
|
+
"credentials" => credentials
|
1282
|
+
}
|
1283
|
+
cfg_fragment['subnets'] = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_subnets(
|
1284
|
+
filters: [
|
1285
|
+
{
|
1286
|
+
name: "vpc-id",
|
1287
|
+
values: [vpc.vpc_id]
|
1288
|
+
}
|
1289
|
+
]
|
1290
|
+
).subnets.map { |s| { "subnet_id" => s.subnet_id } }
|
1291
|
+
break
|
1292
|
+
end
|
1293
|
+
}
|
1294
|
+
|
1295
|
+
cfg_fragment
|
1296
|
+
end
|
1297
|
+
|
1298
|
+
# Return a {MU::Config::Ref} that indicates this VPC.
|
1299
|
+
# @param subnet_ids [Array<String>]: Optional list of subnet ids with which to infer a +subnet_pref+ parameter.
|
1300
|
+
# @return [MU::Config::Ref]
|
1301
|
+
def getReference(subnet_ids = [])
|
1302
|
+
have_private = have_public = false
|
1303
|
+
subnets.each { |s|
|
1304
|
+
next if subnet_ids and !subnet_ids.empty? and !subnet_ids.include?(s.cloud_id)
|
1305
|
+
if s.private?
|
1306
|
+
have_private = true
|
1307
|
+
else
|
1308
|
+
have_public = true
|
1309
|
+
end
|
1310
|
+
}
|
1311
|
+
subnet_pref = if have_private == have_public
|
1312
|
+
"any"
|
1313
|
+
elsif have_private
|
1314
|
+
"all_private"
|
1315
|
+
elsif have_public
|
1316
|
+
"all_public"
|
1317
|
+
end
|
1318
|
+
MU::Config::Ref.get(
|
1319
|
+
id: @cloud_id,
|
1320
|
+
cloud: "AWS",
|
1321
|
+
credentials: @credentials,
|
1322
|
+
region: @config['region'],
|
1323
|
+
type: "vpcs",
|
1324
|
+
subnet_pref: subnet_pref
|
1325
|
+
)
|
1326
|
+
end
|
1327
|
+
|
1328
|
+
private
|
1329
|
+
|
1330
|
+
def peerWith(peer)
|
1331
|
+
peer_ref = MU::Config::Ref.get(peer['vpc'])
|
1332
|
+
peer_obj = peer_ref.kitten
|
1333
|
+
peer_id = peer_ref.kitten.cloud_id
|
1334
|
+
if peer_id == @cloud_id
|
1335
|
+
MU.log "#{@mu_name} attempted to peer with itself (#{@cloud_id})", MU::ERR, details: peer
|
1336
|
+
raise "#{@mu_name} attempted to peer with itself (#{@cloud_id})"
|
1337
|
+
end
|
1338
|
+
|
1339
|
+
if peer_obj and peer_obj.config['peers']
|
1340
|
+
peer_obj.config['peers'].each { |peerpeer|
|
1341
|
+
if peerpeer['vpc']['name'] == @config['name'] and
|
1342
|
+
(peer['vpc']['name'] <=> @config['name']) == -1
|
1343
|
+
MU.log "VPCs #{peer['vpc']['name']} and #{@config['name']} both declare mutual peering connection, ignoring #{@config['name']}'s redundant declaration", MU::DEBUG
|
1344
|
+
return
|
1345
|
+
# XXX and if deploy_id matches or is unset
|
1346
|
+
end
|
1347
|
+
}
|
1348
|
+
|
1349
|
+
peer['account'] ||= MU::Cloud::AWS.credToAcct(peer_obj.credentials)
|
1350
|
+
end
|
1351
|
+
|
1352
|
+
peer['account'] ||= MU::Cloud::AWS.account_number
|
1353
|
+
|
1354
|
+
# See if the peering connection exists before we bother
|
1355
|
+
# creating it.
|
1356
|
+
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
|
1357
|
+
filters: [
|
1358
|
+
{
|
1359
|
+
name: "requester-vpc-info.vpc-id",
|
1360
|
+
values: [@cloud_id]
|
1361
|
+
},
|
1362
|
+
{
|
1363
|
+
name: "accepter-vpc-info.vpc-id",
|
1364
|
+
values: [peer_id.to_s]
|
1365
|
+
}
|
1366
|
+
]
|
1367
|
+
)
|
1368
|
+
|
1369
|
+
peering_id = if !resp or !resp.vpc_peering_connections or
|
1370
|
+
resp.vpc_peering_connections.empty?
|
1371
|
+
|
1372
|
+
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
|
1373
|
+
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_vpc_peering_connection(
|
1374
|
+
vpc_id: @cloud_id,
|
1375
|
+
peer_vpc_id: peer_id,
|
1376
|
+
peer_owner_id: peer['account'],
|
1377
|
+
peer_region: peer_obj.config['region']
|
1378
|
+
)
|
1379
|
+
resp.vpc_peering_connection.vpc_peering_connection_id
|
1380
|
+
else
|
1381
|
+
resp.vpc_peering_connections.first.vpc_peering_connection_id
|
1382
|
+
end
|
1383
|
+
|
1384
|
+
peering_name = @deploy.getResourceName(@config['name']+"-PEER-"+peer_id)
|
1385
|
+
|
1386
|
+
tag_me(peering_id, peering_name)
|
1387
|
+
|
1388
|
+
# Create routes to our new friend.
|
1389
|
+
MU::Cloud::AWS::VPC.listAllSubnetRouteTables(@cloud_id, region: @config['region'], credentials: @config['credentials']).each { |rtb_id|
|
1390
|
+
my_route_config = {
|
1391
|
+
:route_table_id => rtb_id,
|
1392
|
+
:destination_cidr_block => peer_obj.cloud_desc.cidr_block,
|
1393
|
+
:vpc_peering_connection_id => peering_id
|
1394
|
+
}
|
1395
|
+
rtbdesc = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
|
1396
|
+
route_table_ids: [rtb_id]
|
1397
|
+
).route_tables.first
|
1398
|
+
already_exists = false
|
1399
|
+
rtbdesc.routes.each { |r|
|
1400
|
+
if r.destination_cidr_block == peer_obj.cloud_desc.cidr_block
|
1401
|
+
if r.vpc_peering_connection_id != peering_id
|
1402
|
+
MU.log "Attempt to create duplicate route to #{peer_obj.cloud_desc.cidr_block} from VPC #{@config['name']}", MU::ERR, details: r
|
1403
|
+
raise MuError, "Can't create route via #{peering_id}, a route to #{peer_obj.cloud_desc.cidr_block} already exists"
|
1404
|
+
else
|
1405
|
+
already_exists = true
|
1406
|
+
end
|
1407
|
+
end
|
1408
|
+
}
|
1409
|
+
next if already_exists
|
1410
|
+
|
1411
|
+
MU.log "Creating peering route to #{peer_obj.cloud_desc.cidr_block} in #{peer['vpc']['region']} from VPC #{@config['name']} in #{@config['region']}"
|
1412
|
+
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(my_route_config)
|
1413
|
+
} # MU::Cloud::AWS::VPC.listAllSubnetRouteTables
|
1414
|
+
|
1415
|
+
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'])
|
1416
|
+
|
1417
|
+
cnxn = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
|
1418
|
+
vpc_peering_connection_ids: [peering_id]
|
1419
|
+
).vpc_peering_connections.first
|
1420
|
+
|
1421
|
+
loop_if = Proc.new {
|
1422
|
+
cnxn = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
|
1423
|
+
vpc_peering_connection_ids: [peering_id]
|
1424
|
+
).vpc_peering_connections.first
|
1425
|
+
((can_auto_accept and cnxn.status.code == "pending-acceptance") or (cnxn.status.code != "active" and cnxn.status.code != "pending-acceptance"))
|
1426
|
+
}
|
1427
|
+
|
1428
|
+
MU.retrier(wait: 5, loop_if: loop_if, ignoreme: [Aws::EC2::Errors::VpcPeeringConnectionAlreadyExists, Aws::EC2::Errors::RouteAlreadyExists]) {
|
1429
|
+
if cnxn.status.code == "pending-acceptance"
|
1430
|
+
if can_auto_accept
|
1431
|
+
MU.log "Auto-accepting peering connection #{peering_id} from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id}", MU::NOTICE
|
1432
|
+
MU::Cloud::AWS.ec2(region: peer_obj.config['region'], credentials: peer['account']).accept_vpc_peering_connection(
|
1433
|
+
vpc_peering_connection_id: peering_id,
|
1434
|
+
)
|
1435
|
+
|
1436
|
+
# Create routes back from our new friend to us.
|
1437
|
+
MU::Cloud::AWS::VPC.listAllSubnetRouteTables(peer_id, region: peer_obj.config['region'], credentials: peer['account']).uniq.each { |rtb_id|
|
1438
|
+
peer_route_config = {
|
1439
|
+
:route_table_id => rtb_id,
|
1440
|
+
:destination_cidr_block => @config['ip_block'],
|
1441
|
+
:vpc_peering_connection_id => peering_id
|
1442
|
+
}
|
1443
|
+
resp = MU::Cloud::AWS.ec2(region: peer_obj.config['region'], credentials: peer['account']).create_route(peer_route_config)
|
1444
|
+
}
|
1445
|
+
else
|
1446
|
+
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."
|
1447
|
+
end
|
1448
|
+
end
|
1449
|
+
|
1450
|
+
if ["failed", "rejected", "expired", "deleted"].include?(cnxn.status.code)
|
1451
|
+
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
|
1452
|
+
begin
|
1453
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).delete_vpc_peering_connection(
|
1454
|
+
vpc_peering_connection_id: peering_id
|
1455
|
+
)
|
1456
|
+
rescue Aws::EC2::Errors::InvalidStateTransition
|
1457
|
+
# XXX apparently this is normal?
|
1458
|
+
end
|
1459
|
+
raise MuError, "VPC peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id} #{cnxn.status.code}: #{cnxn.status.message}"
|
1460
|
+
end
|
1461
|
+
|
1462
|
+
}
|
1463
|
+
|
1464
|
+
end
|
1465
|
+
|
1466
|
+
def tag_me(resource_id = @cloud_id, name = @mu_name)
|
1467
|
+
MU::Cloud::AWS.createStandardTags(
|
1468
|
+
resource_id,
|
1469
|
+
region: @config['region'],
|
1470
|
+
credentials: @config['credentials'],
|
1471
|
+
optional: @config['optional_tags'],
|
1472
|
+
nametag: name,
|
1473
|
+
othertags: @config['tags']
|
1474
|
+
)
|
1475
|
+
end
|
1476
|
+
|
1648
1477
|
# Helper method for manufacturing route tables. Expect to be called from
|
1649
1478
|
# {MU::Cloud::AWS::VPC#create} or {MU::Cloud::AWS::VPC#groom}.
|
1650
1479
|
# @param rtb [Hash]: A route table description parsed through {MU::Config::BasketofKittens::vpcs::route_tables}.
|
@@ -1656,21 +1485,9 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1656
1485
|
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route_table(vpc_id: vpc_id).route_table
|
1657
1486
|
route_table_id = rtb['route_table_id'] = resp.route_table_id
|
1658
1487
|
sleep 5
|
1659
|
-
MU::MommaCat.createTag(route_table_id, "Name", vpc_name+"-"+rtb['name'].upcase, credentials: @config['credentials'])
|
1660
|
-
|
1661
|
-
if @config['tags']
|
1662
|
-
@config['tags'].each { |tag|
|
1663
|
-
MU::MommaCat.createTag(route_table_id, tag['key'], tag['value'], credentials: @config['credentials'])
|
1664
|
-
}
|
1665
|
-
end
|
1666
1488
|
|
1667
|
-
|
1668
|
-
MU::MommaCat.listOptionalTags.each { |key, value|
|
1669
|
-
MU::MommaCat.createTag(route_table_id, key, value, region: @config['region'], credentials: @config['credentials'])
|
1670
|
-
}
|
1671
|
-
end
|
1489
|
+
tag_me(route_table_id, vpc_name+"-"+rtb['name'].upcase)
|
1672
1490
|
|
1673
|
-
MU::Cloud::AWS.createStandardTags(route_table_id, credentials: @config['credentials'])
|
1674
1491
|
rtb['routes'].each { |route|
|
1675
1492
|
if route['nat_host_id'].nil? and route['nat_host_name'].nil?
|
1676
1493
|
route_config = {
|
@@ -1693,7 +1510,6 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1693
1510
|
return rtb
|
1694
1511
|
end
|
1695
1512
|
|
1696
|
-
|
1697
1513
|
# Remove all network gateways associated with the currently loaded deployment.
|
1698
1514
|
# @param noop [Boolean]: If true, will only print what would be done
|
1699
1515
|
# @param region [String]: The cloud provider region
|
@@ -1746,6 +1562,7 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1746
1562
|
}
|
1747
1563
|
return nil
|
1748
1564
|
end
|
1565
|
+
private_class_method :purge_gateways
|
1749
1566
|
|
1750
1567
|
# Remove all NAT gateways associated with the VPC of the currently loaded deployment.
|
1751
1568
|
# @param noop [Boolean]: If true, will only print what would be done
|
@@ -1763,36 +1580,25 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1763
1580
|
).nat_gateways
|
1764
1581
|
|
1765
1582
|
threads = []
|
1766
|
-
|
1583
|
+
|
1767
1584
|
if !gateways.empty?
|
1768
1585
|
gateways.each { |gateway|
|
1586
|
+
next if noop
|
1587
|
+
MU.log "Deleting NAT Gateway #{gateway.nat_gateway_id}"
|
1769
1588
|
threads << Thread.new {
|
1770
|
-
MU.
|
1771
|
-
|
1772
|
-
|
1773
|
-
|
1774
|
-
|
1775
|
-
|
1589
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_nat_gateway(nat_gateway_id: gateway.nat_gateway_id)
|
1590
|
+
|
1591
|
+
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_nat_gateways(nat_gateway_ids: [gateway.nat_gateway_id]).nat_gateways.first
|
1592
|
+
|
1593
|
+
loop_if = Proc.new {
|
1594
|
+
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_nat_gateways(nat_gateway_ids: [gateway.nat_gateway_id]).nat_gateways.first
|
1595
|
+
(resp.state != "deleted" and resp.state != "failed")
|
1596
|
+
}
|
1597
|
+
|
1598
|
+
MU.retrier([Aws::EmptyStructure, NoMethodError], ignoreme: [Aws::EC2::Errors::NatGatewayMalformed, Aws::EC2::Errors::NatGatewayNotFound], max: 50, loop_if: loop_if) { |retries, _wait|
|
1599
|
+
MU.log "Waiting for nat gateway #{gateway.nat_gateway_id} to delete" if retries % 3 == 0
|
1600
|
+
}
|
1776
1601
|
|
1777
|
-
attempts = 0
|
1778
|
-
while resp.state != "deleted" and resp.state != "failed"
|
1779
|
-
MU.log "Waiting for nat gateway #{gateway.nat_gateway_id} to delete" if attempts % 2 == 0
|
1780
|
-
sleep 30
|
1781
|
-
begin
|
1782
|
-
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_nat_gateways(nat_gateway_ids: [gateway.nat_gateway_id]).nat_gateways.first
|
1783
|
-
rescue Aws::EmptyStructure, NoMethodError
|
1784
|
-
sleep 5
|
1785
|
-
retry
|
1786
|
-
rescue Aws::EC2::Errors::NatGatewayNotFound
|
1787
|
-
MU.log "NAT gateway #{gateway.nat_gateway_id} already deleted", MU::NOTICE
|
1788
|
-
end
|
1789
|
-
MU.log "Timed out while waiting for NAT Gateway to delete #{gateway.nat_gateway_id}: #{resp}", MU::WARN if attempts > 50
|
1790
|
-
attempts += 1
|
1791
|
-
end
|
1792
|
-
rescue Aws::EC2::Errors::NatGatewayMalformed
|
1793
|
-
MU.log "NAT Gateway #{gateway.nat_gateway_id} was already deleted", MU::NOTICE
|
1794
|
-
end
|
1795
|
-
end
|
1796
1602
|
}
|
1797
1603
|
}
|
1798
1604
|
end
|
@@ -1803,6 +1609,7 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1803
1609
|
|
1804
1610
|
return nil
|
1805
1611
|
end
|
1612
|
+
private_class_method :purge_nat_gateways
|
1806
1613
|
|
1807
1614
|
# Remove all VPC endpoints associated with the VPC of the currently loaded deployment.
|
1808
1615
|
# @param noop [Boolean]: If true, will only print what would be done
|
@@ -1820,38 +1627,21 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1820
1627
|
).vpc_endpoints
|
1821
1628
|
|
1822
1629
|
threads = []
|
1823
|
-
|
1630
|
+
|
1824
1631
|
if !vpc_endpoints.empty?
|
1825
1632
|
vpc_endpoints.each { |endpoint|
|
1633
|
+
MU.log "Deleting VPC endpoint #{endpoint.vpc_endpoint_id}"
|
1634
|
+
next if noop
|
1826
1635
|
threads << Thread.new {
|
1827
|
-
MU.
|
1828
|
-
MU.
|
1829
|
-
|
1830
|
-
|
1831
|
-
|
1832
|
-
|
1833
|
-
|
1834
|
-
|
1835
|
-
|
1836
|
-
MU.log "Waiting for VPC endpoint #{endpoint.vpc_endpoint_id} to delete" if attempts % 5 == 0
|
1837
|
-
sleep 30
|
1838
|
-
begin
|
1839
|
-
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id]).vpc_endpoints.first
|
1840
|
-
rescue Aws::EmptyStructure, NoMethodError
|
1841
|
-
sleep 5
|
1842
|
-
retry
|
1843
|
-
rescue Aws::EC2::Errors::InvalidVpcEndpointIdNotFound
|
1844
|
-
MU.log "VPC endpoint #{endpoint.vpc_endpoint_id} already deleted", MU::NOTICE
|
1845
|
-
end
|
1846
|
-
MU.log "Timed out while waiting for VPC endpoint to delete #{endpoint.vpc_endpoint_id}: #{resp}", MU::WARN if attempts > 50
|
1847
|
-
attempts += 1
|
1848
|
-
end
|
1849
|
-
rescue Aws::EC2::Errors::VpcEndpointIdMalformed
|
1850
|
-
MU.log "VPC endpoint #{endpoint.vpc_endpoint_id} was already deleted", MU::NOTICE
|
1851
|
-
rescue Aws::EC2::Errors::InvalidVpcEndpointIdNotFound
|
1852
|
-
MU.log "VPC endpoint #{endpoint.vpc_endpoint_id} already deleted", MU::NOTICE
|
1853
|
-
end
|
1854
|
-
end
|
1636
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id])
|
1637
|
+
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id]).vpc_endpoints.first
|
1638
|
+
loop_if = Proc.new {
|
1639
|
+
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id]).vpc_endpoints.first
|
1640
|
+
resp.state != "deleted"
|
1641
|
+
}
|
1642
|
+
MU.retrier([Aws::EmptyStructure, NoMethodError], ignoreme: [Aws::EC2::Errors::InvalidVpcEndpointIdNotFound, Aws::EC2::Errors::VpcEndpointIdMalformed], max: 20, wait: 10, loop_if: loop_if) { |retries, _wait|
|
1643
|
+
MU.log "Waiting for VPC endpoint #{endpoint.vpc_endpoint_id} to delete" if retries % 5 == 0
|
1644
|
+
}
|
1855
1645
|
}
|
1856
1646
|
}
|
1857
1647
|
end
|
@@ -1862,6 +1652,7 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1862
1652
|
|
1863
1653
|
return nil
|
1864
1654
|
end
|
1655
|
+
private_class_method :purge_endpoints
|
1865
1656
|
|
1866
1657
|
# Remove all route tables associated with the currently loaded deployment.
|
1867
1658
|
# @param noop [Boolean]: If true, will only print what would be done
|
@@ -1882,7 +1673,7 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1882
1673
|
MU.log "Deleting Network Interface #{route.network_interface_id}"
|
1883
1674
|
begin
|
1884
1675
|
MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_network_interface(network_interface_id: route.network_interface_id) if !noop
|
1885
|
-
rescue Aws::EC2::Errors::InvalidNetworkInterfaceIDNotFound
|
1676
|
+
rescue Aws::EC2::Errors::InvalidNetworkInterfaceIDNotFound
|
1886
1677
|
MU.log "Network Interface #{route.network_interface_id} has already been deleted", MU::WARN
|
1887
1678
|
end
|
1888
1679
|
end
|
@@ -1902,9 +1693,9 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1902
1693
|
table.associations.each { |assoc|
|
1903
1694
|
begin
|
1904
1695
|
MU::Cloud::AWS.ec2(credentials: credentials, region: region).disassociate_route_table(association_id: assoc.route_table_association_id) if !noop
|
1905
|
-
rescue Aws::EC2::Errors::InvalidAssociationIDNotFound
|
1696
|
+
rescue Aws::EC2::Errors::InvalidAssociationIDNotFound
|
1906
1697
|
MU.log "Route table association #{assoc.route_table_association_id} already removed", MU::WARN
|
1907
|
-
rescue Aws::EC2::Errors::InvalidParameterValue
|
1698
|
+
rescue Aws::EC2::Errors::InvalidParameterValue
|
1908
1699
|
# normal and ignorable with the default route table
|
1909
1700
|
can_delete = false
|
1910
1701
|
next
|
@@ -1920,124 +1711,7 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
1920
1711
|
}
|
1921
1712
|
return nil
|
1922
1713
|
end
|
1923
|
-
|
1924
|
-
|
1925
|
-
# Remove all network interfaces associated with the currently loaded deployment.
|
1926
|
-
# @param noop [Boolean]: If true, will only print what would be done
|
1927
|
-
# @param filters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
|
1928
|
-
# @param region [String]: The cloud provider region
|
1929
|
-
# @return [void]
|
1930
|
-
def self.purge_interfaces(noop = false, filters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
|
1931
|
-
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_network_interfaces(
|
1932
|
-
filters: filters
|
1933
|
-
)
|
1934
|
-
ifaces = resp.data.network_interfaces
|
1935
|
-
|
1936
|
-
return if ifaces.nil? or ifaces.size == 0
|
1937
|
-
|
1938
|
-
ifaces.each { |iface|
|
1939
|
-
if iface.vpc_id
|
1940
|
-
default_sg_resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_security_groups(
|
1941
|
-
filters: [
|
1942
|
-
{ name: "group-name", values: ["default"] },
|
1943
|
-
{ name: "vpc-id", values: [iface.vpc_id] }
|
1944
|
-
]
|
1945
|
-
).security_groups
|
1946
|
-
if default_sg_resp and default_sg_resp.size == 1
|
1947
|
-
default_sg = default_sg_resp.first.group_id
|
1948
|
-
if iface.groups.size != 1 or
|
1949
|
-
iface.groups.first.group_id != default_sg
|
1950
|
-
MU.log "Removing extra security groups from ENI #{iface.network_interface_id}"
|
1951
|
-
MU::Cloud::AWS.ec2(credentials: credentials, region: region).modify_network_interface_attribute(
|
1952
|
-
network_interface_id: iface.network_interface_id,
|
1953
|
-
groups: [default_sg]
|
1954
|
-
)
|
1955
|
-
end
|
1956
|
-
end
|
1957
|
-
end
|
1958
|
-
begin
|
1959
|
-
if iface.attachment and iface.attachment.status == "attached"
|
1960
|
-
MU.log "Detaching Network Interface #{iface.network_interface_id} from #{iface.attachment.instance_owner_id}"
|
1961
|
-
tried_lbs = false
|
1962
|
-
begin
|
1963
|
-
MU::Cloud::AWS.ec2(credentials: credentials, region: region).detach_network_interface(attachment_id: iface.attachment.attachment_id) if !noop
|
1964
|
-
rescue Aws::EC2::Errors::OperationNotPermitted => e
|
1965
|
-
MU.log "Can't detach #{iface.network_interface_id}: #{e.message}", MU::WARN, details: iface.attachment
|
1966
|
-
next
|
1967
|
-
rescue Aws::EC2::Errors::InvalidAttachmentIDNotFound => e
|
1968
|
-
# suits me just fine
|
1969
|
-
rescue Aws::EC2::Errors::AuthFailure => e
|
1970
|
-
if !tried_lbs and iface.attachment.instance_owner_id == "amazon-elb"
|
1971
|
-
MU::Cloud::AWS::LoadBalancer.cleanup(
|
1972
|
-
noop: noop,
|
1973
|
-
region: region,
|
1974
|
-
credentials: credentials,
|
1975
|
-
flags: {"vpc_id" => iface.vpc_id}
|
1976
|
-
)
|
1977
|
-
tried_lbs = true
|
1978
|
-
retry
|
1979
|
-
end
|
1980
|
-
MU.log e.message, MU::ERR, details: iface.attachment
|
1981
|
-
end
|
1982
|
-
end
|
1983
|
-
MU.log "Deleting Network Interface #{iface.network_interface_id}"
|
1984
|
-
MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_network_interface(network_interface_id: iface.network_interface_id) if !noop
|
1985
|
-
rescue Aws::EC2::Errors::InvalidNetworkInterfaceIDNotFound => e
|
1986
|
-
# ok then!
|
1987
|
-
rescue Aws::EC2::Errors::InvalidParameterValue => e
|
1988
|
-
MU.log e.message, MU::ERR, details: iface
|
1989
|
-
end
|
1990
|
-
}
|
1991
|
-
end
|
1992
|
-
|
1993
|
-
# Remove all subnets associated with the currently loaded deployment.
|
1994
|
-
# @param noop [Boolean]: If true, will only print what would be done
|
1995
|
-
# @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
|
1996
|
-
# @param region [String]: The cloud provider region
|
1997
|
-
# @return [void]
|
1998
|
-
def self.purge_subnets(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
|
1999
|
-
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_subnets(
|
2000
|
-
filters: tagfilters
|
2001
|
-
)
|
2002
|
-
subnets = resp.data.subnets
|
2003
|
-
|
2004
|
-
return if subnets.nil? or subnets.size == 0
|
2005
|
-
|
2006
|
-
retries = 0
|
2007
|
-
subnets.each { |subnet|
|
2008
|
-
MU.log "Deleting Subnet #{subnet.subnet_id}"
|
2009
|
-
begin
|
2010
|
-
if subnet.state != "available"
|
2011
|
-
MU.log "Waiting for #{subnet.subnet_id} to be in a removable state...", MU::NOTICE
|
2012
|
-
sleep 30
|
2013
|
-
else
|
2014
|
-
MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_subnet(subnet_id: subnet.subnet_id) if !noop
|
2015
|
-
end
|
2016
|
-
rescue Aws::EC2::Errors::DependencyViolation => e
|
2017
|
-
# We're often stuck waiting for an RDS database or something else
|
2018
|
-
# that takes 5-ever to delete.
|
2019
|
-
if retries < 19
|
2020
|
-
loglevel = (retries > 0 and (retries % 3) == 0) ? MU::NOTICE : MU::DEBUG
|
2021
|
-
MU.log "#{e.message} (retry #{retries.to_s}/20)", loglevel
|
2022
|
-
if loglevel == MU::NOTICE
|
2023
|
-
MU::Cloud::AWS::VPC.purge_interfaces(noop, [{name: "subnet-id", values: [subnet.subnet_id]}], region: region, credentials: credentials)
|
2024
|
-
end
|
2025
|
-
sleep 30
|
2026
|
-
retries = retries + 1
|
2027
|
-
retry
|
2028
|
-
elsif retries < 20
|
2029
|
-
MU.log "#{e.message} (final attempt)", MU::WARN
|
2030
|
-
sleep 60
|
2031
|
-
retries = retries + 1
|
2032
|
-
retry
|
2033
|
-
else
|
2034
|
-
raise e
|
2035
|
-
end
|
2036
|
-
rescue Aws::EC2::Errors::InvalidSubnetIDNotFound
|
2037
|
-
next
|
2038
|
-
end while subnet.state != "available"
|
2039
|
-
}
|
2040
|
-
end
|
1714
|
+
private_class_method :purge_routetables
|
2041
1715
|
|
2042
1716
|
# Remove all DHCP options sets associated with the currently loaded
|
2043
1717
|
# deployment.
|
@@ -2056,7 +1730,9 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
2056
1730
|
sets.each { |optset|
|
2057
1731
|
begin
|
2058
1732
|
MU.log "Deleting DHCP Option Set #{optset.dhcp_options_id}"
|
2059
|
-
|
1733
|
+
if !noop
|
1734
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_dhcp_options(dhcp_options_id: optset.dhcp_options_id)
|
1735
|
+
end
|
2060
1736
|
rescue Aws::EC2::Errors::DependencyViolation => e
|
2061
1737
|
MU.log e.inspect, MU::ERR
|
2062
1738
|
# rescue Aws::EC2::Errors::InvalidSubnetIDNotFound
|
@@ -2065,6 +1741,62 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
2065
1741
|
end
|
2066
1742
|
}
|
2067
1743
|
end
|
1744
|
+
private_class_method :purge_dhcpopts
|
1745
|
+
|
1746
|
+
def self.purge_peering_connections(noop, vpc_id, region: MU.curRegion, credentials: nil)
|
1747
|
+
my_peer_conns = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_peering_connections(
|
1748
|
+
filters: [
|
1749
|
+
{
|
1750
|
+
name: "requester-vpc-info.vpc-id",
|
1751
|
+
values: [vpc_id]
|
1752
|
+
}
|
1753
|
+
]
|
1754
|
+
).vpc_peering_connections
|
1755
|
+
my_peer_conns.concat(MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_peering_connections(
|
1756
|
+
filters: [
|
1757
|
+
{
|
1758
|
+
name: "accepter-vpc-info.vpc-id",
|
1759
|
+
values: [vpc_id]
|
1760
|
+
}
|
1761
|
+
]
|
1762
|
+
).vpc_peering_connections)
|
1763
|
+
|
1764
|
+
my_peer_conns.each { |cnxn|
|
1765
|
+
[cnxn.accepter_vpc_info.vpc_id, cnxn.requester_vpc_info.vpc_id].each { |peer_vpc|
|
1766
|
+
MU::Cloud::AWS::VPC.listAllSubnetRouteTables(peer_vpc, region: region, credentials: credentials).each { |rtb_id|
|
1767
|
+
begin
|
1768
|
+
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_route_tables(
|
1769
|
+
route_table_ids: [rtb_id]
|
1770
|
+
)
|
1771
|
+
rescue Aws::EC2::Errors::InvalidRouteTableIDNotFound
|
1772
|
+
next
|
1773
|
+
end
|
1774
|
+
resp.route_tables.each { |rtb|
|
1775
|
+
rtb.routes.each { |route|
|
1776
|
+
if route.vpc_peering_connection_id == cnxn.vpc_peering_connection_id
|
1777
|
+
MU.log "Removing route #{route.destination_cidr_block} from route table #{rtb_id} in VPC #{peer_vpc}"
|
1778
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_route(
|
1779
|
+
route_table_id: rtb_id,
|
1780
|
+
destination_cidr_block: route.destination_cidr_block
|
1781
|
+
) if !noop
|
1782
|
+
end
|
1783
|
+
}
|
1784
|
+
}
|
1785
|
+
}
|
1786
|
+
}
|
1787
|
+
MU.log "Deleting VPC peering connection #{cnxn.vpc_peering_connection_id}"
|
1788
|
+
begin
|
1789
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_vpc_peering_connection(
|
1790
|
+
vpc_peering_connection_id: cnxn.vpc_peering_connection_id
|
1791
|
+
) if !noop
|
1792
|
+
rescue Aws::EC2::Errors::InvalidStateTransition
|
1793
|
+
MU.log "VPC peering connection #{cnxn.vpc_peering_connection_id} not in removable (state #{cnxn.status.code})", MU::WARN
|
1794
|
+
rescue Aws::EC2::Errors::OperationNotPermitted => e
|
1795
|
+
MU.log "VPC peering connection #{cnxn.vpc_peering_connection_id} refuses to delete: #{e.message}", MU::WARN
|
1796
|
+
end
|
1797
|
+
}
|
1798
|
+
end
|
1799
|
+
private_class_method :purge_peering_connections
|
2068
1800
|
|
2069
1801
|
# Remove all VPCs associated with the currently loaded deployment.
|
2070
1802
|
# @param noop [Boolean]: If true, will only print what would be done
|
@@ -2073,177 +1805,39 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
|
|
2073
1805
|
# @return [void]
|
2074
1806
|
def self.purge_vpcs(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
|
2075
1807
|
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpcs(
|
2076
|
-
|
1808
|
+
filters: tagfilters
|
2077
1809
|
)
|
2078
1810
|
|
2079
1811
|
vpcs = resp.data.vpcs
|
2080
1812
|
return if vpcs.nil? or vpcs.size == 0
|
2081
1813
|
|
2082
1814
|
vpcs.each { |vpc|
|
2083
|
-
|
2084
|
-
|
2085
|
-
|
2086
|
-
|
2087
|
-
|
2088
|
-
|
2089
|
-
|
2090
|
-
|
2091
|
-
|
2092
|
-
|
2093
|
-
{
|
2094
|
-
name: "accepter-vpc-info.vpc-id",
|
2095
|
-
values: [vpc.vpc_id]
|
2096
|
-
}
|
2097
|
-
]
|
2098
|
-
).vpc_peering_connections)
|
2099
|
-
my_peer_conns.each { |cnxn|
|
2100
|
-
|
2101
|
-
[cnxn.accepter_vpc_info.vpc_id, cnxn.requester_vpc_info.vpc_id].each { |peer_vpc|
|
2102
|
-
MU::Cloud::AWS::VPC.listAllSubnetRouteTables(peer_vpc, region: region, credentials: credentials).each { |rtb_id|
|
2103
|
-
begin
|
2104
|
-
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_route_tables(
|
2105
|
-
route_table_ids: [rtb_id]
|
2106
|
-
)
|
2107
|
-
rescue Aws::EC2::Errors::InvalidRouteTableIDNotFound => e
|
2108
|
-
next
|
2109
|
-
end
|
2110
|
-
resp.route_tables.each { |rtb|
|
2111
|
-
rtb.routes.each { |route|
|
2112
|
-
if route.vpc_peering_connection_id == cnxn.vpc_peering_connection_id
|
2113
|
-
MU.log "Removing route #{route.destination_cidr_block} from route table #{rtb_id} in VPC #{peer_vpc}"
|
2114
|
-
MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_route(
|
2115
|
-
route_table_id: rtb_id,
|
2116
|
-
destination_cidr_block: route.destination_cidr_block
|
2117
|
-
) if !noop
|
2118
|
-
end
|
2119
|
-
}
|
2120
|
-
}
|
2121
|
-
}
|
2122
|
-
}
|
2123
|
-
MU.log "Deleting VPC peering connection #{cnxn.vpc_peering_connection_id}"
|
2124
|
-
begin
|
2125
|
-
MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_vpc_peering_connection(
|
2126
|
-
vpc_peering_connection_id: cnxn.vpc_peering_connection_id
|
2127
|
-
) if !noop
|
2128
|
-
rescue Aws::EC2::Errors::InvalidStateTransition => e
|
2129
|
-
MU.log "VPC peering connection #{cnxn.vpc_peering_connection_id} not in removable (state #{cnxn.status.code})", MU::WARN
|
2130
|
-
rescue Aws::EC2::Errors::OperationNotPermitted => e
|
2131
|
-
MU.log "VPC peering connection #{cnxn.vpc_peering_connection_id} refuses to delete: #{e.message}", MU::WARN
|
2132
|
-
end
|
1815
|
+
purge_peering_connections(noop, vpc.vpc_id, region: region, credentials: credentials)
|
1816
|
+
|
1817
|
+
on_retry = Proc.new {
|
1818
|
+
MU::Cloud.resourceClass("AWS", "FirewallRule").cleanup(
|
1819
|
+
noop: noop,
|
1820
|
+
region: region,
|
1821
|
+
credentials: credentials,
|
1822
|
+
flags: { "vpc_id" => vpc.vpc_id }
|
1823
|
+
)
|
1824
|
+
purge_gateways(noop, tagfilters, region: region, credentials: credentials)
|
2133
1825
|
}
|
2134
1826
|
|
2135
|
-
|
2136
|
-
begin
|
1827
|
+
MU.retrier([Aws::EC2::Errors::DependencyViolation], ignoreme: [Aws::EC2::Errors::InvalidVpcIDNotFound], max: 20, on_retry: on_retry) {
|
2137
1828
|
MU.log "Deleting VPC #{vpc.vpc_id}"
|
2138
1829
|
MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_vpc(vpc_id: vpc.vpc_id) if !noop
|
2139
|
-
|
2140
|
-
MU.log "VPC #{vpc.vpc_id} has already been deleted", MU::WARN
|
2141
|
-
rescue Aws::EC2::Errors::DependencyViolation => e
|
2142
|
-
if retries < 5
|
2143
|
-
MU.log "#{vpc.vpc_id} in #{region} had hidden dependencies, will try to remove them", MU::NOTICE
|
2144
|
-
retries += 1
|
2145
|
-
# fry some common rogue resources
|
2146
|
-
MU::Cloud::AWS::FirewallRule.cleanup(
|
2147
|
-
noop: noop,
|
2148
|
-
region: region,
|
2149
|
-
credentials: credentials,
|
2150
|
-
flags: { "vpc_id" => vpc.vpc_id }
|
2151
|
-
)
|
2152
|
-
purge_gateways(noop, tagfilters, region: region, credentials: credentials)
|
2153
|
-
sleep 10
|
2154
|
-
retry
|
2155
|
-
else
|
2156
|
-
MU.log "Failed to remove #{vpc.vpc_id} in #{region}: #{e.message}", MU::ERR
|
2157
|
-
next
|
2158
|
-
end
|
2159
|
-
end
|
1830
|
+
}
|
2160
1831
|
|
2161
1832
|
if !MU::Cloud::AWS.isGovCloud?(region)
|
2162
1833
|
mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu", region: region, credentials: credentials).values.first
|
2163
1834
|
if !mu_zone.nil?
|
2164
|
-
MU::Cloud
|
1835
|
+
MU::Cloud.resourceClass("AWS", "DNSZone").toggleVPCAccess(id: mu_zone.id, vpc_id: vpc.vpc_id, remove: true, credentials: credentials)
|
2165
1836
|
end
|
2166
1837
|
end
|
2167
1838
|
}
|
2168
1839
|
end
|
2169
|
-
|
2170
|
-
protected
|
2171
|
-
|
2172
|
-
# Subnets are almost a first-class resource. So let's kinda sorta treat
|
2173
|
-
# them like one. This should only be invoked on objects that already
|
2174
|
-
# exists in the cloud layer.
|
2175
|
-
class Subnet < MU::Cloud::AWS::VPC
|
2176
|
-
|
2177
|
-
attr_reader :cloud_id
|
2178
|
-
attr_reader :ip_block
|
2179
|
-
attr_reader :mu_name
|
2180
|
-
attr_reader :name
|
2181
|
-
attr_reader :az
|
2182
|
-
attr_reader :cloud_desc
|
2183
|
-
|
2184
|
-
# @param parent [MU::Cloud::AWS::VPC]: The parent VPC of this subnet.
|
2185
|
-
# @param config [Hash<String>]:
|
2186
|
-
def initialize(parent, config)
|
2187
|
-
@parent = parent
|
2188
|
-
@config = MU::Config.manxify(config)
|
2189
|
-
@cloud_id = config['cloud_id']
|
2190
|
-
@mu_name = config['mu_name']
|
2191
|
-
@name = config['name']
|
2192
|
-
@deploydata = config # This is a dummy for the sake of describe()
|
2193
|
-
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [@cloud_id]).subnets.first
|
2194
|
-
@az = resp.availability_zone
|
2195
|
-
@ip_block = resp.cidr_block
|
2196
|
-
@cloud_desc = resp # XXX this really isn't the cloud implementation's business
|
2197
|
-
|
2198
|
-
end
|
2199
|
-
|
2200
|
-
# Return the cloud identifier for the default route of this subnet.
|
2201
|
-
def defaultRoute
|
2202
|
-
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
|
2203
|
-
filters: [{name: "association.subnet-id", values: [@cloud_id]}]
|
2204
|
-
)
|
2205
|
-
if resp.route_tables.size == 0 # use default route table for the VPC
|
2206
|
-
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
|
2207
|
-
filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
|
2208
|
-
)
|
2209
|
-
end
|
2210
|
-
resp.route_tables.each { |route_table|
|
2211
|
-
route_table.routes.each { |route|
|
2212
|
-
if route.destination_cidr_block =="0.0.0.0/0" and route.state != "blackhole"
|
2213
|
-
return route.instance_id if !route.instance_id.nil?
|
2214
|
-
return route.gateway_id if !route.gateway_id.nil?
|
2215
|
-
return route.vpc_peering_connection_id if !route.vpc_peering_connection_id.nil?
|
2216
|
-
return route.network_interface_id if !route.network_interface_id.nil?
|
2217
|
-
end
|
2218
|
-
}
|
2219
|
-
}
|
2220
|
-
return nil
|
2221
|
-
end
|
2222
|
-
|
2223
|
-
# Is this subnet privately-routable only, or public?
|
2224
|
-
# @return [Boolean]
|
2225
|
-
def private?
|
2226
|
-
return false if @cloud_id.nil?
|
2227
|
-
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
|
2228
|
-
filters: [{name: "association.subnet-id", values: [@cloud_id]}]
|
2229
|
-
)
|
2230
|
-
if resp.route_tables.size == 0 # use default route table for the VPC
|
2231
|
-
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
|
2232
|
-
filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
|
2233
|
-
)
|
2234
|
-
end
|
2235
|
-
resp.route_tables.each { |route_table|
|
2236
|
-
route_table.routes.each { |route|
|
2237
|
-
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
|
2238
|
-
if route.destination_cidr_block == "0.0.0.0/0"
|
2239
|
-
return true if !route.instance_id.nil?
|
2240
|
-
return true if route.nat_gateway_id
|
2241
|
-
end
|
2242
|
-
}
|
2243
|
-
}
|
2244
|
-
return true
|
2245
|
-
end
|
2246
|
-
end
|
1840
|
+
private_class_method :purge_vpcs
|
2247
1841
|
|
2248
1842
|
end #class
|
2249
1843
|
end #class
|