cloud-mu 3.2.0 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/ansible/roles/mu-nat/tasks/main.yml +3 -0
  4. data/bin/mu-adopt +12 -1
  5. data/bin/mu-aws-setup +41 -7
  6. data/bin/mu-azure-setup +34 -0
  7. data/bin/mu-configure +214 -119
  8. data/bin/mu-gcp-setup +37 -2
  9. data/bin/mu-load-config.rb +2 -1
  10. data/bin/mu-node-manage +3 -0
  11. data/bin/mu-refresh-ssl +67 -0
  12. data/bin/mu-run-tests +28 -6
  13. data/bin/mu-self-update +30 -10
  14. data/bin/mu-upload-chef-artifacts +30 -26
  15. data/cloud-mu.gemspec +10 -8
  16. data/cookbooks/mu-master/attributes/default.rb +5 -1
  17. data/cookbooks/mu-master/metadata.rb +2 -2
  18. data/cookbooks/mu-master/recipes/default.rb +81 -26
  19. data/cookbooks/mu-master/recipes/init.rb +197 -62
  20. data/cookbooks/mu-master/recipes/update_nagios_only.rb +1 -1
  21. data/cookbooks/mu-master/recipes/vault.rb +78 -77
  22. data/cookbooks/mu-master/templates/default/mods/rewrite.conf.erb +1 -0
  23. data/cookbooks/mu-master/templates/default/nagios.conf.erb +103 -0
  24. data/cookbooks/mu-master/templates/default/web_app.conf.erb +14 -30
  25. data/cookbooks/mu-tools/attributes/default.rb +12 -0
  26. data/cookbooks/mu-tools/files/centos-6/CentOS-Base.repo +47 -0
  27. data/cookbooks/mu-tools/libraries/helper.rb +98 -4
  28. data/cookbooks/mu-tools/libraries/monkey.rb +1 -1
  29. data/cookbooks/mu-tools/recipes/apply_security.rb +31 -9
  30. data/cookbooks/mu-tools/recipes/aws_api.rb +8 -2
  31. data/cookbooks/mu-tools/recipes/base_repositories.rb +1 -1
  32. data/cookbooks/mu-tools/recipes/gcloud.rb +2 -9
  33. data/cookbooks/mu-tools/recipes/google_api.rb +7 -0
  34. data/cookbooks/mu-tools/recipes/rsyslog.rb +8 -1
  35. data/cookbooks/mu-tools/resources/disk.rb +113 -42
  36. data/cookbooks/mu-tools/resources/mommacat_request.rb +1 -2
  37. data/cookbooks/mu-tools/templates/centos-8/sshd_config.erb +215 -0
  38. data/extras/Gemfile.lock.bootstrap +394 -0
  39. data/extras/bucketstubs/error.html +0 -0
  40. data/extras/bucketstubs/index.html +0 -0
  41. data/extras/clean-stock-amis +11 -3
  42. data/extras/generate-stock-images +6 -3
  43. data/extras/git_rpm/build.sh +20 -0
  44. data/extras/git_rpm/mugit.spec +53 -0
  45. data/extras/image-generators/AWS/centos7.yaml +19 -16
  46. data/extras/image-generators/AWS/{rhel7.yaml → rhel71.yaml} +0 -0
  47. data/extras/image-generators/AWS/{win2k12.yaml → win2k12r2.yaml} +0 -0
  48. data/extras/image-generators/VMWare/centos8.yaml +15 -0
  49. data/extras/openssl_rpm/build.sh +19 -0
  50. data/extras/openssl_rpm/mussl.spec +46 -0
  51. data/extras/python_rpm/muthon.spec +14 -4
  52. data/extras/ruby_rpm/muby.spec +9 -5
  53. data/extras/sqlite_rpm/build.sh +19 -0
  54. data/extras/sqlite_rpm/muqlite.spec +47 -0
  55. data/install/installer +7 -5
  56. data/modules/mommacat.ru +2 -2
  57. data/modules/mu.rb +14 -7
  58. data/modules/mu/adoption.rb +5 -5
  59. data/modules/mu/cleanup.rb +47 -25
  60. data/modules/mu/cloud.rb +29 -1
  61. data/modules/mu/cloud/dnszone.rb +0 -2
  62. data/modules/mu/cloud/machine_images.rb +1 -1
  63. data/modules/mu/cloud/providers.rb +6 -1
  64. data/modules/mu/cloud/resource_base.rb +16 -7
  65. data/modules/mu/cloud/ssh_sessions.rb +5 -1
  66. data/modules/mu/cloud/wrappers.rb +20 -7
  67. data/modules/mu/config.rb +28 -12
  68. data/modules/mu/config/bucket.rb +31 -2
  69. data/modules/mu/config/cache_cluster.rb +1 -1
  70. data/modules/mu/config/cdn.rb +100 -0
  71. data/modules/mu/config/container_cluster.rb +1 -1
  72. data/modules/mu/config/database.rb +3 -3
  73. data/modules/mu/config/dnszone.rb +4 -3
  74. data/modules/mu/config/endpoint.rb +1 -0
  75. data/modules/mu/config/firewall_rule.rb +1 -1
  76. data/modules/mu/config/function.rb +16 -7
  77. data/modules/mu/config/job.rb +89 -0
  78. data/modules/mu/config/notifier.rb +7 -18
  79. data/modules/mu/config/ref.rb +55 -9
  80. data/modules/mu/config/schema_helpers.rb +12 -3
  81. data/modules/mu/config/server.rb +11 -5
  82. data/modules/mu/config/server_pool.rb +2 -2
  83. data/modules/mu/config/vpc.rb +11 -10
  84. data/modules/mu/defaults/AWS.yaml +106 -106
  85. data/modules/mu/deploy.rb +40 -14
  86. data/modules/mu/groomers/chef.rb +2 -2
  87. data/modules/mu/master.rb +70 -3
  88. data/modules/mu/mommacat.rb +28 -9
  89. data/modules/mu/mommacat/daemon.rb +13 -7
  90. data/modules/mu/mommacat/naming.rb +2 -2
  91. data/modules/mu/mommacat/search.rb +16 -5
  92. data/modules/mu/mommacat/storage.rb +67 -32
  93. data/modules/mu/providers/aws.rb +298 -85
  94. data/modules/mu/providers/aws/alarm.rb +5 -5
  95. data/modules/mu/providers/aws/bucket.rb +284 -50
  96. data/modules/mu/providers/aws/cache_cluster.rb +26 -26
  97. data/modules/mu/providers/aws/cdn.rb +782 -0
  98. data/modules/mu/providers/aws/collection.rb +16 -16
  99. data/modules/mu/providers/aws/container_cluster.rb +84 -64
  100. data/modules/mu/providers/aws/database.rb +59 -55
  101. data/modules/mu/providers/aws/dnszone.rb +29 -12
  102. data/modules/mu/providers/aws/endpoint.rb +535 -50
  103. data/modules/mu/providers/aws/firewall_rule.rb +32 -26
  104. data/modules/mu/providers/aws/folder.rb +1 -1
  105. data/modules/mu/providers/aws/function.rb +300 -134
  106. data/modules/mu/providers/aws/group.rb +16 -14
  107. data/modules/mu/providers/aws/habitat.rb +4 -4
  108. data/modules/mu/providers/aws/job.rb +469 -0
  109. data/modules/mu/providers/aws/loadbalancer.rb +67 -45
  110. data/modules/mu/providers/aws/log.rb +17 -17
  111. data/modules/mu/providers/aws/msg_queue.rb +22 -13
  112. data/modules/mu/providers/aws/nosqldb.rb +99 -8
  113. data/modules/mu/providers/aws/notifier.rb +137 -65
  114. data/modules/mu/providers/aws/role.rb +119 -83
  115. data/modules/mu/providers/aws/search_domain.rb +166 -30
  116. data/modules/mu/providers/aws/server.rb +209 -118
  117. data/modules/mu/providers/aws/server_pool.rb +95 -130
  118. data/modules/mu/providers/aws/storage_pool.rb +19 -11
  119. data/modules/mu/providers/aws/user.rb +5 -5
  120. data/modules/mu/providers/aws/userdata/linux.erb +5 -4
  121. data/modules/mu/providers/aws/vpc.rb +109 -54
  122. data/modules/mu/providers/aws/vpc_subnet.rb +43 -39
  123. data/modules/mu/providers/azure.rb +78 -12
  124. data/modules/mu/providers/azure/server.rb +20 -4
  125. data/modules/mu/providers/cloudformation/server.rb +1 -1
  126. data/modules/mu/providers/google.rb +21 -5
  127. data/modules/mu/providers/google/bucket.rb +1 -1
  128. data/modules/mu/providers/google/container_cluster.rb +1 -1
  129. data/modules/mu/providers/google/database.rb +1 -1
  130. data/modules/mu/providers/google/firewall_rule.rb +1 -1
  131. data/modules/mu/providers/google/folder.rb +7 -3
  132. data/modules/mu/providers/google/function.rb +66 -31
  133. data/modules/mu/providers/google/group.rb +1 -1
  134. data/modules/mu/providers/google/habitat.rb +1 -1
  135. data/modules/mu/providers/google/loadbalancer.rb +1 -1
  136. data/modules/mu/providers/google/role.rb +6 -3
  137. data/modules/mu/providers/google/server.rb +1 -1
  138. data/modules/mu/providers/google/server_pool.rb +1 -1
  139. data/modules/mu/providers/google/user.rb +1 -1
  140. data/modules/mu/providers/google/vpc.rb +28 -3
  141. data/modules/tests/aws-jobs-functions.yaml +46 -0
  142. data/modules/tests/aws-servers-with-handrolled-iam.yaml +37 -0
  143. data/modules/tests/centos6.yaml +4 -0
  144. data/modules/tests/centos7.yaml +4 -0
  145. data/modules/tests/ecs.yaml +2 -2
  146. data/modules/tests/eks.yaml +1 -1
  147. data/modules/tests/functions/node-function/lambda_function.js +10 -0
  148. data/modules/tests/functions/python-function/lambda_function.py +12 -0
  149. data/modules/tests/k8s.yaml +1 -1
  150. data/modules/tests/microservice_app.yaml +288 -0
  151. data/modules/tests/rds.yaml +5 -5
  152. data/modules/tests/regrooms/rds.yaml +5 -5
  153. data/modules/tests/server-with-scrub-muisms.yaml +1 -1
  154. data/modules/tests/super_complex_bok.yml +2 -2
  155. data/modules/tests/super_simple_bok.yml +2 -2
  156. metadata +42 -17
