cloud-mu 3.4.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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/ansible/roles/mu-nat/tasks/main.yml +3 -0
  3. data/bin/mu-aws-setup +41 -7
  4. data/bin/mu-azure-setup +34 -0
  5. data/bin/mu-configure +214 -119
  6. data/bin/mu-gcp-setup +37 -2
  7. data/bin/mu-node-manage +3 -0
  8. data/bin/mu-refresh-ssl +67 -0
  9. data/bin/mu-run-tests +14 -4
  10. data/bin/mu-self-update +30 -10
  11. data/bin/mu-upload-chef-artifacts +30 -26
  12. data/cloud-mu.gemspec +8 -6
  13. data/cookbooks/mu-master/attributes/default.rb +5 -1
  14. data/cookbooks/mu-master/metadata.rb +2 -2
  15. data/cookbooks/mu-master/recipes/default.rb +81 -26
  16. data/cookbooks/mu-master/recipes/init.rb +197 -62
  17. data/cookbooks/mu-master/recipes/update_nagios_only.rb +1 -1
  18. data/cookbooks/mu-master/recipes/vault.rb +78 -77
  19. data/cookbooks/mu-master/templates/default/mods/rewrite.conf.erb +1 -0
  20. data/cookbooks/mu-master/templates/default/nagios.conf.erb +103 -0
  21. data/cookbooks/mu-master/templates/default/web_app.conf.erb +14 -30
  22. data/cookbooks/mu-tools/attributes/default.rb +5 -0
  23. data/cookbooks/mu-tools/files/centos-6/CentOS-Base.repo +47 -0
  24. data/cookbooks/mu-tools/libraries/helper.rb +12 -2
  25. data/cookbooks/mu-tools/libraries/monkey.rb +1 -1
  26. data/cookbooks/mu-tools/recipes/apply_security.rb +6 -0
  27. data/cookbooks/mu-tools/recipes/aws_api.rb +6 -4
  28. data/cookbooks/mu-tools/recipes/base_repositories.rb +1 -1
  29. data/cookbooks/mu-tools/recipes/gcloud.rb +2 -9
  30. data/cookbooks/mu-tools/recipes/google_api.rb +5 -2
  31. data/cookbooks/mu-tools/resources/disk.rb +108 -58
  32. data/extras/Gemfile.lock.bootstrap +394 -0
  33. data/extras/bucketstubs/error.html +0 -0
  34. data/extras/bucketstubs/index.html +0 -0
  35. data/extras/clean-stock-amis +9 -9
  36. data/extras/git_rpm/build.sh +20 -0
  37. data/extras/git_rpm/mugit.spec +53 -0
  38. data/extras/image-generators/VMWare/centos8.yaml +15 -0
  39. data/extras/openssl_rpm/build.sh +19 -0
  40. data/extras/openssl_rpm/mussl.spec +46 -0
  41. data/extras/python_rpm/muthon.spec +14 -4
  42. data/extras/ruby_rpm/muby.spec +9 -5
  43. data/extras/sqlite_rpm/build.sh +19 -0
  44. data/extras/sqlite_rpm/muqlite.spec +47 -0
  45. data/install/installer +7 -5
  46. data/modules/mu.rb +12 -5
  47. data/modules/mu/cloud/machine_images.rb +1 -1
  48. data/modules/mu/cloud/providers.rb +6 -1
  49. data/modules/mu/cloud/resource_base.rb +1 -1
  50. data/modules/mu/cloud/ssh_sessions.rb +4 -0
  51. data/modules/mu/config.rb +28 -12
  52. data/modules/mu/config/database.rb +2 -2
  53. data/modules/mu/config/firewall_rule.rb +1 -1
  54. data/modules/mu/config/ref.rb +2 -2
  55. data/modules/mu/config/schema_helpers.rb +12 -3
  56. data/modules/mu/config/server.rb +10 -4
  57. data/modules/mu/config/server_pool.rb +2 -2
  58. data/modules/mu/config/vpc.rb +10 -10
  59. data/modules/mu/defaults/AWS.yaml +32 -32
  60. data/modules/mu/deploy.rb +23 -10
  61. data/modules/mu/groomers/chef.rb +2 -2
  62. data/modules/mu/master.rb +49 -3
  63. data/modules/mu/mommacat.rb +8 -5
  64. data/modules/mu/mommacat/naming.rb +2 -2
  65. data/modules/mu/mommacat/storage.rb +22 -27
  66. data/modules/mu/providers/aws.rb +142 -48
  67. data/modules/mu/providers/aws/alarm.rb +3 -3
  68. data/modules/mu/providers/aws/bucket.rb +19 -19
  69. data/modules/mu/providers/aws/cache_cluster.rb +22 -22
  70. data/modules/mu/providers/aws/cdn.rb +2 -2
  71. data/modules/mu/providers/aws/collection.rb +14 -14
  72. data/modules/mu/providers/aws/container_cluster.rb +27 -27
  73. data/modules/mu/providers/aws/database.rb +40 -39
  74. data/modules/mu/providers/aws/dnszone.rb +5 -5
  75. data/modules/mu/providers/aws/endpoint.rb +35 -35
  76. data/modules/mu/providers/aws/firewall_rule.rb +26 -23
  77. data/modules/mu/providers/aws/function.rb +28 -28
  78. data/modules/mu/providers/aws/group.rb +7 -7
  79. data/modules/mu/providers/aws/habitat.rb +2 -2
  80. data/modules/mu/providers/aws/job.rb +6 -6
  81. data/modules/mu/providers/aws/loadbalancer.rb +34 -34
  82. data/modules/mu/providers/aws/log.rb +14 -14
  83. data/modules/mu/providers/aws/msg_queue.rb +10 -10
  84. data/modules/mu/providers/aws/nosqldb.rb +8 -8
  85. data/modules/mu/providers/aws/notifier.rb +7 -7
  86. data/modules/mu/providers/aws/role.rb +17 -15
  87. data/modules/mu/providers/aws/search_domain.rb +10 -10
  88. data/modules/mu/providers/aws/server.rb +176 -95
  89. data/modules/mu/providers/aws/server_pool.rb +65 -105
  90. data/modules/mu/providers/aws/storage_pool.rb +17 -9
  91. data/modules/mu/providers/aws/user.rb +1 -1
  92. data/modules/mu/providers/aws/vpc.rb +103 -51
  93. data/modules/mu/providers/aws/vpc_subnet.rb +43 -39
  94. data/modules/mu/providers/azure.rb +78 -12
  95. data/modules/mu/providers/azure/server.rb +18 -3
  96. data/modules/mu/providers/cloudformation/server.rb +1 -1
  97. data/modules/mu/providers/google.rb +19 -4
  98. data/modules/mu/providers/google/folder.rb +6 -2
  99. data/modules/mu/providers/google/function.rb +65 -30
  100. data/modules/mu/providers/google/role.rb +1 -1
  101. data/modules/mu/providers/google/vpc.rb +27 -2
  102. data/modules/tests/aws-servers-with-handrolled-iam.yaml +37 -0
  103. data/modules/tests/k8s.yaml +1 -1
  104. metadata +24 -8
