cloud-mu 3.1.4 → 3.3.1

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 (203) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +5 -1
  3. data/ansible/roles/mu-windows/README.md +33 -0
  4. data/ansible/roles/mu-windows/defaults/main.yml +2 -0
  5. data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
  6. data/ansible/roles/mu-windows/files/config.xml +76 -0
  7. data/ansible/roles/mu-windows/handlers/main.yml +2 -0
  8. data/ansible/roles/mu-windows/meta/main.yml +53 -0
  9. data/ansible/roles/mu-windows/tasks/main.yml +36 -0
  10. data/ansible/roles/mu-windows/tests/inventory +2 -0
  11. data/ansible/roles/mu-windows/tests/test.yml +5 -0
  12. data/ansible/roles/mu-windows/vars/main.yml +2 -0
  13. data/bin/mu-adopt +16 -12
  14. data/bin/mu-azure-tests +57 -0
  15. data/bin/mu-cleanup +2 -4
  16. data/bin/mu-configure +52 -0
  17. data/bin/mu-deploy +3 -3
  18. data/bin/mu-findstray-tests +25 -0
  19. data/bin/mu-gen-docs +2 -4
  20. data/bin/mu-load-config.rb +2 -1
  21. data/bin/mu-node-manage +15 -16
  22. data/bin/mu-run-tests +37 -12
  23. data/cloud-mu.gemspec +5 -3
  24. data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
  25. data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
  26. data/cookbooks/mu-tools/libraries/helper.rb +1 -1
  27. data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
  28. data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
  29. data/cookbooks/mu-tools/recipes/eks.rb +2 -2
  30. data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
  31. data/cookbooks/mu-tools/recipes/windows-client.rb +163 -164
  32. data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
  33. data/extras/clean-stock-amis +25 -19
  34. data/extras/generate-stock-images +1 -0
  35. data/extras/image-generators/AWS/win2k12.yaml +18 -13
  36. data/extras/image-generators/AWS/win2k16.yaml +18 -13
  37. data/extras/image-generators/AWS/win2k19.yaml +21 -0
  38. data/modules/mommacat.ru +1 -1
  39. data/modules/mu.rb +158 -107
  40. data/modules/mu/adoption.rb +386 -59
  41. data/modules/mu/cleanup.rb +214 -303
  42. data/modules/mu/cloud.rb +128 -1632
  43. data/modules/mu/cloud/database.rb +49 -0
  44. data/modules/mu/cloud/dnszone.rb +44 -0
  45. data/modules/mu/cloud/machine_images.rb +212 -0
  46. data/modules/mu/cloud/providers.rb +81 -0
  47. data/modules/mu/cloud/resource_base.rb +926 -0
  48. data/modules/mu/cloud/server.rb +40 -0
  49. data/modules/mu/cloud/server_pool.rb +1 -0
  50. data/modules/mu/cloud/ssh_sessions.rb +228 -0
  51. data/modules/mu/cloud/winrm_sessions.rb +237 -0
  52. data/modules/mu/cloud/wrappers.rb +169 -0
  53. data/modules/mu/config.rb +135 -82
  54. data/modules/mu/config/alarm.rb +2 -6
  55. data/modules/mu/config/bucket.rb +32 -3
  56. data/modules/mu/config/cache_cluster.rb +2 -2
  57. data/modules/mu/config/cdn.rb +100 -0
  58. data/modules/mu/config/collection.rb +1 -1
  59. data/modules/mu/config/container_cluster.rb +7 -2
  60. data/modules/mu/config/database.rb +84 -105
  61. data/modules/mu/config/database.yml +1 -2
  62. data/modules/mu/config/dnszone.rb +5 -4
  63. data/modules/mu/config/doc_helpers.rb +5 -6
  64. data/modules/mu/config/endpoint.rb +2 -1
  65. data/modules/mu/config/firewall_rule.rb +3 -19
  66. data/modules/mu/config/folder.rb +1 -1
  67. data/modules/mu/config/function.rb +17 -8
  68. data/modules/mu/config/group.rb +1 -1
  69. data/modules/mu/config/habitat.rb +1 -1
  70. data/modules/mu/config/job.rb +89 -0
  71. data/modules/mu/config/loadbalancer.rb +57 -11
  72. data/modules/mu/config/log.rb +1 -1
  73. data/modules/mu/config/msg_queue.rb +1 -1
  74. data/modules/mu/config/nosqldb.rb +1 -1
  75. data/modules/mu/config/notifier.rb +8 -19
  76. data/modules/mu/config/ref.rb +92 -14
  77. data/modules/mu/config/role.rb +1 -1
  78. data/modules/mu/config/schema_helpers.rb +38 -37
  79. data/modules/mu/config/search_domain.rb +1 -1
  80. data/modules/mu/config/server.rb +12 -13
  81. data/modules/mu/config/server.yml +1 -0
  82. data/modules/mu/config/server_pool.rb +3 -7
  83. data/modules/mu/config/storage_pool.rb +1 -1
  84. data/modules/mu/config/tail.rb +11 -0
  85. data/modules/mu/config/user.rb +1 -1
  86. data/modules/mu/config/vpc.rb +27 -23
  87. data/modules/mu/config/vpc.yml +0 -1
  88. data/modules/mu/defaults/AWS.yaml +91 -68
  89. data/modules/mu/defaults/Azure.yaml +1 -0
  90. data/modules/mu/defaults/Google.yaml +1 -0
  91. data/modules/mu/deploy.rb +33 -19
  92. data/modules/mu/groomer.rb +16 -1
  93. data/modules/mu/groomers/ansible.rb +123 -21
  94. data/modules/mu/groomers/chef.rb +64 -11
  95. data/modules/mu/logger.rb +120 -144
  96. data/modules/mu/master.rb +97 -4
  97. data/modules/mu/master/ssl.rb +0 -1
  98. data/modules/mu/mommacat.rb +154 -867
  99. data/modules/mu/mommacat/daemon.rb +23 -14
  100. data/modules/mu/mommacat/naming.rb +110 -3
  101. data/modules/mu/mommacat/search.rb +495 -0
  102. data/modules/mu/mommacat/storage.rb +225 -192
  103. data/modules/mu/{clouds → providers}/README.md +1 -1
  104. data/modules/mu/{clouds → providers}/aws.rb +281 -64
  105. data/modules/mu/{clouds → providers}/aws/alarm.rb +3 -3
  106. data/modules/mu/{clouds → providers}/aws/bucket.rb +275 -41
  107. data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +14 -50
  108. data/modules/mu/providers/aws/cdn.rb +782 -0
  109. data/modules/mu/{clouds → providers}/aws/collection.rb +5 -5
  110. data/modules/mu/{clouds → providers}/aws/container_cluster.rb +708 -749
  111. data/modules/mu/providers/aws/database.rb +1744 -0
  112. data/modules/mu/{clouds → providers}/aws/dnszone.rb +75 -57
  113. data/modules/mu/providers/aws/endpoint.rb +1072 -0
  114. data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +212 -242
  115. data/modules/mu/{clouds → providers}/aws/folder.rb +1 -1
  116. data/modules/mu/{clouds → providers}/aws/function.rb +289 -134
  117. data/modules/mu/{clouds → providers}/aws/group.rb +18 -20
  118. data/modules/mu/{clouds → providers}/aws/habitat.rb +3 -3
  119. data/modules/mu/providers/aws/job.rb +466 -0
  120. data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +50 -41
  121. data/modules/mu/{clouds → providers}/aws/log.rb +5 -5
  122. data/modules/mu/{clouds → providers}/aws/msg_queue.rb +14 -11
  123. data/modules/mu/{clouds → providers}/aws/nosqldb.rb +96 -5
  124. data/modules/mu/{clouds → providers}/aws/notifier.rb +135 -63
  125. data/modules/mu/{clouds → providers}/aws/role.rb +94 -57
  126. data/modules/mu/{clouds → providers}/aws/search_domain.rb +173 -42
  127. data/modules/mu/{clouds → providers}/aws/server.rb +782 -1107
  128. data/modules/mu/{clouds → providers}/aws/server_pool.rb +36 -46
  129. data/modules/mu/{clouds → providers}/aws/storage_pool.rb +21 -38
  130. data/modules/mu/{clouds → providers}/aws/user.rb +12 -16
  131. data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
  132. data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +5 -4
  133. data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +2 -1
  134. data/modules/mu/{clouds → providers}/aws/vpc.rb +429 -849
  135. data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
  136. data/modules/mu/{clouds → providers}/azure.rb +13 -0
  137. data/modules/mu/{clouds → providers}/azure/container_cluster.rb +1 -5
  138. data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +8 -1
  139. data/modules/mu/{clouds → providers}/azure/habitat.rb +0 -0
  140. data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +0 -0
  141. data/modules/mu/{clouds → providers}/azure/role.rb +0 -0
  142. data/modules/mu/{clouds → providers}/azure/server.rb +32 -24
  143. data/modules/mu/{clouds → providers}/azure/user.rb +1 -1
  144. data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
  145. data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
  146. data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
  147. data/modules/mu/{clouds → providers}/azure/vpc.rb +4 -6
  148. data/modules/mu/{clouds → providers}/cloudformation.rb +10 -0
  149. data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
  150. data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
  151. data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
  152. data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
  153. data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
  154. data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
  155. data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
  156. data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
  157. data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
  158. data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
  159. data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +3 -3
  160. data/modules/mu/{clouds → providers}/docker.rb +0 -0
  161. data/modules/mu/{clouds → providers}/google.rb +29 -6
  162. data/modules/mu/{clouds → providers}/google/bucket.rb +5 -5
  163. data/modules/mu/{clouds → providers}/google/container_cluster.rb +59 -37
  164. data/modules/mu/{clouds → providers}/google/database.rb +5 -12
  165. data/modules/mu/{clouds → providers}/google/firewall_rule.rb +5 -5
  166. data/modules/mu/{clouds → providers}/google/folder.rb +5 -9
  167. data/modules/mu/{clouds → providers}/google/function.rb +14 -8
  168. data/modules/mu/{clouds → providers}/google/group.rb +9 -17
  169. data/modules/mu/{clouds → providers}/google/habitat.rb +4 -8
  170. data/modules/mu/{clouds → providers}/google/loadbalancer.rb +5 -5
  171. data/modules/mu/{clouds → providers}/google/role.rb +50 -31
  172. data/modules/mu/{clouds → providers}/google/server.rb +142 -55
  173. data/modules/mu/{clouds → providers}/google/server_pool.rb +14 -14
  174. data/modules/mu/{clouds → providers}/google/user.rb +34 -24
  175. data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
  176. data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
  177. data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
  178. data/modules/mu/{clouds → providers}/google/vpc.rb +46 -15
  179. data/modules/tests/aws-jobs-functions.yaml +46 -0
  180. data/modules/tests/centos6.yaml +15 -0
  181. data/modules/tests/centos7.yaml +15 -0
  182. data/modules/tests/centos8.yaml +12 -0
  183. data/modules/tests/ecs.yaml +23 -0
  184. data/modules/tests/eks.yaml +1 -1
  185. data/modules/tests/functions/node-function/lambda_function.js +10 -0
  186. data/modules/tests/functions/python-function/lambda_function.py +12 -0
  187. data/modules/tests/includes-and-params.yaml +2 -1
  188. data/modules/tests/microservice_app.yaml +288 -0
  189. data/modules/tests/rds.yaml +108 -0
  190. data/modules/tests/regrooms/rds.yaml +123 -0
  191. data/modules/tests/server-with-scrub-muisms.yaml +2 -1
  192. data/modules/tests/super_complex_bok.yml +2 -2
  193. data/modules/tests/super_simple_bok.yml +3 -5
  194. data/modules/tests/win2k12.yaml +25 -0
  195. data/modules/tests/win2k16.yaml +25 -0
  196. data/modules/tests/win2k19.yaml +25 -0
  197. data/requirements.txt +1 -0
  198. data/spec/mu/clouds/azure_spec.rb +2 -2
  199. metadata +169 -93
  200. data/extras/image-generators/AWS/windows.yaml +0 -18
  201. data/modules/mu/clouds/aws/database.rb +0 -1974
  202. data/modules/mu/clouds/aws/endpoint.rb +0 -596
  203. data/modules/tests/needwork/win2k12.yaml +0 -13