@@ -29,7 +29,7 @@ module MU
29
29
  # @return [String]: The cloud provider's identifier for this storage pool.
30
30
  def create
31
31
  MU.log "Creating storage pool #{@mu_name}"
32
- resp = MU::Cloud::AWS.efs(region: @config['region'], credentials: @config['credentials']).create_file_system(
32
+ resp = MU::Cloud::AWS.efs(region: @region, credentials: @credentials).create_file_system(
33
33
  creation_token: @mu_name,
34
34
  performance_mode: @config['storage_type']
35
35
  )
@@ -37,7 +37,7 @@ module MU
37
37
  attempts = 0
38
38
  loop do
39
39
  MU.log "Waiting for #{@mu_name}: #{resp.file_system_id} to become available" if attempts % 5 == 0
40
- storage_pool = MU::Cloud::AWS.efs(region: @config['region'], credentials: @config['credentials']).describe_file_systems(
40
+ storage_pool = MU::Cloud::AWS.efs(region: @region, credentials: @credentials).describe_file_systems(
41
41
  creation_token: @mu_name
42
42
  ).file_systems.first
43
43
  break if storage_pool.life_cycle_state == "available"
@@ -47,7 +47,7 @@ module MU
47
47
  raise MuError, "timed out waiting for #{resp.mount_target_id }" if attempts >= 20
48
48
  end
49
49
 
50
- addStandardTags(cloud_id: resp.file_system_id, region: @config['region'], credentials: @config['credentials'])
50
+ addStandardTags(cloud_id: resp.file_system_id, region: @region, credentials: @credentials)
51
51
  @cloud_id = resp.file_system_id
52
52
 
53
53
  if @config['mount_points'] && !@config['mount_points'].empty?
@@ -82,8 +82,8 @@ module MU
82
82
  ip_address: target['ip_address'],
83
83
  subnet_id: target['vpc']['subnet_id'],
84
84
  security_groups: sgs,
85
- credentials: @config['credentials'],
86
- region: @config['region']
85
+ credentials: @credentials,
86
+ region: @region
87
87
  )
88
88
  target['cloud_id'] = mount_target.mount_target_id
89
89
  }