@@ -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
@@ -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,
@@ -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,6 +890,7 @@ 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|
@@ -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
  )
@@ -1356,7 +1374,7 @@ module MU
1356
1374
 
1357
1375
  # See if the peering connection exists before we bother
1358
1376
  # creating it.
1359
- 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(
1360
1378
  filters: [
1361
1379
  {
1362
1380
  name: "requester-vpc-info.vpc-id",
@@ -1372,8 +1390,8 @@ module MU
1372
1390
  peering_id = if !resp or !resp.vpc_peering_connections or
1373
1391
  resp.vpc_peering_connections.empty?
1374
1392
 
1375
- 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
1376
- 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(
1377
1395
  vpc_id: @cloud_id,
1378
1396
  peer_vpc_id: peer_id,
1379
1397
  peer_owner_id: peer['account'],
@@ -1389,13 +1407,13 @@ module MU
1389
1407
  tag_me(peering_id, peering_name)
1390
1408
 
1391
1409
  # Create routes to our new friend.
1392
- 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|
1393
1411
  my_route_config = {
1394
1412
  :route_table_id => rtb_id,
1395
1413
  :destination_cidr_block => peer_obj.cloud_desc.cidr_block,
1396
1414
  :vpc_peering_connection_id => peering_id
1397
1415
  }
1398
- 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(
1399
1417
  route_table_ids: [rtb_id]
1400
1418
  ).route_tables.first
1401
1419
  already_exists = false
@@ -1411,18 +1429,18 @@ module MU
1411
1429
  }
1412
1430
  next if already_exists
1413
1431
 
1414
- MU.log "Creating peering route to #{peer_obj.cloud_desc.cidr_block} in #{peer['vpc']['region']} from VPC #{@config['name']} in #{@config['region']}"
1415
- 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)
1416
1434
  } # MU::Cloud::AWS::VPC.listAllSubnetRouteTables
1417
1435
 
1418
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'])
1419
1437
 
1420
- 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(
1421
1439
  vpc_peering_connection_ids: [peering_id]
1422
1440
  ).vpc_peering_connections.first
1423
1441
 
1424
1442
  loop_if = Proc.new {
1425
- 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(
1426
1444
  vpc_peering_connection_ids: [peering_id]
1427
1445
  ).vpc_peering_connections.first
1428
1446
  ((can_auto_accept and cnxn.status.code == "pending-acceptance") or (cnxn.status.code != "active" and cnxn.status.code != "pending-acceptance"))
@@ -1451,9 +1469,9 @@ module MU
1451
1469
  end
1452
1470
 
1453
1471
  if ["failed", "rejected", "expired", "deleted"].include?(cnxn.status.code)
1454
- 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
1455
1473
  begin
1456
- 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(
1457
1475
  vpc_peering_connection_id: peering_id
1458
1476
  )
1459
1477
  rescue Aws::EC2::Errors::InvalidStateTransition
@@ -1469,8 +1487,8 @@ module MU
1469
1487
  def tag_me(resource_id = @cloud_id, name = @mu_name)
1470
1488
  MU::Cloud::AWS.createStandardTags(
1471
1489
  resource_id,
1472
- region: @config['region'],
1473
- credentials: @config['credentials'],
1490
+ region: @region,
1491
+ credentials: @credentials,
1474
1492
  optional: @config['optional_tags'],
1475
1493
  nametag: name,
1476
1494
  othertags: @config['tags']
@@ -1484,8 +1502,8 @@ module MU
1484
1502
  def createRouteTable(rtb)
1485
1503
  vpc_id = @cloud_id
1486
1504
  vpc_name = @config['name']
1487
- MU.setVar("curRegion", @config['region']) if !@config['region'].nil?
1488
- 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
1489
1507
  route_table_id = rtb['route_table_id'] = resp.route_table_id
1490
1508
  sleep 5
1491
1509
 
@@ -1506,7 +1524,7 @@ module MU
1506
1524
  unless route['gateway'] == '#NAT'
1507
1525
  # Need to change the order of how things are created to create the route here
1508
1526
  MU.log "Creating route for #{route['destination_network']}", details: route_config
1509
- 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)
1510
1528
  end
1511
1529
  end
1512
1530
  }
@@ -1614,6 +1632,40 @@ module MU
1614
1632
  end
1615
1633
  private_class_method :purge_nat_gateways
1616
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
+
1617
1669
  # Remove all VPC endpoints associated with the VPC of the currently loaded deployment.
1618
1670
  # @param noop [Boolean]: If true, will only print what would be done
1619
1671
  # @param vpc_id [String]: The cloud provider's unique VPC identifier
@@ -29,18 +29,21 @@ module MU
29
29
  attr_reader :mu_name
30
30
  attr_reader :name
31
31
  attr_reader :az
32
+ attr_reader :config
32
33
  attr_reader :cloud_desc
33
34
 
34
35
  # @param parent [MU::Cloud::AWS::VPC]: The parent VPC of this subnet.
35
36
  # @param config [Hash<String>]:
36
37
  def initialize(parent, config)
37
- @parent = parent
38
38
  @config = MU::Config.manxify(config)
39
+ MU::Cloud::AWS.resourceInitHook(self, @deploy)
40
+ @parent = parent
39
41
  @cloud_id = config['cloud_id']
42
+ @credentials ||= config['credentials']
40
43
  @mu_name = config['mu_name']
41
44
  @name = config['name']
42
45
  @deploydata = config # This is a dummy for the sake of describe()
43
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [@cloud_id]).subnets.first
46
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_subnets(subnet_ids: [@cloud_id]).subnets.first
44
47
  @az = resp.availability_zone