@@ -120,7 +120,7 @@ module MU
120
120
  if !@deploy.nocleanup
121
121
  Thread.new {
122
122
  MU.dupGlobals(parent_thread_id)
123
- MU::Cloud::AWS::Server.terminateInstance(id: member.instance_id)
123
+ MU::Cloud.resourceClass("AWS", "Server").terminateInstance(id: member.instance_id)
124
124
  }
125
125
  end
126
126
  end
@@ -193,9 +193,10 @@ module MU
193
193
  # @return [Array<MU::Cloud::Server>]
194
194
  def listNodes
195
195
  nodes = []
196
- me = MU::Cloud::AWS::ServerPool.find(cloud_id: cloud_id)
197
- if me and me.first and me.first.instances
198
- me.first.instances.each { |instance|
196
+ me = MU::Cloud::AWS::ServerPool.find(cloud_id: cloud_id).values.first
197
+ pp me
198
+ if me and me.instances
199
+ me.instances.each { |instance|
199
200
  found = MU::MommaCat.findStray("AWS", "server", cloud_id: instance.instance_id, region: @config["region"], dummy_ok: true)
200
201
  nodes.concat(found)
201
202
  }
@@ -425,6 +426,7 @@ module MU
425
426
  # @return [OpenStruct]
426
427
  def cloud_desc(use_cache: true)
427
428
  return @cloud_desc_cache if @cloud_desc_cache and use_cache
429
+ return nil if !@cloud_id
428
430
  @cloud_desc_cache = MU::Cloud::AWS.autoscale(region: @config['region'], credentials: @config['credentials']).describe_auto_scaling_groups(
429
431
  auto_scaling_group_names: [@mu_name]
430
432
  ).auto_scaling_groups.first
@@ -531,14 +533,25 @@ module MU
531
533
  if cloud_desc.vpc_zone_identifier and
532
534
  !cloud_desc.vpc_zone_identifier.empty?
533
535
  nets = cloud_desc.vpc_zone_identifier.split(/,/)
534
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @credentials).describe_subnets(subnet_ids: nets).subnets.first
535
- bok['vpc'] = MU::Config::Ref.get(
536
- id: resp.vpc_id,
537
- cloud: "AWS",
538
- credentials: @credentials,
539
- type: "vpcs",
540
- subnets: nets.map { |s| { "subnet_id" => s } }
541
- )
536
+ begin
537
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @credentials).describe_subnets(subnet_ids: nets).subnets.first
538
+ bok['vpc'] = MU::Config::Ref.get(
539
+ id: resp.vpc_id,
540
+ cloud: "AWS",
541
+ credentials: @credentials,
542
+ type: "vpcs",
543
+ subnets: nets.map { |s| { "subnet_id" => s } }
544
+ )
545
+ rescue Aws::EC2::Errors::InvalidSubnetIDNotFound => e
546
+ if e.message.match(/The subnet ID '(subnet-[a-f0-9]+)' does not exist/)
547
+ nets.delete(Regexp.last_match[1])
548
+ if nets.empty?
549
+ MU.log "Autoscale Group #{@cloud_id} was configured for a VPC, but the configuration held no valid subnets", MU::WARN, details: cloud_desc.vpc_zone_identifier.split(/,/)
550
+ end
551
+ else
552
+ raise e
553
+ end
554
+ end
542
555
  end
543
556
 
544
557
  # MU.log @cloud_id, MU::NOTICE, details: cloud_desc
@@ -813,26 +826,7 @@ module MU
813
826
  }
814
827
  }
815
828
  },
816
- "ingress_rules" => {
817
- "items" => {
818
- "properties" => {
819
- "sgs" => {
820
- "type" => "array",
821
- "items" => {
822
- "description" => "Other AWS Security Groups; resources that are associated with this group will have this rule applied to their traffic",
823
- "type" => "string"
824
- }
825
- },
826
- "lbs" => {
827
- "type" => "array",
828
- "items" => {
829
- "description" => "AWS Load Balancers which will have this rule applied to their traffic",
830
- "type" => "string"
831
- }
832
- }
833
- }
834
- }
835
- }
829
+ "ingress_rules" => MU::Cloud.resourceClass("AWS", "FirewallRule").ingressRuleAddtlSchema
836
830
  }
837
831
  [toplevel_required, schema]
838
832
  end
@@ -905,7 +899,7 @@ module MU
905
899
  launch = pool["basis"]["launch_config"]
906
900
  launch['iam_policies'] ||= pool['iam_policies']
907
901
 
908
- launch['size'] = MU::Cloud::AWS::Server.validateInstanceType(launch["size"], pool["region"])
902
+ launch['size'] = MU::Cloud.resourceClass("AWS", "Server").validateInstanceType(launch["size"], pool["region"])
909
903
  ok = false if launch['size'].nil?
910
904
  if !launch['generate_iam_role']
911
905
  if !launch['iam_role'] and pool['cloud'] != "CloudFormation"
@@ -949,11 +943,7 @@ module MU
949
943
 
950
944
  role['credentials'] = pool['credentials'] if pool['credentials']
951
945
  configurator.insertKitten(role, "roles")
952
- pool["dependencies"] ||= []
953
- pool["dependencies"] << {
954
- "type" => "role",
955
- "name" => pool["name"]
956
- }
946
+ MU::Config.addDependency(pool, pool['name'], "role")
957
947
  end
958
948
  launch["ami_id"] ||= launch["image_id"]
959
949
  if launch["server"].nil? and launch["instance_id"].nil? and launch["ami_id"].nil?
@@ -967,7 +957,7 @@ module MU
967
957
  end
968
958
  end
969
959
  if launch["server"] != nil
970
- pool["dependencies"] << {"type" => "server", "name" => launch["server"]}
960
+ MU::Config.addDependency(pool, launch["server"], "server", phase: "groom")
971
961
  # XXX I dunno, maybe toss an error if this isn't done already
972
962
  # servers.each { |server|
973
963
  # if server["name"] == launch["server"]
@@ -1073,7 +1063,7 @@ module MU
1073
1063
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
1074
1064
  # @param region [String]: The cloud provider region
1075
1065
  # @return [void]
1076
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
1066
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
1077
1067
  MU.log "AWS::ServerPool.cleanup: need to support flags['known']", MU::DEBUG, details: flags
1078
1068
 
1079
1069
  filters = [{name: "key", values: ["MU-ID"]}]
@@ -1096,7 +1086,7 @@ module MU
1096
1086
  if asg.key == "MU-MASTER-IP" and asg.value != MU.mu_public_ip and !ignoremaster
1097
1087
  no_purge << asg.resource_id
1098
1088
  end
1099
- if asg.key == "MU-ID" and asg.value == MU.deploy_id
1089
+ if asg.key == "MU-ID" and asg.value == deploy_id
1100
1090
  maybe_purge << asg.resource_id
1101
1091
  end
1102
1092
  }
@@ -1123,7 +1113,7 @@ module MU
1123
1113
  end
1124
1114
  end
1125
1115
 
1126
- # MU::Cloud::AWS::Server.removeIAMProfile(resource_id)
1116
+ # MU::Cloud.resourceClass("AWS", "Server").removeIAMProfile(resource_id)
1127
1117
 
1128
1118
  # Generally there should be a launch_configuration of the same name
1129
1119
  # XXX search for these independently, too?
@@ -1164,14 +1154,14 @@ module MU
1164
1154
  @config['basis']['launch_config']["ami_id"] = @deploy.deployment["images"][@config['basis']['launch_config']["server"]]["image_id"]
1165
1155
  MU.log "Using AMI '#{@config['basis']['launch_config']["ami_id"]}' from sibling server #{@config['basis']['launch_config']["server"]} in ServerPool #{@mu_name}"
1166
1156
  elsif !@config['basis']['launch_config']["instance_id"].nil?