@@ -100,7 +100,7 @@ module MU
100
100
  # Canonical Amazon Resource Number for this resource
101
101
  # @return [String]
102
102
  def arn
103
- "arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":elasticfilesystem:"+@config['region']+":"+MU::Cloud::AWS.credToAcct(@config['credentials'])+":file-system/"+@cloud_id
103
+ "arn:"+(MU::Cloud::AWS.isGovCloud?(@region) ? "aws-us-gov" : "aws")+":elasticfilesystem:"+@region+":"+MU::Cloud::AWS.credToAcct(@credentials)+":file-system/"+@cloud_id
104
104
  end
105
105
 
106
106
  # Locate an existing storage pool and return an array containing matching AWS resource descriptors for those that match.
@@ -254,14 +254,14 @@ module MU
254
254
 
255
255
  # Register a description of this storage pool with this deployment's metadata.
256
256
  def notify
257
- storage_pool = MU::Cloud::AWS.efs(region: @config['region'], credentials: @config['credentials']).describe_file_systems(
257
+ storage_pool = MU::Cloud::AWS.efs(region: @region, credentials: @credentials).describe_file_systems(
258
258
  creation_token: @mu_name
259
259
  ).file_systems.first
260
260
 
261
261
  targets = {}
262
262
 
263
263
  if @config['mount_points'] && !@config['mount_points'].empty?
264
- mount_targets = MU::Cloud::AWS.efs(region: @config['region'], credentials: @config['credentials']).describe_mount_targets(
264
+ mount_targets = MU::Cloud::AWS.efs(region: @region, credentials: @credentials).describe_mount_targets(
265
265
  file_system_id: storage_pool.file_system_id
266
266
  ).mount_targets
267
267
 
@@ -274,6 +274,10 @@ module MU
274
274
  subnet_obj = mp_vpc.subnets.select { |s|
275
275
  s.name == mp["vpc"]["subnet_name"] or s.cloud_id == mp["vpc"]["subnet_id"]
276
276
  }.first
277
+ if !subnet_obj
278
+ MU.log "Failed to find live subnet matching configured mount_point", MU::WARN, details: mp["vpc"]
279
+ next
280
+ end
277
281
  mount_target = nil
278
282
  mount_targets.each { |t|
279
283
  subnet_cidr_obj = NetAddr::IPv4Net.parse(subnet_obj.ip_block)
@@ -283,6 +287,10 @@ module MU
283
287
  break
284
288
  end
285
289
  }
290
+ if !mount_target
291
+ MU.log "Failed to find live mount_target corresponding to configured mount_point", MU::WARN, details: mp
292
+ next
293
+ end
286
294
 
287
295
  targets[mp["name"]] = {
288
296
  "owner_id" => mount_target.owner_id,
@@ -294,7 +302,7 @@ module MU
294
302
  "availability_zone" => subnet.availability_zone,
295
303
  "state" => mount_target.life_cycle_state,
296
304
  "ip_address" => mount_target.ip_address,
297
- "endpoint" => "#{subnet.availability_zone}.#{mount_target.file_system_id}.efs.#{@config['region']}.amazonaws.com",
305
+ "endpoint" => "#{subnet.availability_zone}.#{mount_target.file_system_id}.efs.#{@region}.amazonaws.com",
298
306
  "network_interface_id" => mount_target.network_interface_id
299
307
  }
300
308
  }
@@ -333,7 +341,7 @@ module MU
333
341
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
334
342
  # @param region [String]: The cloud provider region in which to operate
335
343
  # @return [void]
336
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
344
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
337
345
  MU.log "AWS::StoragePool.cleanup: need to support flags['known']", MU::DEBUG, details: flags
338
346
 
339
347
  supported_regions = %w{us-west-2 us-east-1 eu-west-1}
@@ -358,7 +366,7 @@ module MU
358
366
  found_muid = false
359
367
  found_master = false
360
368
  tags.each { |tag|
361
- found_muid = true if tag.key == "MU-ID" && tag.value == MU.deploy_id
369
+ found_muid = true if tag.key == "MU-ID" && tag.value == deploy_id
362
370
  found_master = true if tag.key == "MU-MASTER-IP" && tag.value == MU.mu_public_ip
363
371
  }
364
372
  next if !found_muid
@@ -190,16 +190,16 @@ module MU
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
192
  # @return [void]
193
- def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
193
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
194
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: "/"+MU.deploy_id+"/"
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 /#{MU.deploy_id}/#{policy.policy_name}"
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(
@@ -277,7 +277,7 @@ MU.log e.inspect, MU::ERR, details: policy
277
277
  has_ourdeploy = false
278
278
  has_ourmaster = false
279
279
  tags.each { |tag|
280
- if tag.key == "MU-ID" and tag.value == MU.deploy_id
280
+ if tag.key == "MU-ID" and tag.value == deploy_id
281
281
  has_ourdeploy = true
282
282
  elsif tag.key == "MU-MASTER-IP" and tag.value == MU.mu_public_ip
283
283
  has_ourmaster = true
@@ -430,7 +430,7 @@ MU.log e.inspect, MU::ERR, details: policy
430
430
  if resp and resp.policy_names and resp.policy_names.size > 0
431
431
  resp.policy_names.each { |pol_name|
432
432
  pol = MU::Cloud::AWS.iam(credentials: @credentials).get_user_policy(user_name: @cloud_id, policy_name: pol_name)
433
- doc = JSON.parse(URI.decode(pol.policy_document))
433
+ doc = JSON.parse(CGI.unescape(pol.policy_document))
434
434
  bok["inline_policies"] = MU::Cloud.resourceClass("AWS", "Role").doc2MuPolicies(pol.policy_name, doc, bok["inline_policies"])
435
435
  }
436
436
  end
@@ -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
- service ssh stop
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
- service ssh start
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
- service sshd stop
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
- service sshd start
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'
@@ -35,7 +35,7 @@ module MU
35
35
  # Called automatically by {MU::Deploy#createResources}
36
36
  def create
37
37
  MU.log "Creating VPC #{@mu_name}", details: @config
38
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_vpc(cidr_block: @config['ip_block']).vpc
38
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_vpc(cidr_block: @config['ip_block']).vpc
39
39
  @cloud_id = resp.vpc_id
40
40
  @config['vpc_id'] = @cloud_id
41
41
 
@@ -45,10 +45,10 @@ module MU
45
45
  begin
46
46
  MU.log "Waiting for VPC #{@mu_name} (#{@cloud_id}) to be available", MU::NOTICE
47
47
  sleep 5
48
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpcs(vpc_ids: [@cloud_id]).vpcs.first
48
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_vpcs(vpc_ids: [@cloud_id]).vpcs.first
49
49
  end while resp.state != "available"
50
50
  # There's a default route table that comes with. Let's tag it.
51
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
51
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_route_tables(
52
52
  filters: [
53
53
  {
54
54
  name: "vpc-id",
@@ -63,13 +63,13 @@ module MU
63
63
 
64
64
  if @config['create_internet_gateway']
65
65
  MU.log "Creating Internet Gateway #{@mu_name}"
66
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_internet_gateway
66
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_internet_gateway
67
67
  internet_gateway_id = resp.internet_gateway.internet_gateway_id
68
68
  sleep 5
69
69
 
70
70
  tag_me(internet_gateway_id)
71
71
 
72
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).attach_internet_gateway(vpc_id: @cloud_id, internet_gateway_id: internet_gateway_id)
72
+ MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).attach_internet_gateway(vpc_id: @cloud_id, internet_gateway_id: internet_gateway_id)
73
73
  @config['internet_gateway_id'] = internet_gateway_id
74
74
  end
75
75
 
@@ -93,7 +93,7 @@ module MU
93
93
  config[:policy_document] = statement.to_json
94
94
  end
95
95
 
96
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_vpc_endpoint(config).vpc_endpoint
96
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_vpc_endpoint(config).vpc_endpoint
97
97
  endpoint_id = resp.vpc_endpoint_id
98
98
  MU.log "Creating VPC endpoint #{endpoint_id}"
99
99
  attempts = 0
@@ -102,7 +102,7 @@ module MU
102
102
  MU.log "Waiting for VPC endpoint #{endpoint_id} to become available" if attempts % 5 == 0
103
103
  sleep 10
104
104
  begin
105
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint_id]).vpc_endpoints.first
105
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint_id]).vpc_endpoints.first
106
106
  rescue Aws::EmptyStructure, NoMethodError