45
48
  @ip_block = resp.cidr_block
46
49
  @cloud_desc = resp # XXX this really isn't the cloud implementation's business
@@ -50,11 +53,11 @@ module MU
50
53
  # Return the cloud identifier for the default route of this subnet.
51
54
  # @return [String,nil]
52
55
  def defaultRoute
53
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
56
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_route_tables(
54
57
  filters: [{name: "association.subnet-id", values: [@cloud_id]}]
55
58
  )
56
59
  if resp.route_tables.size == 0 # use default route table for the VPC
57
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
60
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_route_tables(
58
61
  filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
59
62
  )
60
63
  end
@@ -75,11 +78,11 @@ module MU
75
78
  # @return [Boolean]
76
79
  def private?
77
80
  return false if @cloud_id.nil?
78
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
81
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_route_tables(
79
82
  filters: [{name: "association.subnet-id", values: [@cloud_id]}]
80
83
  )
81
84
  if resp.route_tables.size == 0 # use default route table for the VPC
82
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
85
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_route_tables(
83
86
  filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
84
87
  )
85
88
  end
@@ -106,14 +109,14 @@ module MU
106
109
 
107
110
  subnetthreads = Array.new
108
111
 
109
- azs = MU::Cloud::AWS.listAZs(region: @config['region'], credentials: @config['credentials'])
112
+ azs = MU::Cloud::AWS.listAZs(region: @region, credentials: @credentials)
110
113
  @config['subnets'].each { |subnet|
111
114
  subnet_name = @config['name']+"-"+subnet['name']
112
115
  az = subnet['availability_zone'] ? subnet['availability_zone'] : azs.op
113
116
  MU.log "Creating Subnet #{subnet_name} (#{subnet['ip_block']}) in #{az}", details: subnet
114
117
 
115
118
  subnetthreads << Thread.new {
116
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_subnet(
119
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_subnet(
117
120
  vpc_id: @cloud_id,
118
121
  cidr_block: subnet['ip_block'],
119
122
  availability_zone: az
@@ -123,7 +126,7 @@ module MU
123
126
  tag_me(subnet_id, @mu_name+"-"+subnet['name'])
124
127
 
125
128
  loop_if = Proc.new {
126
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
129
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_subnets(subnet_ids: [subnet_id]).subnets.first
127
130
  (!resp or resp.state != "available")
128
131
  }
129
132
 
@@ -141,7 +144,7 @@ module MU
141
144
  end
142
145
  MU.log "Associating Route Table '#{subnet['route_table']}' (#{routes[subnet['route_table']]['route_table_id']}) with #{subnet_name}"
143
146
  MU.retrier([Aws::EC2::Errors::InvalidRouteTableIDNotFound], wait: 10, max: 10) {
144
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).associate_route_table(
147
+ MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).associate_route_table(
145
148
  route_table_id: routes[subnet['route_table']]['route_table_id'],
146
149
  subnet_id: subnet_id
147
150
  )
@@ -150,7 +153,7 @@ module MU
150
153
 
151
154
  if subnet.has_key?("map_public_ips")
152
155
  MU.retrier([Aws::EC2::Errors::InvalidSubnetIDNotFound], wait: 10, max: 10) {
153
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_subnet_attribute(
156
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).modify_subnet_attribute(
154
157
  subnet_id: subnet_id,
155
158
  map_public_ip_on_launch: {
156
159
  value: subnet['map_public_ips'],
@@ -167,7 +170,7 @@ module MU
167
170
  loggroup = @deploy.findLitterMate(name: @config['name']+"loggroup", type: "logs")
168
171
  logrole = @deploy.findLitterMate(name: @config['name']+"logrole", type: "roles")
169
172
  MU.log "Enabling traffic logging on Subnet #{subnet_name} in VPC #{@mu_name} to log group #{loggroup.mu_name}"
170
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_flow_logs(
173
+ MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_flow_logs(
171
174
  resource_ids: [subnet_id],
172
175
  resource_type: "Subnet",
173
176
  traffic_type: subnet["traffic_type_to_log"],
@@ -188,30 +191,31 @@ module MU
188
191
  def allocate_eip_for_nat
189
192
  MU::MommaCat.lock("nat-gateway-eipalloc")
190
193
 
191
- eips = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_addresses(
192
- filters: [
193
- {
194
- name: "domain",
195
- values: ["vpc"]
196
- }
197
- ]
198
- ).addresses
199
-
200
- allocation_id = nil
201
- eips.each { |eip|
202
- next if !eip.association_id.nil? and !eip.association_id.empty?
203
- if (eip.private_ip_address.nil? || eip.private_ip_address.empty?) and MU::MommaCat.lock(eip.allocation_id, true, true)
204
- if !@eip_allocation_ids.include?(eip.allocation_id)
205
- allocation_id = eip.allocation_id
206
- break
207
- end
208
- end
209
- }
210
-
211
- if allocation_id.nil?
212
- allocation_id = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).allocate_address(domain: "vpc").allocation_id
213
- MU::MommaCat.lock(allocation_id, false, true)
214
- end
194
+ # eips = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_addresses(
195
+ # filters: [
196
+ # {
197
+ # name: "domain",
198
+ # values: ["vpc"]
199
+ # }
200
+ # ]
201
+ # ).addresses
202
+
203
+ # allocation_id = nil
204
+ # eips.each { |eip|
205
+ # next if !eip.association_id.nil? and !eip.association_id.empty?
206
+ # if (eip.private_ip_address.nil? || eip.private_ip_address.empty?) and MU::MommaCat.lock(eip.allocation_id, true, true)
207
+ # if !@eip_allocation_ids.include?(eip.allocation_id)
208
+ # allocation_id = eip.allocation_id
209
+ # break
210
+ # end
211
+ # end
212
+ # }
213
+
214
+ # if allocation_id.nil?
215
+ allocation_id = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).allocate_address(domain: "vpc").allocation_id
216
+ tag_me(allocation_id)
217
+ # MU::MommaCat.lock(allocation_id, false, true)
218
+ # end
215
219
 
216
220
  @eip_allocation_ids << allocation_id
217
221
 
@@ -223,15 +227,15 @@ module MU
223
227
  def create_nat_gateway(subnet)
224
228
  allocation_id = allocate_eip_for_nat
225
229
 
226
- nat_gateway_id = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_nat_gateway(
230
+ nat_gateway_id = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_nat_gateway(
227
231
  subnet_id: subnet['subnet_id'],
228
232
  allocation_id: allocation_id,
229
233
  ).nat_gateway.nat_gateway_id
230
234
 
231
235
  ensure_unlock = Proc.new { MU::MommaCat.unlock(allocation_id, true) }
232
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_nat_gateways(nat_gateway_ids: [nat_gateway_id]).nat_gateways.first
236
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_nat_gateways(nat_gateway_ids: [nat_gateway_id]).nat_gateways.first
233
237
  loop_if = Proc.new {
234
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_nat_gateways(nat_gateway_ids: [nat_gateway_id]).nat_gateways.first
238
+ resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_nat_gateways(nat_gateway_ids: [nat_gateway_id]).nat_gateways.first
235
239
  resp.class != Aws::EC2::Types::NatGateway or resp.state == "pending"
236
240
  }
237
241