1167
- @config['basis']['launch_config']["ami_id"] = MU::Cloud::AWS::Server.createImage(
1157
+ @config['basis']['launch_config']["ami_id"] = MU::Cloud.resourceClass("AWS", "Server").createImage(
1168
1158
  name: @mu_name,
1169
1159
  instance_id: @config['basis']['launch_config']["instance_id"],
1170
1160
  credentials: @config['credentials'],
1171
1161
  region: @config['region']
1172
1162
  )[@config['region']]
1173
1163
  end
1174
- MU::Cloud::AWS::Server.waitForAMI(@config['basis']['launch_config']["ami_id"], credentials: @config['credentials'])
1164
+ MU::Cloud.resourceClass("AWS", "Server").waitForAMI(@config['basis']['launch_config']["ami_id"], credentials: @config['credentials'])
1175
1165
 
1176
1166
  oldlaunch = MU::Cloud::AWS.autoscale(region: @config['region'], credentials: @config['credentials']).describe_launch_configurations(
1177
1167
  launch_configuration_names: [@mu_name]
@@ -1226,12 +1216,12 @@ module MU
1226
1216
  vol.delete("encrypted")
1227
1217
  end
1228
1218
  end
1229
- mapping, _cfm_mapping = MU::Cloud::AWS::Server.convertBlockDeviceMapping(vol)
1219
+ mapping, _cfm_mapping = MU::Cloud.resourceClass("AWS", "Server").convertBlockDeviceMapping(vol)
1230
1220
  storage << mapping
1231
1221
  }
1232
1222
  end
1233
1223
 
1234
- storage.concat(MU::Cloud::AWS::Server.ephemeral_mappings)
1224
+ storage.concat(MU::Cloud.resourceClass("AWS", "Server").ephemeral_mappings)
1235
1225
 
1236
1226
  if @config['basis']['launch_config']['generate_iam_role']
1237
1227
  role = @deploy.findLitterMate(name: @config['name'], type: "roles")
@@ -67,7 +67,7 @@ module MU
67
67
  if target['vpc']["subnet_name"]
68
68
  subnet_obj = vpc.getSubnet(name: target['vpc']["subnet_name"])
69
69
  if subnet_obj.nil?
70
- raise MuError, "Failed to locate subnet from #{subnet} in StoragePool #{@config['name']}:#{target['name']}"
70
+ raise MuError, "Failed to locate subnet from #{target['vpc']["subnet_name"]} in StoragePool #{@config['name']}:#{target['name']}"
71
71
  end
72
72
  target['vpc']['subnet_id'] = subnet_obj.cloud_id
73
73
  end
@@ -261,49 +261,29 @@ module MU
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(
265
+ file_system_id: storage_pool.file_system_id
266
+ ).mount_targets
267
+
264
268
  @config['mount_points'].each { |mp|
265
269
  subnet = nil
266
270
  dependencies
267
- mp_vpc = if mp['vpc'] and mp['vpc']['vpc_name']
268
- @deploy.findLitterMate(type: "vpc", name: mp['vpc']['vpc_name'], credentials: @config['credentials'])
269
- elsif mp['vpc']
270
- MU::MommaCat.findStray(
271
- @config['cloud'],
272
- "vpcs",
273
- deploy_id: mp['vpc']["deploy_id"],
274
- credentials: @config['credentials'],
275
- mu_name: mp['vpc']["mu_name"],
276
- cloud_id: mp['vpc']['vpc_id'],
277
- region: @config['region'],
278
- dummy_ok: false
279
- ).first
280
- # XXX non-sibling, findStray version
281
- end
271
+ mp_vpc = MU::Config::Ref.get(mp['vpc']).kitten
282
272
 
283
- mount_targets = MU::Cloud::AWS.efs(region: @config['region'], credentials: @config['credentials']).describe_mount_targets(
284
- file_system_id: storage_pool.file_system_id
285
- ).mount_targets
286
273
 
287
- # subnet_obj = mp_vpc.subnets.select { |s|
288
- # s.name == mp["vpc"]["subnet_name"] or s.cloud_id == mp["vpc"]["subnet_id"]
289
- # }.first
274
+ subnet_obj = mp_vpc.subnets.select { |s|
275
+ s.name == mp["vpc"]["subnet_name"] or s.cloud_id == mp["vpc"]["subnet_id"]
276
+ }.first
290
277
  mount_target = nil
291
- mp_vpc.subnets.each { |subnet_obj|
292
- mount_targets.map { |t|
293
- subnet_cidr_obj = NetAddr::IPv4Net.parse(subnet_obj.ip_block)
294
- if subnet_cidr_obj.contains(NetAddr::IPv4.parse(t.ip_address))
295
- mount_target = t
296
- subnet = subnet_obj.cloud_desc
297
- end
298
- }
299
- break if mount_target
278
+ mount_targets.each { |t|
279
+ subnet_cidr_obj = NetAddr::IPv4Net.parse(subnet_obj.ip_block)
280
+ if subnet_cidr_obj.contains(NetAddr::IPv4.parse(t.ip_address))
281
+ mount_target = t
282
+ subnet = subnet_obj.cloud_desc
283
+ break
284
+ end
300
285
  }
301
286
 
302
- # mount_target = MU::Cloud::AWS.efs(region: @config['region'], credentials: @config['credentials']).describe_mount_targets(
303
- # mount_target_id: mp["cloud_id"]
304
- # ).mount_targets.first
305
-
306
-
307
287
  targets[mp["name"]] = {
308
288
  "owner_id" => mount_target.owner_id,
309
289
  "cloud_id" => mount_target.mount_target_id,
@@ -353,7 +333,7 @@ module MU
353
333
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
354
334
  # @param region [String]: The cloud provider region in which to operate
355
335
  # @return [void]
356
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
336
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
357
337
  MU.log "AWS::StoragePool.cleanup: need to support flags['known']", MU::DEBUG, details: flags
358
338
 
359
339
  supported_regions = %w{us-west-2 us-east-1 eu-west-1}
@@ -378,7 +358,7 @@ module MU
378
358
  found_muid = false
379
359
  found_master = false
380
360
  tags.each { |tag|
381
- found_muid = true if tag.key == "MU-ID" && tag.value == MU.deploy_id
361
+ found_muid = true if tag.key == "MU-ID" && tag.value == deploy_id
382
362
  found_master = true if tag.key == "MU-MASTER-IP" && tag.value == MU.mu_public_ip
383
363
  }
384
364
  next if !found_muid
@@ -493,6 +473,9 @@ module MU
493
473
 
494
474
  if pool['mount_points'] && !pool['mount_points'].empty?
495
475
  pool['mount_points'].each{ |mp|
476
+ if mp['vpc'] and mp['vpc']['name']
477
+ MU::Config.addDependency(pool, mp['vpc']['name'], "vpc")
478
+ end
496
479
  if mp['ingress_rules']
497
480
  fwname = "storage-#{mp['name']}"
498
481
  acl = {
@@ -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::AWS::Role.manageRawPolicies(
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
@@ -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::AWS::Role.purgePolicy(a.policy_arn, @credentials)
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::AWS::Role.genPolicyDocument(@config['inline_policies'], deploy_obj: @deploy)
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(
@@ -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
@@ -431,7 +431,7 @@ MU.log e.inspect, MU::ERR, details: policy
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
433
  doc = JSON.parse(URI.decode(pol.policy_document))
434
- bok["inline_policies"] = MU::Cloud::AWS::Role.doc2MuPolicies(pol.policy_name, doc, bok["inline_policies"])
434
+ bok["inline_policies"] = MU::Cloud.resourceClass("AWS", "Role").doc2MuPolicies(pol.policy_name, doc, bok["inline_policies"])
435
435
  }
436
436
  end
437
437
 
@@ -465,7 +465,7 @@ MU.log e.inspect, MU::ERR, details: policy
465
465
  def self.schema(_config)
466
466
  toplevel_required = []
467
467
  polschema = MU::Config::Role.schema["properties"]["policies"]
468
- polschema.deep_merge!(MU::Cloud::AWS::Role.condition_schema)
468
+ polschema.deep_merge!(MU::Cloud.resourceClass("AWS", "Role").condition_schema)
469
469
 
470
470
  schema = {
471
471
  "inline_policies" => polschema,
@@ -517,7 +517,7 @@ style long name, like +IAMTESTS-DEV-2018112815-IS-USER-FOO+"
517
517
  # If we're attaching some managed policies, make sure all of the ones
518
518
  # that should already exist do indeed exist
519
519
  if user['attachable_policies']
520
- ok = false if !MU::Cloud::AWS::Role.validateAttachablePolicies(
520
+ ok = false if !MU::Cloud.resourceClass("AWS", "Role").validateAttachablePolicies(
521
521
  user['attachable_policies'],
522
522
  credentials: user['credentials'],
523
523
  region: user['region']
@@ -530,7 +530,7 @@ style long name, like +IAMTESTS-DEV-2018112815-IS-USER-FOO+"
530
530
  if configurator.haveLitterMate?(group, "groups")
531
531
  need_dependency = true
532
532
  else
533
- found = MU::Cloud::AWS::Group.find(cloud_id: group)
533
+ found = MU::Cloud.resourceClass("AWS", "Group").find(cloud_id: group)
534
534
  if found.nil? or found.empty? or (configurator.updating and
535
535
  found.values.first.group.path == "/"+configurator.updating+"/")
536
536
  groupdesc = {
@@ -542,11 +542,7 @@ style long name, like +IAMTESTS-DEV-2018112815-IS-USER-FOO+"
542
542
  end
543
543
 
544
544
  if need_dependency
545
- user["dependencies"] ||= []
546
- user["dependencies"] << {
547
- "type" => "group",
548
- "name" => group
549
- }
545
+ MU::Config.addDependency(user, group, "group")
550
546
  end
551
547
  }
552
548
  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'
@@ -23,7 +23,7 @@ function log
23
23
  }
24
24
 
25
25
  function fetchSecret([string]$file){
26
- log "Fetching s3://<%= $mu.adminBucketName %>/$file to $tmp/$file"
26
+ log "aws.cmd --region $region s3 cp s3://<%= $mu.adminBucketName %>/$file $tmp/$file"
27
27
  aws.cmd --region $region s3 cp s3://<%= $mu.adminBucketName %>/$file $tmp/$file
28
28
  }
29
29
 
@@ -245,6 +245,7 @@ if($ingroup -ne $admin_username){
245
245
  net localgroup WinRMRemoteWMIUsers__ /add $admin_username
246
246
  }
247
247
 
248
+ importCert "$myname-winrm.crt" "root"
248
249
  $winrmcert = importCert "$myname-winrm.crt" "TrustedPeople"
249
250
  Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true
250
251
  Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name LocalAccountTokenFilterPolicy -Value 1
@@ -18,6 +18,7 @@ module MU
18
18
 
19
19
  # Creation of Virtual Private Clouds and associated artifacts (routes, subnets, etc).
20
20
  class VPC < MU::Cloud::VPC
21
+ require 'mu/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
- vpc_id = @config['vpc_id'] = resp.vpc_id
39
+ @cloud_id = resp.vpc_id
40
+ @config['vpc_id'] = @cloud_id
39
41
 
40
- MU::Cloud::AWS.createStandardTags(vpc_id, region: @config['region'], credentials: @config['credentials'])
41
- MU::Cloud::AWS.createTag(vpc_id, "Name", @mu_name, region: @config['region'], credentials: @config['credentials'])
42
-
43
- if @config['tags']
44
- @config['tags'].each { |tag|
45
- MU::Cloud::AWS.createTag(vpc_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
46
- }
47
- end
48
-
49
- if @config['optional_tags']
50
- MU::MommaCat.listOptionalTags.each { |key, value|
51
- MU::Cloud::AWS.createTag(vpc_id, key, value, region: @config['region'], credentials: @config['credentials'])
52
- }
53
- end
42
+ tag_me
54
43
 
55
44
  if resp.state != "available"
56
45
  begin
57
- MU.log "Waiting for VPC #{@mu_name} (#{vpc_id}) to be available", MU::NOTICE
46
+ MU.log "Waiting for VPC #{@mu_name} (#{@cloud_id}) to be available", MU::NOTICE
58
47
  sleep 5
59
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpcs(vpc_ids: [vpc_id]).vpcs.first
48
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpcs(vpc_ids: [@cloud_id]).vpcs.first
60
49
  end while resp.state != "available"
61
50
  # There's a default route table that comes with. Let's tag it.
62
51
  resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
63
52
  filters: [
64
53
  {
65
54
  name: "vpc-id",
66
- values: [vpc_id]
55
+ values: [@cloud_id]
67
56
  }
68
57
  ]
69
58
  )
70
59
  resp.route_tables.each { |rtb|
71
- MU::Cloud::AWS.createTag(rtb.route_table_id, "Name", @mu_name+"-#DEFAULTPRIV", region: @config['region'], credentials: @config['credentials'])
72
- if @config['tags']
73
- @config['tags'].each { |tag|
74
- MU::Cloud::AWS.createTag(rtb.route_table_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
75
- }
76
- end
77
-
78
- MU::Cloud::AWS.createStandardTags(rtb.route_table_id, region: @config['region'], credentials: @config['credentials'])
79
-
80
- if @config['optional_tags']
81
- MU::MommaCat.listOptionalTags.each { |key, value|
82
- MU::Cloud::AWS.createTag(rtb.route_table_id, key, value, region: @config['region'], credentials: @config['credentials'])
83
- }
84
- end
60
+ tag_me(rtb.route_table_id, @mu_name+"-#DEFAULTPRIV")
85
61
  }
86
62
  end
87
- @config['vpc_id'] = vpc_id
88
- @cloud_id = vpc_id
89
63
 
90
64
  if @config['create_internet_gateway']
91
65
  MU.log "Creating Internet Gateway #{@mu_name}"
92
66
  resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_internet_gateway
93
67
  internet_gateway_id = resp.internet_gateway.internet_gateway_id
94
68
  sleep 5
95
- MU::Cloud::AWS.createStandardTags(internet_gateway_id, region: @config['region'], credentials: @config['credentials'])
96
- MU::Cloud::AWS.createTag(internet_gateway_id, "Name", @mu_name, region: @config['region'], credentials: @config['credentials'])
97
- if @config['tags']
98
- @config['tags'].each { |tag|
99
- MU::Cloud::AWS.createTag(internet_gateway_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
100
- }
101
- end
102
69
 
103
- if @config['optional_tags']
104
- MU::MommaCat.listOptionalTags.each { |key, value|
105
- MU::Cloud::AWS.createTag(internet_gateway_id, key, value, region: @config['region'], credentials: @config['credentials'])
106
- }
107
- end
70
+ tag_me(internet_gateway_id)
108
71
 
109
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).attach_internet_gateway(vpc_id: vpc_id, internet_gateway_id: internet_gateway_id)
72
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).attach_internet_gateway(vpc_id: @cloud_id, internet_gateway_id: internet_gateway_id)
110
73
  @config['internet_gateway_id'] = internet_gateway_id
111
74
  end
112
75
 
@@ -165,236 +128,35 @@ module MU
165
128
  )
166
129
  end
167
130
 
168
- nat_gateways = []
169
- if !@config['subnets'].nil?
170
- allocation_ids = []
171
- subnetthreads = Array.new
172
- parent_thread_id = Thread.current.object_id
173
- azs = []
174
- @config['subnets'].each { |subnet|
175
- subnet_name = @config['name']+"-"+subnet['name']
176
- MU.log "Creating Subnet #{subnet_name} (#{subnet['ip_block']})", details: subnet
177
- azs = MU::Cloud::AWS.listAZs(region: @config['region'], credentials: @config['credentials']) if azs.size == 0
178
- if !subnet['availability_zone'].nil?
179
- az = subnet['availability_zone']
180
- else
181
- az = azs.pop
182
- end
183
-
184
- subnetthreads << Thread.new {
185
- MU.dupGlobals(parent_thread_id)
186
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_subnet(
187
- vpc_id: vpc_id,
188
- cidr_block: subnet['ip_block'],
189
- availability_zone: az
190
- ).subnet
191
- subnet_id = subnet['subnet_id'] = resp.subnet_id
192
- MU::Cloud::AWS.createStandardTags(subnet_id, region: @config['region'], credentials: @config['credentials'])
193
- MU::Cloud::AWS.createTag(subnet_id, "Name", @mu_name+"-"+subnet['name'], region: @config['region'], credentials: @config['credentials'])
194
- if @config['tags']
195
- @config['tags'].each { |tag|
196
- MU::Cloud::AWS.createTag(subnet_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
197
- }
198
- end
199
-
200
- if @config['optional_tags']
201
- MU::MommaCat.listOptionalTags.each { |key, value|
202
- MU::Cloud::AWS.createTag(subnet_id, key, value, region: @config['region'], credentials: @config['credentials'])
203
- }
204
- end
205
-
206
- retries = 0
207
- begin
208
- if resp.state != "available"
209
- begin
210
- MU.log "Waiting for Subnet #{subnet_name} (#{subnet_id}) to be available", MU::NOTICE if retries > 0 and (retries % 3) == 0
211
- sleep 5
212
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
213
- rescue Aws::EC2::Errors::InvalidSubnetIDNotFound => e
214
- sleep 10
215
- retry
216
- end while resp.state != "available"
217
- end
218
- rescue NoMethodError => e
219
- if retries <= 3
220
- MU.log "Got bogus Aws::EmptyResponse error on #{subnet_id} (retries used: #{retries}/3)", MU::WARN
221
- retries = retries + 1
222
- sleep 5
223
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
224
- retry
225
- else
226
- raise e
227
- end
228
- end
229
-
230
- if !subnet['route_table'].nil?
231
- routes = {}
232
- @config['route_tables'].each { |tbl|
233
- routes[tbl['name']] = tbl
234
- }
235
- if routes.nil? or routes[subnet['route_table']].nil?
236
- MU.log "Subnet #{subnet_name} references non-existent route #{subnet['route_table']}", MU::ERR, details: @deploy.deployment['vpcs']
237
- raise MuError, "deploy failure"
238
- end
239
- MU.log "Associating Route Table '#{subnet['route_table']}' (#{routes[subnet['route_table']]['route_table_id']}) with #{subnet_name}"
240
- retries = 0
241
- begin
242
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).associate_route_table(
243
- route_table_id: routes[subnet['route_table']]['route_table_id'],
244
- subnet_id: subnet_id
245
- )
246
- rescue Aws::EC2::Errors::InvalidRouteTableIDNotFound => e
247
- retries = retries + 1
248
- if retries < 10
249
- sleep 10
250
- retry
251
- else
252
- raise MuError, e.inspect
253
- end
254
- end
255
- end
256
- retries = 0
257
- begin
258
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
259
- rescue Aws::EC2::Errors::InvalidSubnetIDNotFound => e
260
- if retries < 10
261
- MU.log "Got #{e.inspect}, waiting and retrying", MU::WARN
262
- sleep 10
263
- retries = retries + 1
264
- retry
265
- end
266
- raise MuError, e.inspect, e.backtrace
267
- end
268
-
269
- if subnet['is_public'] && subnet['create_nat_gateway']
270
- MU::MommaCat.lock("nat-gateway-eipalloc")
271
- filters = [{name: "domain", values: ["vpc"]}]
272
- eips = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_addresses(filters: filters).addresses
273
- allocation_id = nil
274
- eips.each { |eip|
275
- next if !eip.association_id.nil? and !eip.association_id.empty?
276
- if (eip.private_ip_address.nil? || eip.private_ip_address.empty?) and MU::MommaCat.lock(eip.allocation_id, true, true)
277
- if !allocation_ids.include?(eip.allocation_id)
278
- allocation_id = eip.allocation_id
279
- break
280
- end
281
- end
282
- }
283
-
284
- if allocation_id.nil?
285
- allocation_id = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).allocate_address(domain: "vpc").allocation_id
286
- MU::MommaCat.lock(allocation_id, false, true)
287
- end
131
+ nat_gateways = create_subnets
288
132
 
289
- allocation_ids << allocation_id
290
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_nat_gateway(
291
- subnet_id: subnet['subnet_id'],
292
- allocation_id: allocation_id,
293
- ).nat_gateway
294
-
295
- nat_gateway_id = resp.nat_gateway_id
296
- attempts = 0
297
- MU::MommaCat.unlock("nat-gateway-eipalloc")
298
- while resp.class.name != "Aws::EC2::Types::NatGateway" or resp.state == "pending"
299
- MU.log "Waiting for nat gateway #{nat_gateway_id} () to become available (EIP allocation: #{allocation_id})" if attempts % 5 == 0
300
- sleep 30
301
- begin
302
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_nat_gateways(nat_gateway_ids: [nat_gateway_id]).nat_gateways.first
303
- rescue Aws::EmptyStructure, NoMethodError
304
- sleep 5
305
- retry
306
- end
307
- if attempts > 30
308
- MU::MommaCat.unlock(allocation_id, true)
309
- raise MuError, "Timed out while waiting for NAT Gateway #{nat_gateway_id}: #{resp}"
310
- end
311
- attempts += 1
312
- end
313
- MU::MommaCat.unlock(allocation_id, true)
314
-
315
- raise MuError, "NAT Gateway failed #{nat_gateway_id}: #{resp}" if resp.state == "failed"
316
- nat_gateways << {'id' => nat_gateway_id, 'availability_zone' => subnet['availability_zone']}
317
- @tags.each_pair { |k, v|
318
- MU::Cloud::AWS.createTag(nat_gateway_id, k, v, region: @config['region'], credentials: @config['credentials'])
319
- }
320
- end
321
-
322
- if subnet.has_key?("map_public_ips")
323
- retries = 0
324
- begin
325
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_subnet_attribute(
326
- subnet_id: subnet_id,
327
- map_public_ip_on_launch: {
328
- value: subnet['map_public_ips'],
329
- }
330
- )
331
- rescue Aws::EC2::Errors::InvalidSubnetIDNotFound => e
332
- if retries < 10
333
- MU.log "Got #{e.inspect} while trying to enable map_public_ips on subnet, waiting and retrying", MU::WARN
334
- sleep 10
335
- retries += 1
336
- retry
337
- end
338
- raise MuError, "Got #{e.inspect}, #{e.backtrace} while trying to enable map_public_ips on subnet"
339
- end
340
- end
341
-
342
- if subnet["enable_traffic_logging"]
343
- loggroup = @deploy.findLitterMate(name: @config['name']+"loggroup", type: "logs")
344
- logrole = @deploy.findLitterMate(name: @config['name']+"logrole", type: "roles")
345
- MU.log "Enabling traffic logging on Subnet #{subnet_name} in VPC #{@mu_name} to log group #{loggroup.mu_name}"
346
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_flow_logs(
347
- resource_ids: [subnet_id],
348
- resource_type: "Subnet",
349
- traffic_type: subnet["traffic_type_to_log"],
350
- log_group_name: loggroup.mu_name,
351
- deliver_logs_permission_arn: logrole.cloudobj.arn
352
- )
353
- end
354
- }
355
- }
356
-
357
- subnetthreads.each { |t|
358
- t.join
359
- }
360
-
361
- notify
362
- end
133
+ notify
363
134
 
364
135
  if !nat_gateways.empty?
365
136
  nat_gateways.each { |gateway|
366
137
  @config['subnets'].each { |subnet|
367
- if subnet['is_public'] == false && subnet['availability_zone'] == gateway['availability_zone']
368
- @config['route_tables'].each { |rtb|
369
- if rtb['name'] == subnet['route_table']
370
- rtb['routes'].each { |route|
371
- if route['gateway'] == '#NAT'
372
- route_config = {
373
- :route_table_id => rtb['route_table_id'],
374
- :destination_cidr_block => route['destination_network'],
375
- :nat_gateway_id => gateway['id']
376
- }
377
-
378
- MU.log "Creating route for #{route['destination_network']} through NAT gatway #{gateway['id']}", details: route_config
379
- nat_retries = 0
380
- begin
381
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(route_config)
382
- rescue Aws::EC2::Errors::InvalidNatGatewayIDNotFound => e
383
- if nat_retries < 5
384
- nat_retries += 1
385
- sleep 10
386
- retry
387
- else
388
- raise e
389
- end
390
- rescue Aws::EC2::Errors::RouteAlreadyExists => e
391
- MU.log "Attempt to create duplicate route to #{route['destination_network']} for #{gateway['id']} in #{rtb['route_table_id']}", MU::WARN
392
- end
393
- end
394
- }
395
- end
138
+ next if subnet['is_public'] != false or subnet['availability_zone'] != gateway['availability_zone']
139
+
140
+ @config['route_tables'].each { |rtb|
141
+ next if rtb['name'] != subnet['route_table']
142
+ rtb['routes'].each { |route|
143
+ next if route['gateway'] != '#NAT'
144
+ route_config = {
145
+ :route_table_id => rtb['route_table_id'],
146
+ :destination_cidr_block => route['destination_network'],
147
+ :nat_gateway_id => gateway['id']
148
+ }
149
+
150
+ MU.log "Creating route for #{route['destination_network']} through NAT gatway #{gateway['id']}", details: route_config
151
+ MU.retrier([Aws::EC2::Errors::InvalidNatGatewayIDNotFound], wait: 10, max: 5) {
152
+ begin
153
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(route_config)
154
+ rescue Aws::EC2::Errors::RouteAlreadyExists
155
+ MU.log "Attempt to create duplicate route to #{route['destination_network']} for #{gateway['id']} in #{rtb['route_table_id']}", MU::WARN
156
+ end
157
+ }
396
158
  }
397
- end
159
+ }
398
160
  }
399
161
  }
400
162
  end
@@ -402,14 +164,14 @@ module MU
402
164
  if @config['enable_dns_support']
403
165
  MU.log "Enabling DNS support in #{@mu_name}"
404
166
  MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_vpc_attribute(
405
- vpc_id: vpc_id,
167
+ vpc_id: @cloud_id,
406
168
  enable_dns_support: {value: @config['enable_dns_support']}
407
169
  )
408
170
  end
409
171
  if @config['enable_dns_hostnames']
410
172
  MU.log "Enabling DNS hostnames in #{@mu_name}"
411
173
  MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_vpc_attribute(
412
- vpc_id: vpc_id,
174
+ vpc_id: @cloud_id,
413
175
  enable_dns_hostnames: {value: @config['enable_dns_hostnames']}
414
176
  )
415
177
  end
@@ -438,29 +200,16 @@ module MU
438
200
  dhcp_configurations: dhcpopts
439
201
  )
440
202
  dhcpopt_id = resp.dhcp_options.dhcp_options_id
441
- MU::Cloud::AWS.createStandardTags(dhcpopt_id, region: @config['region'], credentials: @config['credentials'])
442
- MU::Cloud::AWS.createTag(dhcpopt_id, "Name", @mu_name, region: @config['region'], credentials: @config['credentials'])
443
-
444
- if @config['tags']
445
- @config['tags'].each { |tag|
446
- MU::Cloud::AWS.createTag(dhcpopt_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
447
- }
448
- end
449
-
450
- if @config['optional_tags']
451
- MU::MommaCat.listOptionalTags.each { |key, value|
452
- MU::Cloud::AWS.createTag(dhcpopt_id, key, value, region: @config['region'], credentials: @config['credentials'])
453
- }
454
- end
203
+ tag_me(dhcpopt_id)
455
204
 
456
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).associate_dhcp_options(dhcp_options_id: dhcpopt_id, vpc_id: vpc_id)
205
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).associate_dhcp_options(dhcp_options_id: dhcpopt_id, vpc_id: @cloud_id)
457
206
  end
458
207
  notify
459
208
 
460
209
  if !MU::Cloud::AWS.isGovCloud?(@config['region'])
461
210
  mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu", credentials: @config['credentials']).values.first
462
211
  if !mu_zone.nil?
463
- MU::Cloud::AWS::DNSZone.toggleVPCAccess(id: mu_zone.id, vpc_id: vpc_id, region: @config['region'], credentials: @config['credentials'])
212
+ MU::Cloud.resourceClass("AWS", "DNSZone").toggleVPCAccess(id: mu_zone.id, vpc_id: @cloud_id, region: @config['region'], credentials: @config['credentials'])
464
213
  end
465
214
  end
466
215
  loadSubnets
@@ -471,9 +220,6 @@ module MU
471
220
  # Canonical Amazon Resource Number for this resource
472
221
  # @return [String]
473
222
  def arn
474
- puts @config['region']
475
- puts MU::Cloud::AWS.credToAcct(@config['credentials'])
476
- puts @cloud_id
477
223
  "arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":ec2:"+@config['region']+":"+MU::Cloud::AWS.credToAcct(@config['credentials'])+":vpc/"+@cloud_id
478
224
  end
479
225
 
@@ -490,202 +236,7 @@ module MU
490
236
  # Generate peering connections
491
237
  if !@config['peers'].nil? and @config['peers'].size > 0
492
238
  @config['peers'].each { |peer|
493
- peer_obj = nil
494
- peer_id = nil
495
- peer['name'] ||= peer['vpc_name']
496
- peer['id'] ||= peer['vpc_id']
497
-
498
- # If we know this to be a sibling VPC elsewhere in our stack,
499
- # go fetch it, and fix it if we've been misconfigured with a
500
- # duplicate peering connection
501
- if peer['vpc']['name'] and !peer['account']
502
- peer_obj = @deploy.findLitterMate(name: peer['vpc']['name'], type: "vpcs")
503
- if peer_obj
504
- if peer_obj.config['peers']
505
- skipme = false
506
- peer_obj.config['peers'].each { |peerpeer|
507
- if peerpeer['vpc']['name'] == @config['name'] and
508
- (peer['vpc']['name'] <=> @config['name']) == -1
509
- skipme = true
510
- MU.log "VPCs #{peer['vpc']['name']} and #{@config['name']} both declare mutual peering connection, ignoring #{@config['name']}'s redundant declaration", MU::DEBUG
511
- # XXX and if deploy_id matches or is unset
512
- end
513
- }
514
- end
515
- next if skipme
516
- peer['account'] = MU::Cloud::AWS.credToAcct(peer_obj.credentials)
517
- peer['vpc']['id'] = peer_obj.cloud_id
518
- peer['vpc']['region'] ||= peer_obj.config['region']
519
- end
520
- end
521
-
522
- # If we still don't know our peer's vpc identifier, go fishing
523
- if !peer_obj
524
- tag_key, tag_value = peer['vpc']['tag'].split(/=/, 2) if !peer['vpc']['tag'].nil?
525
- if peer['vpc']['deploy_id'].nil? and peer['vpc']['id'].nil? and tag_key.nil?
526
- peer['vpc']['deploy_id'] = @deploy.deploy_id
527
- end
528
- peer_obj = MU::MommaCat.findStray(
529
- "AWS",
530
- "vpcs",
531
- deploy_id: peer['vpc']['deploy_id'],
532
- cloud_id: peer['vpc']['id'],
533
- # XXX we need a credentials argument here... maybe
534
- name: peer['vpc']['name'],
535
- tag_key: tag_key,
536
- tag_value: tag_value,
537
- dummy_ok: true,
538
- region: peer['vpc']['region']
539
- )
540
- MU.log "wtf", MU::ERR, details: peer if peer_obj.nil? or peer_obj.first.nil?
541
- raise MuError, "No result looking for #{@mu_name}'s peer VPCs (#{peer['vpc']})" if peer_obj.nil? or peer_obj.first.nil?
542
- peer_obj = peer_obj.first
543
- peer['account'] ||= MU::Cloud::AWS.credToAcct(peer_obj.credentials)
544
- peer['vpc']['id'] ||= peer_obj.cloud_id
545
- peer['vpc']['region'] ||= peer_obj.config['region']
546
- end
547
-
548
- peer_id = peer['vpc']['id']
549
- peer['account'] ||= MU::Cloud::AWS.account_number
550
-
551
- # See if the peering connection exists before we bother
552
- # creating it.
553
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
554
- filters: [
555
- {
556
- name: "requester-vpc-info.vpc-id",
557
- values: [@cloud_id]
558
- },
559
- {
560
- name: "accepter-vpc-info.vpc-id",
561
- values: [peer_id.to_s]
562
- }
563
- ]
564
- )
565
-
566
- peering_id = if !resp or !resp.vpc_peering_connections or
567
- resp.vpc_peering_connections.empty?
568
-
569
- MU.log "Setting peering connection from VPC #{@config['name']} (#{@cloud_id} in account #{MU::Cloud::AWS.credToAcct(@config['credentials'])}) to #{peer_id} in account #{peer['account']}", details: peer
570
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_vpc_peering_connection(
571
- vpc_id: @cloud_id,
572
- peer_vpc_id: peer_id,
573
- peer_owner_id: peer['account'],
574
- peer_region: peer['vpc']['region']
575
- )
576
- resp.vpc_peering_connection.vpc_peering_connection_id
577
- else
578
- resp.vpc_peering_connections.first.vpc_peering_connection_id
579
- end
580
-
581
- peering_name = @deploy.getResourceName(@config['name']+"-PEER-"+peer['vpc']['id'])
582
-
583
- MU::Cloud::AWS.createStandardTags(peering_id, region: @config['region'], credentials: @config['credentials'])
584
- MU::Cloud::AWS.createTag(peering_id, "Name", peering_name, region: @config['region'], credentials: @config['credentials'])
585
-
586
- if @config['optional_tags']
587
- MU::MommaCat.listOptionalTags.each { |key, value|
588
- MU::Cloud::AWS.createTag(peering_id, key, value, region: @config['region'], credentials: @config['credentials'])
589
- }
590
- end
591
-
592
- if @config['tags']
593
- @config['tags'].each { |tag|
594
- MU::Cloud::AWS.createTag(peering_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
595
- }
596
- end
597
-
598
- # Create routes to our new friend.
599
- MU::Cloud::AWS::VPC.listAllSubnetRouteTables(@cloud_id, region: @config['region'], credentials: @config['credentials']).each { |rtb_id|
600
- my_route_config = {
601
- :route_table_id => rtb_id,
602
- :destination_cidr_block => peer_obj.cloud_desc.cidr_block,
603
- :vpc_peering_connection_id => peering_id
604
- }
605
- rtbdesc = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
606
- route_table_ids: [rtb_id]
607
- ).route_tables.first
608
- already_exists = false
609
- rtbdesc.routes.each { |r|
610
- if r.destination_cidr_block == peer_obj.cloud_desc.cidr_block
611
- if r.vpc_peering_connection_id != peering_id
612
- MU.log "Attempt to create duplicate route to #{peer_obj.cloud_desc.cidr_block} from VPC #{@config['name']}", MU::ERR, details: r
613
- raise MuError, "Can't create route via #{peering_id}, a route to #{peer_obj.cloud_desc.cidr_block} already exists"
614
- else
615
- already_exists = true
616
- end
617
- end
618
- }
619
- next if already_exists
620
-
621
- MU.log "Creating peering route to #{peer_obj.cloud_desc.cidr_block} in #{peer['vpc']['region']} from VPC #{@config['name']} in #{@config['region']}"
622
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(my_route_config)
623
- } # MU::Cloud::AWS::VPC.listAllSubnetRouteTables
624
-
625
- begin
626
- cnxn = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
627
- vpc_peering_connection_ids: [peering_id]
628
- ).vpc_peering_connections.first
629
-
630
- if cnxn.status.code == "pending-acceptance"
631
- if ((!peer_obj.nil? and !peer_obj.deploydata.nil? and peer_obj.deploydata['auto_accept_peers']) or $MU_CFG['allow_invade_foreign_vpcs'])
632
- MU.log "Auto-accepting peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id}", MU::NOTICE
633
- begin
634
- MU::Cloud::AWS.ec2(region: peer['vpc']['region'], credentials: peer['account']).accept_vpc_peering_connection(
635
- vpc_peering_connection_id: peering_id,
636
- )
637
- if peer['account'] != MU::Cloud::AWS.credToAcct(@config['credentials'])
638
- # this seems to take a while across accounts
639
- sleep 5
640
- end
641
- cnxn = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
642
- vpc_peering_connection_ids: [peering_id]
643
- ).vpc_peering_connections.first
644
- rescue Aws::EC2::Errors::VpcPeeringConnectionAlreadyExists => e
645
- MU.log "Attempt to create duplicate peering connection to #{peer_id} from VPC #{@config['name']}", MU::WARN
646
- end
647
-
648
- # Create routes back from our new friend to us.
649
- MU::Cloud::AWS::VPC.listAllSubnetRouteTables(peer_id, region: peer['vpc']['region'], credentials: peer['account']).uniq.each { |rtb_id|
650
- peer_route_config = {
651
- :route_table_id => rtb_id,
652
- :destination_cidr_block => @config['ip_block'],
653
- :vpc_peering_connection_id => peering_id
654
- }
655
- begin
656
- resp = MU::Cloud::AWS.ec2(region: peer['vpc']['region'], credentials: peer['account']).create_route(peer_route_config)
657
- rescue Aws::EC2::Errors::RouteAlreadyExists => e
658
- rtbdesc = MU::Cloud::AWS.ec2(region: peer['vpc']['region'], credentials: peer['account']).describe_route_tables(
659
- route_table_ids: [rtb_id]
660
- ).route_tables.first
661
- rtbdesc.routes.each { |r|
662
- if r.destination_cidr_block == @config['ip_block']
663
- if r.vpc_peering_connection_id != peering_id
664
- MU.log "Attempt to create duplicate route to VPC #{@config['name']} (#{@config['ip_block']}) from peer VPC #{peer_id}'s route table #{rtb_id}", MU::ERR
665
- end
666
- end
667
- }
668
- end
669
- }
670
- else
671
- MU.log "VPC #{peer_id} is not managed by this Mu server or is not configured to auto-accept peering requests. You must accept the peering request for '#{@config['name']}' (#{@cloud_id}) by hand.", MU::WARN, details: "In the AWS Console, go to VPC => Peering Connections and look in the Actions drop-down. You can also set 'Invade Foreign VPCs' to 'true' using mu-configure to auto-accept all peering connections within this account, regardless of whether this Mu server owns the VPCs. This setting is per-user."
672
- end
673
- end
674
-
675
- if cnxn.status.code == "failed" or cnxn.status.code == "rejected" or cnxn.status.code == "expired" or cnxn.status.code == "deleted"
676
- MU.log "VPC peering connection from VPC #{@config['name']} (#{@cloud_id} in #{@config['region']}) to #{peer_id} in #{peer['vpc']['region']} #{cnxn.status.code}: #{cnxn.status.message}", MU::ERR
677
- begin
678
- MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).delete_vpc_peering_connection(
679
- vpc_peering_connection_id: peering_id
680
- )
681
- rescue Aws::EC2::Errors::InvalidStateTransition => e
682
- # XXX apparently this is normal?
683
- end
684
- raise MuError, "VPC peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id} #{cnxn.status.code}: #{cnxn.status.message}"
685
- end
686
-
687
- end while cnxn.status.code != "active" and !((peer_obj.nil? or peer_obj.deploydata.nil? or !peer_obj.deploydata['auto_accept_peers']) and cnxn.status.code == "pending-acceptance")
688
-
239
+ peerWith(peer)
689
240
  }
690
241
  end
691
242
 
@@ -837,12 +388,9 @@ MU.log "wtf", MU::ERR, details: peer if peer_obj.nil? or peer_obj.first.nil?
837
388
  if rtb_desc.associations
838
389
  rtb_desc.associations.each { |assoc|
839
390
  if assoc.subnet_id
840
- if associations[assoc.subnet_id] and associations[assoc.subnet_id] != rtb['name']
841
- MU.log "wait more than one route table association for #{assoc.subnet_id} what", MU::WARN, details: associations[assoc.subnet_id]+" => "+rtb['name']
842
- end
843
391
  associations[assoc.subnet_id] = rtb['name']
844
392
  elsif assoc.gateway_id
845
- MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_desc
393
+ MU.log " Saw a route table association I don't know how to adopt in #{@cloud_id}", MU::WARN, details: rtb_desc
846
394
  end
847
395
  }
848
396
  end
@@ -902,20 +450,18 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
902
450
  # Describe subnets associated with this VPC. We'll compose identifying
903
451
  # information similar to what MU::Cloud.describe builds for first-class
904
452
  # resources.
905
- # XXX this is weaksauce. Subnets should be objects with their own methods
906
- # that work like first-class objects. How would we enforce that?
907
- # @return [Array<Hash>]: A list of cloud provider identifiers of subnets associated with this VPC.
453
+ # @return [Array<MU::Cloud::AWS::VPC::Subnet>]
908
454
  def loadSubnets
909
- if @cloud_id
910
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(
911
- filters: [
912
- { name: "vpc-id", values: [@cloud_id] }
913
- ]
914
- )
915
- if resp.nil? or resp.subnets.nil? or resp.subnets.size == 0
916
- MU.log "Got empty results when trying to list subnets in #{@cloud_id}", MU::WARN
917
- return []
918
- end
455
+ return [] if !@cloud_id
456
+
457
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(
458
+ filters: [
459
+ { name: "vpc-id", values: [@cloud_id] }
460
+ ]
461
+ )
462
+ if resp.nil? or resp.subnets.nil? or resp.subnets.empty?
463
+ MU.log "Got empty results when trying to list subnets in #{@cloud_id}", MU::WARN
464
+ return []
919
465
  end
920
466
 
921
467
  @subnetcachesemaphore.synchronize {
@@ -926,23 +472,21 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
926
472
  # metadata. Like ya do.
927
473
  if !@config.nil? and @config.has_key?("subnets")
928
474
  @config['subnets'].each { |subnet|
929
- subnet['mu_name'] = @mu_name+"-"+subnet['name'] if !subnet.has_key?("mu_name")
475
+ subnet['mu_name'] ||= @mu_name+"-"+subnet['name']
930
476
  subnet['region'] = @config['region']
931
477
  subnet['credentials'] = @config['credentials']
932
- if !resp.nil? and !resp.data.nil? and !resp.data.subnets.nil?
933
- resp.data.subnets.each { |desc|
934
- if desc.cidr_block == subnet["ip_block"]
935
- subnet["tags"] = MU.structToHash(desc.tags)
936
- subnet["cloud_id"] = desc.subnet_id
937
- break
938
- end
939
- }
940
- end
478
+ resp.subnets.each { |desc|
479
+ if desc.cidr_block == subnet["ip_block"]
480
+ subnet["tags"] = MU.structToHash(desc.tags)
481
+ subnet["cloud_id"] = desc.subnet_id
482
+ break
483
+ end
484
+ }
941
485
 
942
486
  if subnet["cloud_id"] and !ext_ids.include?(subnet["cloud_id"])
943
487
  @subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
944
488
  elsif !subnet["cloud_id"]
945
- resp.data.subnets.each { |desc|
489
+ resp.subnets.each { |desc|
946
490
  if desc.cidr_block == subnet["ip_block"]
947
491
  subnet['cloud_id'] = desc.subnet_id
948
492
  @subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
@@ -955,21 +499,21 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
955
499
 
956
500
  # Of course we might be loading up a dummy subnet object from a
957
501
  # foreign or non-Mu-created VPC and subnet. So make something up.
958
- if !resp.nil? and @subnets.empty?
959
- resp.data.subnets.each { |desc|
960
- subnet = {}
961
- subnet["ip_block"] = desc.cidr_block
962
- subnet["name"] = subnet["ip_block"].gsub(/[\.\/]/, "_")
502
+ if @subnets.empty?
503
+ resp.subnets.each { |desc|
504
+ subnet = {
505
+ "ip_block" => desc.cidr_block,
506
+ "tags" => MU.structToHash(desc.tags),
507
+ "cloud_id" => desc.subnet_id,
508
+ 'region' => @config['region'],
509
+ 'credentials' => @config['credentials'],
510
+ }
511
+ subnet['name'] = subnet["ip_block"].gsub(/[\.\/]/, "_")
963
512
  subnet['mu_name'] = @mu_name+"-"+subnet['name']
964
- subnet["tags"] = MU.structToHash(desc.tags)
965
- subnet["cloud_id"] = desc.subnet_id
966
- subnet['region'] = @config['region']
967
- subnet['credentials'] = @config['credentials']
968
- if !ext_ids.include?(desc.subnet_id)
969
- @subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
970
- end
513
+ @subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
971
514
  }
972
515
  end
516
+
973
517
  return @subnets
974
518
  }
975
519
  end
@@ -1138,14 +682,14 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1138
682
  MU::Cloud::AWS::VPC.update_route_tables_cache(my_subnets_key, region: MU.myRegion)
1139
683
  MU::Cloud::AWS::VPC.update_route_tables_cache(target_subnets_key, region: region, credentials: credentials)
1140
684
 
1141
- if MU::Cloud::AWS::VPC.have_route_peered_vpc?(my_subnets_key, target_subnets_key, instance_id)
685
+ if MU::Cloud::AWS::VPC.can_route_to_master_peer?(my_subnets_key, target_subnets_key, instance_id)
1142
686
  return true
1143
687
  else
1144
688
  # The cache can be out of date at times, check again without it
1145
689
  MU::Cloud::AWS::VPC.update_route_tables_cache(my_subnets_key, use_cache: false, region: MU.myRegion)
1146
690
  MU::Cloud::AWS::VPC.update_route_tables_cache(target_subnets_key, use_cache: false, region: region, credentials: credentials)
1147
691
 
1148
- return MU::Cloud::AWS::VPC.have_route_peered_vpc?(my_subnets_key, target_subnets_key, instance_id)
692
+ return MU::Cloud::AWS::VPC.can_route_to_master_peer?(my_subnets_key, target_subnets_key, instance_id)
1149
693
  end
1150
694
 
1151
695
  end
@@ -1184,7 +728,7 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1184
728
  # @param target_subnets_key [String]: The subnet/subnets on the other side of the peered VPC.
1185
729
  # @param instance_id [String]: The instance ID in the target subnet/subnets.
1186
730
  # @return [Boolean]
1187
- def self.have_route_peered_vpc?(source_subnets_key, target_subnets_key, instance_id)
731
+ def self.can_route_to_master_peer?(source_subnets_key, target_subnets_key, instance_id)
1188
732
  my_routes = []
1189
733
  vpc_peer_mapping = {}
1190
734
 
@@ -1278,32 +822,39 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1278
822
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
1279
823
  # @param region [String]: The cloud provider region
1280
824
  # @return [void]
1281
- 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: {})
1282
826
  MU.log "AWS::VPC.cleanup: need to support flags['known']", MU::DEBUG, details: flags
1283
827
 
1284
828
  tagfilters = [
1285
- {name: "tag:MU-ID", values: [MU.deploy_id]}
829
+ {name: "tag:MU-ID", values: [deploy_id]}
1286
830
  ]
1287
831
  if !ignoremaster
1288
832
  tagfilters << {name: "tag:MU-MASTER-IP", values: [MU.mu_public_ip]}
1289
833
  end
1290
834
 
1291
835
  vpcs = []
1292
- retries = 0
1293
- begin
836
+ MU.retrier([Aws::EC2::Errors::InvalidVpcIDNotFound], wait: 5) {
1294
837
  resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_vpcs(filters: tagfilters, max_results: 1000).vpcs
1295
838
  vpcs = resp if !resp.empty?
1296
- rescue Aws::EC2::Errors::InvalidVpcIDNotFound
1297
- if retries < 5
1298
- sleep 5
1299
- retries += 1
1300
- retry
1301
- end
1302
- end
839
+ }
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
+ # )
1303
853
 
1304
854
  if !vpcs.empty?
1305
855
  gwthreads = []
1306
856
  vpcs.each { |vpc|
857
+ purge_peering_connections(noop, vpc.vpc_id, region: region, credentials: credentials)
1307
858
  # NAT gateways don't have any tags, and we can't assign them a name. Lets find them based on a VPC ID
1308
859
  gwthreads << Thread.new {
1309
860
  purge_nat_gateways(noop, vpc_id: vpc.vpc_id, region: region, credentials: credentials)
@@ -1325,7 +876,7 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1325
876
 
1326
877
  # unless noop
1327
878
  # MU::Cloud::AWS.iam.list_roles.roles.each{ |role|
1328
- # match_string = "#{MU.deploy_id}.*TRAFFIC-LOG"
879
+ # match_string = "#{deploy_id}.*TRAFFIC-LOG"
1329
880
  # }
1330
881
  # end
1331
882
  end
@@ -1379,11 +930,7 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1379
930
  logdesc["tags"] = vpc["tags"] if !vpc["tags"].nil?
1380
931
  # logdesc["optional_tags"] = vpc["optional_tags"] if !vpc["optional_tags"].nil?
1381
932
  configurator.insertKitten(logdesc, "logs")
1382
- vpc['dependencies'] ||= []
1383
- vpc['dependencies'] << {
1384
- "type" => "log",
1385
- "name" => vpc['name']+"loggroup"
1386
- }
933
+ MU::Config.addDependency(vpc, vpc['name']+"loggroup", "log")
1387
934
 
1388
935
  roledesc = {
1389
936
  "name" => vpc['name']+"logrole",
@@ -1421,11 +968,7 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1421
968
  roledesc["tags"] = vpc["tags"] if !vpc["tags"].nil?
1422
969
  roledesc["optional_tags"] = vpc["optional_tags"] if !vpc["optional_tags"].nil?
1423
970
  configurator.insertKitten(roledesc, "roles")
1424
- vpc['dependencies'] ||= []
1425
- vpc['dependencies'] << {
1426
- "type" => "role",
1427
- "name" => vpc['name']+"logrole"
1428
- }
971
+ MU::Config.addDependency(vpc, vpc['name']+"logrole", "role")
1429
972
  end
1430
973
 
1431
974
  subnet_routes = Hash.new
@@ -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['dependencies'] << {
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
- if vpc['nat_gateway_multi_az']
1497
- subnet['create_nat_gateway'] = true
1498
- else
1499
- if nat_gateway_added
1500
- subnet['create_nat_gateway'] = false
1501
- else
1502
- subnet['create_nat_gateway'] = true
1503
- nat_gateway_added = true
1504
- end
1505
- end
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
@@ -1662,17 +1196,10 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1662
1196
 
1663
1197
  ifaces.each { |iface|
1664
1198
  if iface.vpc_id
1665
- default_sg_resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_security_groups(
1666
- filters: [
1667
- { name: "group-name", values: ["default"] },
1668
- { name: "vpc-id", values: [iface.vpc_id] }
1669
- ]
1670
- ).security_groups
1671
- if default_sg_resp and default_sg_resp.size == 1
1672
- default_sg = default_sg_resp.first.group_id
1673
- if iface.groups.size > 1 or
1674
- iface.groups.first.group_id != default_sg
1675
- MU.log "Removing extra security groups from ENI #{iface.network_interface_id}"
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
1676
1203
  begin
1677
1204
  MU::Cloud::AWS.ec2(credentials: credentials, region: region).modify_network_interface_attribute(
1678
1205
  network_interface_id: iface.network_interface_id,
@@ -1693,11 +1220,15 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1693
1220
  rescue Aws::EC2::Errors::OperationNotPermitted => e
1694
1221
  MU.log "Can't detach #{iface.network_interface_id}: #{e.message}", MU::WARN, details: iface.attachment
1695
1222
  next
1223
+ rescue Aws::EC2::Errors::IncorrectState => e
1224
+ MU.log e.message, MU::WARN
1225
+ sleep 5
1226
+ retry
1696
1227
  rescue Aws::EC2::Errors::InvalidAttachmentIDNotFound => e
1697
1228
  # suits me just fine
1698
1229
  rescue Aws::EC2::Errors::AuthFailure => e
1699
1230
  if !tried_lbs and iface.attachment.instance_owner_id == "amazon-elb"
1700
- MU::Cloud::AWS::LoadBalancer.cleanup(
1231
+ MU::Cloud.resourceClass("AWS", "LoadBalancer").cleanup(
1701
1232
  noop: noop,
1702
1233
  region: region,
1703
1234
  credentials: credentials,
@@ -1719,9 +1250,230 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1719
1250
  }
1720
1251
  end
1721
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
1722
1327
 
1723
1328
  private
1724
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
+
1725
1477
  # Helper method for manufacturing route tables. Expect to be called from
1726
1478
  # {MU::Cloud::AWS::VPC#create} or {MU::Cloud::AWS::VPC#groom}.
1727
1479
  # @param rtb [Hash]: A route table description parsed through {MU::Config::BasketofKittens::vpcs::route_tables}.
@@ -1733,21 +1485,9 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1733
1485
  resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route_table(vpc_id: vpc_id).route_table
1734
1486
  route_table_id = rtb['route_table_id'] = resp.route_table_id
1735
1487
  sleep 5
1736
- MU::Cloud::AWS.createTag(route_table_id, "Name", vpc_name+"-"+rtb['name'].upcase, credentials: @config['credentials'])
1737
-
1738
- if @config['tags']
1739
- @config['tags'].each { |tag|
1740
- MU::Cloud::AWS.createTag(route_table_id, tag['key'], tag['value'], credentials: @config['credentials'])
1741
- }
1742
- end
1743
1488
 
1744
- if @config['optional_tags']
1745
- MU::MommaCat.listOptionalTags.each { |key, value|
1746
- MU::Cloud::AWS.createTag(route_table_id, key, value, region: @config['region'], credentials: @config['credentials'])
1747
- }
1748
- end
1489
+ tag_me(route_table_id, vpc_name+"-"+rtb['name'].upcase)
1749
1490
 
1750
- MU::Cloud::AWS.createStandardTags(route_table_id, credentials: @config['credentials'])
1751
1491
  rtb['routes'].each { |route|
1752
1492
  if route['nat_host_id'].nil? and route['nat_host_name'].nil?
1753
1493
  route_config = {
@@ -1840,36 +1580,25 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1840
1580
  ).nat_gateways
1841
1581
 
1842
1582
  threads = []
1843
- parent_thread_id = Thread.current.object_id
1583
+
1844
1584
  if !gateways.empty?
1845
1585
  gateways.each { |gateway|
1586
+ next if noop
1587
+ MU.log "Deleting NAT Gateway #{gateway.nat_gateway_id}"
1846
1588
  threads << Thread.new {
1847
- MU.dupGlobals(parent_thread_id)
1848
- MU.log "Deleting NAT Gateway #{gateway.nat_gateway_id}"
1849
- if !noop
1850
- begin
1851
- MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_nat_gateway(nat_gateway_id: gateway.nat_gateway_id)
1852
- resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_nat_gateways(nat_gateway_ids: [gateway.nat_gateway_id]).nat_gateways.first
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
+ }
1853
1601
 
1854
- attempts = 0
1855
- while resp.state != "deleted" and resp.state != "failed"
1856
- MU.log "Waiting for nat gateway #{gateway.nat_gateway_id} to delete" if attempts % 2 == 0
1857
- sleep 30
1858
- begin
1859
- resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_nat_gateways(nat_gateway_ids: [gateway.nat_gateway_id]).nat_gateways.first
1860
- rescue Aws::EmptyStructure, NoMethodError
1861
- sleep 5
1862
- retry
1863
- rescue Aws::EC2::Errors::NatGatewayNotFound
1864
- MU.log "NAT gateway #{gateway.nat_gateway_id} already deleted", MU::NOTICE
1865
- end
1866
- MU.log "Timed out while waiting for NAT Gateway to delete #{gateway.nat_gateway_id}: #{resp}", MU::WARN if attempts > 50
1867
- attempts += 1
1868
- end
1869
- rescue Aws::EC2::Errors::NatGatewayMalformed
1870
- MU.log "NAT Gateway #{gateway.nat_gateway_id} was already deleted", MU::NOTICE
1871
- end
1872
- end
1873
1602
  }
1874
1603
  }
1875
1604
  end
@@ -1898,38 +1627,21 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
1898
1627
  ).vpc_endpoints
1899
1628
 
1900
1629
  threads = []
1901
- parent_thread_id = Thread.current.object_id
1630
+
1902
1631
  if !vpc_endpoints.empty?
1903
1632
  vpc_endpoints.each { |endpoint|
1633
+ MU.log "Deleting VPC endpoint #{endpoint.vpc_endpoint_id}"
1634
+ next if noop
1904
1635
  threads << Thread.new {
1905
- MU.dupGlobals(parent_thread_id)
1906
- MU.log "Deleting VPC endpoint #{endpoint.vpc_endpoint_id}"
1907
- if !noop
1908
- begin
1909
- MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id])
1910
- resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id]).vpc_endpoints.first
1911
-
1912
- attempts = 0
1913
- while resp.state != "deleted"
1914
- MU.log "Waiting for VPC endpoint #{endpoint.vpc_endpoint_id} to delete" if attempts % 5 == 0
1915
- sleep 30
1916
- begin
1917
- resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id]).vpc_endpoints.first
1918
- rescue Aws::EmptyStructure, NoMethodError
1919
- sleep 5
1920
- retry
1921
- rescue Aws::EC2::Errors::InvalidVpcEndpointIdNotFound
1922
- MU.log "VPC endpoint #{endpoint.vpc_endpoint_id} already deleted", MU::NOTICE
1923
- end
1924
- MU.log "Timed out while waiting for VPC endpoint to delete #{endpoint.vpc_endpoint_id}: #{resp}", MU::WARN if attempts > 50
1925
- attempts += 1
1926
- end
1927
- rescue Aws::EC2::Errors::VpcEndpointIdMalformed
1928
- MU.log "VPC endpoint #{endpoint.vpc_endpoint_id} was already deleted", MU::NOTICE
1929
- rescue Aws::EC2::Errors::InvalidVpcEndpointIdNotFound
1930
- MU.log "VPC endpoint #{endpoint.vpc_endpoint_id} already deleted", MU::NOTICE
1931
- end
1932
- end
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
+ }
1933
1645
  }
1934
1646
  }
1935
1647
  end
@@ -2001,56 +1713,6 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
2001
1713
  end
2002
1714
  private_class_method :purge_routetables
2003
1715
 
2004
- # Remove all subnets associated with the currently loaded deployment.
2005
- # @param noop [Boolean]: If true, will only print what would be done
2006
- # @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
2007
- # @param region [String]: The cloud provider region
2008
- # @return [void]
2009
- def self.purge_subnets(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
2010
- resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_subnets(
2011
- filters: tagfilters
2012
- )
2013
- subnets = resp.data.subnets
2014
-
2015
- return if subnets.nil? or subnets.size == 0
2016
-
2017
- retries = 0
2018
- subnets.each { |subnet|
2019
- MU.log "Deleting Subnet #{subnet.subnet_id}"
2020
- begin
2021
- if subnet.state != "available"
2022
- MU.log "Waiting for #{subnet.subnet_id} to be in a removable state...", MU::NOTICE
2023
- sleep 30
2024
- else
2025
- MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_subnet(subnet_id: subnet.subnet_id) if !noop
2026
- end
2027
- rescue Aws::EC2::Errors::DependencyViolation => e
2028
- # We're often stuck waiting for an RDS database or something else
2029
- # that takes 5-ever to delete.
2030
- if retries < 19
2031
- loglevel = (retries > 0 and (retries % 3) == 0) ? MU::NOTICE : MU::DEBUG
2032
- MU.log "#{e.message} (retry #{retries.to_s}/20)", loglevel
2033
- if loglevel == MU::NOTICE
2034
- MU::Cloud::AWS::VPC.purge_interfaces(noop, [{name: "subnet-id", values: [subnet.subnet_id]}], region: region, credentials: credentials)
2035
- end
2036
- sleep 30
2037
- retries = retries + 1
2038
- retry
2039
- elsif retries < 20
2040
- MU.log "#{e.message} (final attempt)", MU::WARN
2041
- sleep 60
2042
- retries = retries + 1
2043
- retry
2044
- else
2045
- raise e
2046
- end
2047
- rescue Aws::EC2::Errors::InvalidSubnetIDNotFound
2048
- next
2049
- end while subnet.state != "available"
2050
- }
2051
- end
2052
- private_class_method :purge_subnets
2053
-
2054
1716
  # Remove all DHCP options sets associated with the currently loaded
2055
1717
  # deployment.
2056
1718
  # @param noop [Boolean]: If true, will only print what would be done
@@ -2081,6 +1743,61 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
2081
1743
  end
2082
1744
  private_class_method :purge_dhcpopts
2083
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
1800
+
2084
1801
  # Remove all VPCs associated with the currently loaded deployment.
2085
1802
  # @param noop [Boolean]: If true, will only print what would be done
2086
1803
  # @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
@@ -2088,177 +1805,40 @@ MU.log "association I don't understand in #{@cloud_id}", MU::WARN, details: rtb_
2088
1805
  # @return [void]
2089
1806
  def self.purge_vpcs(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
2090
1807
  resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpcs(
2091
- filters: tagfilters
1808
+ filters: tagfilters
2092
1809
  )
2093
1810
 
2094
1811
  vpcs = resp.data.vpcs
2095
1812
  return if vpcs.nil? or vpcs.size == 0
2096
1813
 
2097
1814
  vpcs.each { |vpc|
2098
- my_peer_conns = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_peering_connections(
2099
- filters: [
2100
- {
2101
- name: "requester-vpc-info.vpc-id",
2102
- values: [vpc.vpc_id]
2103
- }
2104
- ]
2105
- ).vpc_peering_connections
2106
- my_peer_conns.concat(MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_peering_connections(
2107
- filters: [
2108
- {
2109
- name: "accepter-vpc-info.vpc-id",
2110
- values: [vpc.vpc_id]
2111
- }
2112
- ]
2113
- ).vpc_peering_connections)
2114
- my_peer_conns.each { |cnxn|
2115
-
2116
- [cnxn.accepter_vpc_info.vpc_id, cnxn.requester_vpc_info.vpc_id].each { |peer_vpc|
2117
- MU::Cloud::AWS::VPC.listAllSubnetRouteTables(peer_vpc, region: region, credentials: credentials).each { |rtb_id|
2118
- begin
2119
- resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_route_tables(
2120
- route_table_ids: [rtb_id]
2121
- )
2122
- rescue Aws::EC2::Errors::InvalidRouteTableIDNotFound
2123
- next
2124
- end
2125
- resp.route_tables.each { |rtb|
2126
- rtb.routes.each { |route|
2127
- if route.vpc_peering_connection_id == cnxn.vpc_peering_connection_id
2128
- MU.log "Removing route #{route.destination_cidr_block} from route table #{rtb_id} in VPC #{peer_vpc}"
2129
- MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_route(
2130
- route_table_id: rtb_id,
2131
- destination_cidr_block: route.destination_cidr_block
2132
- ) if !noop
2133
- end
2134
- }
2135
- }
2136
- }
2137
- }
2138
- MU.log "Deleting VPC peering connection #{cnxn.vpc_peering_connection_id}"
2139
- begin
2140
- MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_vpc_peering_connection(
2141
- vpc_peering_connection_id: cnxn.vpc_peering_connection_id
2142
- ) if !noop
2143
- rescue Aws::EC2::Errors::InvalidStateTransition
2144
- MU.log "VPC peering connection #{cnxn.vpc_peering_connection_id} not in removable (state #{cnxn.status.code})", MU::WARN
2145
- rescue Aws::EC2::Errors::OperationNotPermitted => e
2146
- MU.log "VPC peering connection #{cnxn.vpc_peering_connection_id} refuses to delete: #{e.message}", MU::WARN
2147
- 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)
2148
1825
  }
2149
1826
 
2150
- retries = 0
2151
- begin
1827
+ MU.retrier([Aws::EC2::Errors::DependencyViolation], ignoreme: [Aws::EC2::Errors::InvalidVpcIDNotFound], max: 20, on_retry: on_retry) {
2152
1828
  MU.log "Deleting VPC #{vpc.vpc_id}"
2153
1829
  MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_vpc(vpc_id: vpc.vpc_id) if !noop
2154
- rescue Aws::EC2::Errors::InvalidVpcIDNotFound
2155
- MU.log "VPC #{vpc.vpc_id} has already been deleted", MU::WARN
2156
- rescue Aws::EC2::Errors::DependencyViolation => e
2157
- if retries < 5
2158
- MU.log "#{vpc.vpc_id} in #{region} had hidden dependencies, will try to remove them", MU::NOTICE
2159
- retries += 1
2160
- # fry some common rogue resources
2161
- MU::Cloud::AWS::FirewallRule.cleanup(
2162
- noop: noop,
2163
- region: region,
2164
- credentials: credentials,
2165
- flags: { "vpc_id" => vpc.vpc_id }
2166
- )
2167
- purge_gateways(noop, tagfilters, region: region, credentials: credentials)
2168
- sleep 10
2169
- retry
2170
- else
2171
- MU.log "Failed to remove #{vpc.vpc_id} in #{region}: #{e.message}", MU::ERR
2172
- next
2173
- end
2174
- end
1830
+ }
2175
1831
 
2176
1832
  if !MU::Cloud::AWS.isGovCloud?(region)
2177
1833
  mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu", region: region, credentials: credentials).values.first
2178
1834
  if !mu_zone.nil?
2179
- MU::Cloud::AWS::DNSZone.toggleVPCAccess(id: mu_zone.id, vpc_id: vpc.vpc_id, remove: true, credentials: credentials)
1835
+ MU::Cloud.resourceClass("AWS", "DNSZone").toggleVPCAccess(id: mu_zone.id, vpc_id: vpc.vpc_id, remove: true, credentials: credentials)
2180
1836
  end
2181
1837
  end
2182
1838
  }
2183
1839
  end
2184
1840
  private_class_method :purge_vpcs
2185
1841
 
2186
- # Subnets are almost a first-class resource. So let's kinda sorta treat
2187
- # them like one. This should only be invoked on objects that already
2188
- # exists in the cloud layer.
2189
- class Subnet < MU::Cloud::AWS::VPC
2190
-
2191
- attr_reader :cloud_id
2192
- attr_reader :ip_block
2193
- attr_reader :mu_name
2194
- attr_reader :name
2195
- attr_reader :az
2196
- attr_reader :cloud_desc
2197
-
2198
- # @param parent [MU::Cloud::AWS::VPC]: The parent VPC of this subnet.
2199
- # @param config [Hash<String>]:
2200
- def initialize(parent, config)
2201
- @parent = parent
2202
- @config = MU::Config.manxify(config)
2203
- @cloud_id = config['cloud_id']
2204
- @mu_name = config['mu_name']
2205
- @name = config['name']
2206
- @deploydata = config # This is a dummy for the sake of describe()
2207
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [@cloud_id]).subnets.first
2208
- @az = resp.availability_zone
2209
- @ip_block = resp.cidr_block
2210
- @cloud_desc = resp # XXX this really isn't the cloud implementation's business
2211
-
2212
- end
2213
-
2214
- # Return the cloud identifier for the default route of this subnet.
2215
- def defaultRoute
2216
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
2217
- filters: [{name: "association.subnet-id", values: [@cloud_id]}]
2218
- )
2219
- if resp.route_tables.size == 0 # use default route table for the VPC
2220
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
2221
- filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
2222
- )
2223
- end
2224
- resp.route_tables.each { |route_table|
2225
- route_table.routes.each { |route|
2226
- if route.destination_cidr_block =="0.0.0.0/0" and route.state != "blackhole"
2227
- return route.instance_id if !route.instance_id.nil?
2228
- return route.gateway_id if !route.gateway_id.nil?
2229
- return route.vpc_peering_connection_id if !route.vpc_peering_connection_id.nil?
2230
- return route.network_interface_id if !route.network_interface_id.nil?
2231
- end
2232
- }
2233
- }
2234
- return nil
2235
- end
2236
-
2237
- # Is this subnet privately-routable only, or public?
2238
- # @return [Boolean]
2239
- def private?
2240
- return false if @cloud_id.nil?
2241
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
2242
- filters: [{name: "association.subnet-id", values: [@cloud_id]}]
2243
- )
2244
- if resp.route_tables.size == 0 # use default route table for the VPC
2245
- resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
2246
- filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
2247
- )
2248
- end
2249
- resp.route_tables.each { |route_table|
2250
- route_table.routes.each { |route|
2251
- return false if !route.gateway_id.nil? and route.gateway_id != "local" # you can have an IgW and route it to a subset of IPs instead of 0.0.0.0/0
2252
- if route.destination_cidr_block == "0.0.0.0/0"
2253
- return true if !route.instance_id.nil?
2254
- return true if route.nat_gateway_id
2255
- end
2256
- }
2257
- }
2258
- return true
2259
- end
2260
- end
2261
-
2262
1842
  end #class
2263
1843
  end #class
2264
1844
  end