107
107
  sleep 5
108
108
  retry
@@ -119,7 +119,7 @@ module MU
119
119
  logrole = @deploy.findLitterMate(name: @config['name']+"logrole", type: "roles")
120
120
 
121
121
  MU.log "Enabling traffic logging on VPC #{@mu_name} to log group #{loggroup.mu_name}"
122
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_flow_logs(
122
+ MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_flow_logs(
123
123
  resource_ids: [@cloud_id],
124
124
  resource_type: "VPC",
125
125
  traffic_type: "ALL",
@@ -150,7 +150,7 @@ module MU
150
150
  MU.log "Creating route for #{route['destination_network']} through NAT gatway #{gateway['id']}", details: route_config
151
151
  MU.retrier([Aws::EC2::Errors::InvalidNatGatewayIDNotFound], wait: 10, max: 5) {
152
152
  begin
153
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(route_config)
153
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_route(route_config)
154
154
  rescue Aws::EC2::Errors::RouteAlreadyExists
155
155
  MU.log "Attempt to create duplicate route to #{route['destination_network']} for #{gateway['id']} in #{rtb['route_table_id']}", MU::WARN
156
156
  end
@@ -163,14 +163,14 @@ module MU
163
163
 
164
164
  if @config['enable_dns_support']
165
165
  MU.log "Enabling DNS support in #{@mu_name}"
166
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_vpc_attribute(
166
+ MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).modify_vpc_attribute(
167
167
  vpc_id: @cloud_id,
168
168
  enable_dns_support: {value: @config['enable_dns_support']}
169
169
  )
170
170
  end
171
171
  if @config['enable_dns_hostnames']
172
172
  MU.log "Enabling DNS hostnames in #{@mu_name}"
173
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_vpc_attribute(
173
+ MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).modify_vpc_attribute(
174
174
  vpc_id: @cloud_id,
175
175
  enable_dns_hostnames: {value: @config['enable_dns_hostnames']}
176
176
  )
@@ -196,20 +196,20 @@ module MU
196
196
  dhcpopts << {key: "netbios-name-servers", values: @config['dhcp']['netbios_servers']}
197
197
  end
198
198
 
199
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_dhcp_options(
199
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_dhcp_options(
200
200
  dhcp_configurations: dhcpopts
201
201
  )
202
202
  dhcpopt_id = resp.dhcp_options.dhcp_options_id
203
203
  tag_me(dhcpopt_id)
204
204
 
205
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).associate_dhcp_options(dhcp_options_id: dhcpopt_id, vpc_id: @cloud_id)
205
+ MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).associate_dhcp_options(dhcp_options_id: dhcpopt_id, vpc_id: @cloud_id)
206
206
  end
207
207
  notify
208
208
 
209
- if !MU::Cloud::AWS.isGovCloud?(@config['region'])
210
- mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu", credentials: @config['credentials']).values.first
209
+ if !MU::Cloud::AWS.isGovCloud?(@region)
210
+ mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu", credentials: @credentials).values.first
211
211
  if !mu_zone.nil?
212
- MU::Cloud.resourceClass("AWS", "DNSZone").toggleVPCAccess(id: mu_zone.id, vpc_id: @cloud_id, region: @config['region'], credentials: @config['credentials'])
212
+ MU::Cloud.resourceClass("AWS", "DNSZone").toggleVPCAccess(id: mu_zone.id, vpc_id: @cloud_id, region: @region, credentials: @credentials)
213
213
  end
214
214
  end
215
215
  loadSubnets
@@ -220,7 +220,7 @@ module MU
220
220
  # Canonical Amazon Resource Number for this resource
221
221
  # @return [String]
222
222
  def arn
223
- "arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":ec2:"+@config['region']+":"+MU::Cloud::AWS.credToAcct(@config['credentials'])+":vpc/"+@cloud_id
223
+ "arn:"+(MU::Cloud::AWS.isGovCloud?(@region) ? "aws-us-gov" : "aws")+":ec2:"+@region+":"+MU::Cloud::AWS.credToAcct(@credentials)+":vpc/"+@cloud_id
224
224
  end
225
225
 
226
226
  # Describe this VPC
@@ -263,7 +263,7 @@ module MU
263
263
  route_config[:instance_id] = nat_instance.cloud_id
264
264
 
265
265
  MU.log "Creating route for #{route['destination_network']} through NAT host #{nat_instance.cloud_id}", details: route_config
266
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(route_config)
266
+ MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_route(route_config)
267
267
  end
268
268
  }
269
269
 
@@ -327,9 +327,9 @@ module MU
327
327
  def toKitten(**_args)
328
328
  bok = {
329
329
  "cloud" => "AWS",
330
- "credentials" => @config['credentials'],
330
+ "credentials" => @credentials,
331
331
  "cloud_id" => @cloud_id,
332
- "region" => @config['region']
332
+ "region" => @region
333
333
  }
334
334
 
335
335
  if !cloud_desc
@@ -352,7 +352,7 @@ module MU
352
352
 
353
353
  bok['create_bastion'] = false # XXX figure out a way to detect this
354
354
 
355
- logs = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @credentials).describe_flow_logs(filter: [{ "name" => "resource-id", "values" => [@cloud_id] }])
355
+ logs = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_flow_logs(filter: [{ "name" => "resource-id", "values" => [@cloud_id] }])
356
356
  if logs and logs.flow_logs and !logs.flow_logs.empty?
357
357
  bok['enable_traffic_logging'] = true
358
358
  bok['traffic_type_to_log'] = logs.flow_logs.first.traffic_type.downcase
@@ -362,13 +362,13 @@ module MU
362
362
  end
363
363
  end
364
364
 
365
- nats = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @credentials).describe_nat_gateways(filter: [{ "name" => "vpc-id", "values" => [@cloud_id] }])
365
+ nats = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_nat_gateways(filter: [{ "name" => "vpc-id", "values" => [@cloud_id] }])
366
366
  if nats and nats.nat_gateways and !nats.nat_gateways.empty?
367
367
  bok['create_nat_gateway'] = true
368
368
  bok['nat_gateway_multi_az'] = true if nats.nat_gateways.size > 1
369
369
  end
370
370
 
371
- rtbs = MU::Cloud::AWS::VPC.get_route_tables(vpc_ids: [@cloud_id], region: @config['region'], credentials: @credentials)
371
+ rtbs = MU::Cloud::AWS::VPC.get_route_tables(vpc_ids: [@cloud_id], region: @region, credentials: @credentials)
372
372
 
373
373
  associations = {}
374
374
  if rtbs and !rtbs.empty?
@@ -454,13 +454,13 @@ module MU
454
454
  def loadSubnets
455
455
  return [] if !@cloud_id
456
456
 
457
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(
457
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_subnets(
458
458
  filters: [
459
459
  { name: "vpc-id", values: [@cloud_id] }
460
460
  ]
461
461
  )
462
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
463
+ MU.log "Got empty results when trying to list subnets in #{@cloud_id} (#{@region})", MU::WARN
464
464
  return []
465
465
  end
466
466
 
@@ -473,8 +473,8 @@ module MU
473
473
  if !@config.nil? and @config.has_key?("subnets")
474
474
  @config['subnets'].each { |subnet|
475
475
  subnet['mu_name'] ||= @mu_name+"-"+subnet['name']
476
- subnet['region'] = @config['region']
477
- subnet['credentials'] = @config['credentials']
476
+ subnet['region'] = @region
477
+ subnet['credentials'] = @credentials
478
478
  resp.subnets.each { |desc|
479
479
  if desc.cidr_block == subnet["ip_block"]
480
480
  subnet["tags"] = MU.structToHash(desc.tags)
@@ -500,15 +500,32 @@ module MU
500
500
  # Of course we might be loading up a dummy subnet object from a
501
501
  # foreign or non-Mu-created VPC and subnet. So make something up.
502
502
  if @subnets.empty?
503
+ nets_by_block = {}
504
+
505
+ # Attempt to dig the canonical resource name out of
506
+ # deployment metadata, if it exists
507
+ if @deploy and @deploy.deployment and
508
+ @deploy.deployment['vpcs'] and
509
+ @deploy.deployment['vpcs'][@config['name']] and
510
+ @deploy.deployment['vpcs'][@config['name']]['subnets']
511
+ @deploy.deployment['vpcs'][@config['name']]['subnets'].each { |s|
512
+ nets_by_block[s["ip_block"]] = s
513
+ }
514
+ end
515
+
503
516
  resp.subnets.each { |desc|
504
517
  subnet = {
505
518
  "ip_block" => desc.cidr_block,
506
519
  "tags" => MU.structToHash(desc.tags),
507
520
  "cloud_id" => desc.subnet_id,
508
- 'region' => @config['region'],
509
- 'credentials' => @config['credentials'],
521
+ 'region' => @region,
522
+ 'credentials' => @credentials,
510
523
  }
511
- subnet['name'] = subnet["ip_block"].gsub(/[\.\/]/, "_")
524
+ if nets_by_block[desc.cidr_block] and
525
+ nets_by_block[desc.cidr_block]["name"]
526
+ subnet['name'] = nets_by_block[desc.cidr_block]["name"]
527
+ end
528
+ subnet['name'] ||= subnet["ip_block"].gsub(/[\.\/]/, "_")
512
529
  subnet['mu_name'] = @mu_name+"-"+subnet['name']
513
530
  @subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
514
531
  }
@@ -571,7 +588,7 @@ module MU
571
588
  @config['cloud'],
572
589
  "server",
573
590
  name: nat_name,
574
- region: @config['region'],
591
+ region: @region,
575
592
  cloud_id: nat_cloud_id,
576
593
  deploy_id: deploy_id,
577
594
  tag_key: nat_tag_key,
@@ -822,11 +839,11 @@ module MU
822
839
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
823
840
  # @param region [String]: The cloud provider region
824
841
  # @return [void]
825
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
842
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
826
843
  MU.log "AWS::VPC.cleanup: need to support flags['known']", MU::DEBUG, details: flags
827
844
 
828
845
  tagfilters = [
829
- {name: "tag:MU-ID", values: [MU.deploy_id]}
846
+ {name: "tag:MU-ID", values: [deploy_id]}
830
847
  ]
831
848
  if !ignoremaster
832
849
  tagfilters << {name: "tag:MU-MASTER-IP", values: [MU.mu_public_ip]}
@@ -838,7 +855,7 @@ module MU
838
855
  vpcs = resp if !resp.empty?
839
856
  }
840
857
 
841
- # resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
858
+ # resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_vpc_peering_connections(
842
859
  # filters: [
843
860
  # {
844
861
  # name: "requester-vpc-info.vpc-id",
@@ -873,10 +890,11 @@ module MU
873
890
  purge_subnets(noop, tagfilters, region: region, credentials: credentials)
874
891
  purge_vpcs(noop, tagfilters, region: region, credentials: credentials)
875
892
  purge_dhcpopts(noop, tagfilters, region: region, credentials: credentials)
893
+ purge_eips(noop, tagfilters, region: region, credentials: credentials)
876
894
 
877
895
  # unless noop
878
896
  # MU::Cloud::AWS.iam.list_roles.roles.each{ |role|
879
- # match_string = "#{MU.deploy_id}.*TRAFFIC-LOG"
897
+ # match_string = "#{deploy_id}.*TRAFFIC-LOG"
880
898
  # }
881
899
  # end
882
900
  end
@@ -1019,7 +1037,7 @@ module MU
1019
1037
  subnet_routes[table['name']].each { |subnet|
1020
1038
  nat_routes[subnet] = route['nat_host_name']
1021
1039
  }
1022
- MU::Config.addDependency(vpc, route['nat_host_name'], "server", no_create_wait: true)
1040
+ MU::Config.addDependency(vpc, route['nat_host_name'], "server", my_phase: "groom")
1023
1041
  elsif route['gateway'] == '#NAT'
1024
1042
  vpc['create_nat_gateway'] = true
1025
1043
  private_rtbs << table['name']
@@ -1118,7 +1136,7 @@ module MU
1118
1136
  if subnets and subnets.size > 0
1119
1137
  filters << { :name => "association.subnet-id", :values => subnets }
1120
1138
  end
1121
- tables = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
1139
+ tables = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_route_tables(
1122
1140
  filters: filters
1123
1141
  )
1124
1142
  cidrs = []
@@ -1319,7 +1337,7 @@ module MU
1319
1337
  id: @cloud_id,
1320
1338
  cloud: "AWS",
1321
1339
  credentials: @credentials,
1322
- region: @config['region'],
1340
+ region: @region,
1323
1341
  type: "vpcs",
1324
1342
  subnet_pref: subnet_pref
1325
1343
  )
@@ -1330,6 +1348,9 @@ module MU
1330
1348
  def peerWith(peer)
1331
1349
  peer_ref = MU::Config::Ref.get(peer['vpc'])
1332
1350
  peer_obj = peer_ref.kitten
1351
+ if !peer_obj
1352
+ raise MuError.new "#{@mu_name}: Failed to locate my peer VPC", details: peer_ref.to_h
1353
+ end
1333
1354
  peer_id = peer_ref.kitten.cloud_id
1334
1355
  if peer_id == @cloud_id
1335
1356
  MU.log "#{@mu_name} attempted to peer with itself (#{@cloud_id})", MU::ERR, details: peer
@@ -1353,7 +1374,7 @@ module MU
1353
1374
 
1354
1375
  # See if the peering connection exists before we bother
1355
1376
  # creating it.
1356
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
1377
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_vpc_peering_connections(
1357
1378
  filters: [
1358
1379
  {
1359
1380
  name: "requester-vpc-info.vpc-id",
@@ -1369,8 +1390,8 @@ module MU
1369
1390
  peering_id = if !resp or !resp.vpc_peering_connections or
1370
1391
  resp.vpc_peering_connections.empty?
1371
1392
 
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(
1393
+ MU.log "Setting peering connection from VPC #{@config['name']} (#{@cloud_id} in account #{MU::Cloud::AWS.credToAcct(@credentials)}) to #{peer_id} in account #{peer['account']}", details: peer
1394
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_vpc_peering_connection(
1374
1395
  vpc_id: @cloud_id,
1375
1396
  peer_vpc_id: peer_id,
1376
1397
  peer_owner_id: peer['account'],
@@ -1386,13 +1407,13 @@ module MU
1386
1407
  tag_me(peering_id, peering_name)
1387
1408
 
1388
1409
  # Create routes to our new friend.
1389
- MU::Cloud::AWS::VPC.listAllSubnetRouteTables(@cloud_id, region: @config['region'], credentials: @config['credentials']).each { |rtb_id|
1410
+ MU::Cloud::AWS::VPC.listAllSubnetRouteTables(@cloud_id, region: @region, credentials: @credentials).each { |rtb_id|
1390
1411
  my_route_config = {
1391
1412
  :route_table_id => rtb_id,
1392
1413
  :destination_cidr_block => peer_obj.cloud_desc.cidr_block,
1393
1414
  :vpc_peering_connection_id => peering_id
1394
1415
  }
1395
- rtbdesc = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
1416
+ rtbdesc = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_route_tables(
1396
1417
  route_table_ids: [rtb_id]
1397
1418
  ).route_tables.first
1398
1419
  already_exists = false
@@ -1408,18 +1429,18 @@ module MU
1408
1429
  }
1409
1430
  next if already_exists
1410
1431
 
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)
1432
+ MU.log "Creating peering route to #{peer_obj.cloud_desc.cidr_block} in #{peer['vpc']['region']} from VPC #{@config['name']} in #{@region}"
1433
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_route(my_route_config)
1413
1434
  } # MU::Cloud::AWS::VPC.listAllSubnetRouteTables
1414
1435
 
1415
1436
  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
1437
 
1417
- cnxn = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
1438
+ cnxn = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_vpc_peering_connections(
1418
1439
  vpc_peering_connection_ids: [peering_id]
1419
1440
  ).vpc_peering_connections.first
1420
1441
 
1421
1442
  loop_if = Proc.new {
1422
- cnxn = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
1443
+ cnxn = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_vpc_peering_connections(
1423
1444
  vpc_peering_connection_ids: [peering_id]
1424
1445
  ).vpc_peering_connections.first
1425
1446
  ((can_auto_accept and cnxn.status.code == "pending-acceptance") or (cnxn.status.code != "active" and cnxn.status.code != "pending-acceptance"))
@@ -1448,9 +1469,9 @@ module MU
1448
1469
  end
1449
1470
 
1450
1471
  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
1472
+ MU.log "VPC peering connection from VPC #{@config['name']} (#{@cloud_id} in #{@region}) to #{peer_id} in #{peer_obj.config['region']} #{cnxn.status.code}: #{cnxn.status.message}", MU::ERR
1452
1473
  begin
1453
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).delete_vpc_peering_connection(
1474
+ MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).delete_vpc_peering_connection(
1454
1475
  vpc_peering_connection_id: peering_id
1455
1476
  )
1456
1477
  rescue Aws::EC2::Errors::InvalidStateTransition
@@ -1466,8 +1487,8 @@ module MU
1466
1487
  def tag_me(resource_id = @cloud_id, name = @mu_name)
1467
1488
  MU::Cloud::AWS.createStandardTags(
1468
1489
  resource_id,
1469
- region: @config['region'],
1470
- credentials: @config['credentials'],
1490
+ region: @region,
1491
+ credentials: @credentials,
1471
1492
  optional: @config['optional_tags'],
1472
1493
  nametag: name,
1473
1494
  othertags: @config['tags']
@@ -1481,8 +1502,8 @@ module MU
1481
1502
  def createRouteTable(rtb)
1482
1503
  vpc_id = @cloud_id
1483
1504
  vpc_name = @config['name']
1484
- MU.setVar("curRegion", @config['region']) if !@config['region'].nil?
1485
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route_table(vpc_id: vpc_id).route_table
1505
+ MU.setVar("curRegion", @region) if !@region.nil?
1506
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_route_table(vpc_id: vpc_id).route_table
1486
1507
  route_table_id = rtb['route_table_id'] = resp.route_table_id
1487
1508
  sleep 5
1488
1509
 
@@ -1503,7 +1524,7 @@ module MU
1503
1524
  unless route['gateway'] == '#NAT'
1504
1525
  # Need to change the order of how things are created to create the route here
1505
1526
  MU.log "Creating route for #{route['destination_network']}", details: route_config
1506
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(route_config)
1527
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_route(route_config)
1507
1528
  end
1508
1529
  end
1509
1530
  }
@@ -1611,6 +1632,40 @@ module MU
1611
1632
  end
1612
1633
  private_class_method :purge_nat_gateways
1613
1634
 
1635
+ # Remove all Elastic IPs from the currently loaded deployment.
1636
+ # @param noop [Boolean]: If true, will only print what would be done
1637
+ # @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
1638
+ # @param region [String]: The cloud provider region
1639
+ # @return [void]
1640
+ def self.purge_eips(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
1641
+ eips = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_addresses(
1642
+ filters: tagfilters
1643
+ ).addresses
1644
+
1645
+ threads = []
1646
+
1647
+ if !eips.empty?
1648
+ eips.each { |eip|
1649
+ MU.log "Releasing EIP #{eip.public_ip} (#{eip.allocation_id})"
1650
+ next if noop
1651
+ if eip.association_id
1652
+ MU.log "Tags tell me I should release EIP #{eip.public_ip} (#{eip.allocation_id}), but it appears to be associated with something", MU::WARN, details: eip
1653
+ next
1654
+ end
1655
+ threads << Thread.new {
1656
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).release_address(allocation_id: eip.allocation_id)
1657
+ }
1658
+ }
1659
+ end
1660
+
1661
+ threads.each { |t|
1662
+ t.join
1663
+ }
1664
+
1665
+ return nil
1666
+ end
1667
+ private_class_method :purge_eips
1668
+
1614
1669
  # Remove all VPC endpoints associated with the VPC of the currently loaded deployment.
1615
1670
  # @param noop [Boolean]: If true, will only print what would be done
1616
1671
  # @param vpc_id [String]: The cloud provider's unique VPC identifier