cloud-mu 3.0.0beta → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -8
  3. data/ansible/roles/mu-nat/README.md +33 -0
  4. data/ansible/roles/mu-nat/defaults/main.yml +3 -0
  5. data/ansible/roles/mu-nat/handlers/main.yml +2 -0
  6. data/ansible/roles/mu-nat/meta/main.yml +60 -0
  7. data/ansible/roles/mu-nat/tasks/main.yml +65 -0
  8. data/ansible/roles/mu-nat/tests/inventory +2 -0
  9. data/ansible/roles/mu-nat/tests/test.yml +5 -0
  10. data/ansible/roles/mu-nat/vars/main.yml +2 -0
  11. data/bin/mu-cleanup +2 -1
  12. data/bin/mu-configure +950 -948
  13. data/bin/mu-gen-docs +6 -0
  14. data/cloud-mu.gemspec +2 -2
  15. data/cookbooks/mu-tools/recipes/gcloud.rb +8 -1
  16. data/modules/mommacat.ru +1 -1
  17. data/modules/mu.rb +31 -39
  18. data/modules/mu/cloud.rb +11 -1
  19. data/modules/mu/clouds/aws.rb +8 -3
  20. data/modules/mu/clouds/aws/alarm.rb +5 -8
  21. data/modules/mu/clouds/aws/bucket.rb +15 -9
  22. data/modules/mu/clouds/aws/cache_cluster.rb +60 -26
  23. data/modules/mu/clouds/aws/collection.rb +4 -4
  24. data/modules/mu/clouds/aws/container_cluster.rb +50 -33
  25. data/modules/mu/clouds/aws/database.rb +25 -21
  26. data/modules/mu/clouds/aws/dnszone.rb +12 -14
  27. data/modules/mu/clouds/aws/endpoint.rb +5 -8
  28. data/modules/mu/clouds/aws/firewall_rule.rb +9 -4
  29. data/modules/mu/clouds/aws/folder.rb +4 -7
  30. data/modules/mu/clouds/aws/function.rb +5 -8
  31. data/modules/mu/clouds/aws/group.rb +5 -8
  32. data/modules/mu/clouds/aws/habitat.rb +2 -5
  33. data/modules/mu/clouds/aws/loadbalancer.rb +12 -16
  34. data/modules/mu/clouds/aws/log.rb +6 -9
  35. data/modules/mu/clouds/aws/msg_queue.rb +16 -19
  36. data/modules/mu/clouds/aws/nosqldb.rb +27 -18
  37. data/modules/mu/clouds/aws/notifier.rb +6 -9
  38. data/modules/mu/clouds/aws/role.rb +4 -7
  39. data/modules/mu/clouds/aws/search_domain.rb +50 -23
  40. data/modules/mu/clouds/aws/server.rb +20 -14
  41. data/modules/mu/clouds/aws/server_pool.rb +22 -12
  42. data/modules/mu/clouds/aws/storage_pool.rb +9 -14
  43. data/modules/mu/clouds/aws/user.rb +5 -8
  44. data/modules/mu/clouds/aws/userdata/linux.erb +7 -1
  45. data/modules/mu/clouds/aws/vpc.rb +16 -14
  46. data/modules/mu/clouds/azure.rb +1 -1
  47. data/modules/mu/clouds/azure/container_cluster.rb +1 -1
  48. data/modules/mu/clouds/azure/server.rb +16 -2
  49. data/modules/mu/clouds/azure/user.rb +1 -1
  50. data/modules/mu/clouds/azure/userdata/linux.erb +84 -80
  51. data/modules/mu/clouds/azure/vpc.rb +32 -13
  52. data/modules/mu/clouds/cloudformation/server.rb +1 -1
  53. data/modules/mu/clouds/google.rb +2 -3
  54. data/modules/mu/clouds/google/container_cluster.rb +9 -1
  55. data/modules/mu/clouds/google/firewall_rule.rb +6 -0
  56. data/modules/mu/clouds/google/role.rb +1 -3
  57. data/modules/mu/clouds/google/server.rb +25 -4
  58. data/modules/mu/clouds/google/user.rb +1 -1
  59. data/modules/mu/clouds/google/userdata/linux.erb +9 -5
  60. data/modules/mu/clouds/google/vpc.rb +102 -21
  61. data/modules/mu/config.rb +250 -49
  62. data/modules/mu/config/alarm.rb +1 -0
  63. data/modules/mu/config/container_cluster.yml +0 -1
  64. data/modules/mu/config/database.yml +4 -1
  65. data/modules/mu/config/search_domain.yml +4 -3
  66. data/modules/mu/config/server.rb +7 -3
  67. data/modules/mu/config/server.yml +4 -1
  68. data/modules/mu/config/server_pool.yml +2 -0
  69. data/modules/mu/config/vpc.rb +42 -29
  70. data/modules/mu/deploy.rb +12 -5
  71. data/modules/mu/groomers/ansible.rb +4 -1
  72. data/modules/mu/groomers/chef.rb +5 -1
  73. data/modules/mu/kittens.rb +60 -11
  74. data/modules/mu/logger.rb +6 -4
  75. data/modules/mu/mommacat.rb +39 -19
  76. data/modules/mu/mu.yaml.rb +276 -0
  77. metadata +13 -4
@@ -494,19 +494,29 @@ module MU
494
494
  MU.log "Creating VPC #{@mu_name} (#{@config['ip_block']}) in #{@config['region']}", details: vpc_obj
495
495
  need_apply = true
496
496
  elsif ext_vpc.location != vpc_obj.location or
497
- ext_vpc.tags != vpc_obj.tags or
497
+ # ext_vpc.tags != vpc_obj.tags or
498
+ # XXX updating tags is a different API call
498
499
  ext_vpc.address_space.address_prefixes != vpc_obj.address_space.address_prefixes
499
500
  MU.log "Updating VPC #{@mu_name} (#{@config['ip_block']}) in #{@config['region']}", MU::NOTICE, details: vpc_obj
501
+ MU.structToHash(ext_vpc).diff(MU.structToHash(vpc_obj))
500
502
  need_apply = true
501
503
  end
502
504
 
503
505
  if need_apply
504
- resp = MU::Cloud::Azure.network(credentials: @config['credentials']).virtual_networks.create_or_update(
505
- @resource_group,
506
- @mu_name,
507
- vpc_obj
508
- )
509
- @cloud_id = Id.new(resp.id)
506
+ begin
507
+ resp = MU::Cloud::Azure.network(credentials: @config['credentials']).virtual_networks.create_or_update(
508
+ @resource_group,
509
+ @mu_name,
510
+ vpc_obj
511
+ )
512
+ @cloud_id = Id.new(resp.id)
513
+ rescue ::MU::Cloud::Azure::APIError => e
514
+ if e.message.match(/InUseSubnetCannotBeDeleted: /)
515
+ MU.log "Cannot delete an in-use Azure subnet", MU::WARN
516
+ else
517
+ raise e
518
+ end
519
+ end
510
520
  end
511
521
 
512
522
  # this is slow, so maybe thread it
@@ -676,17 +686,26 @@ module MU
676
686
  ext_subnet.network_security_group.nil? and !subnet_obj.network_security_group.nil? or
677
687
  (!ext_subnet.network_security_group.nil? and !subnet_obj.network_security_group.nil? and ext_subnet.network_security_group.id != subnet_obj.network_security_group.id)
678
688
  MU.log "Updating Subnet #{subnet_name} in VPC #{@mu_name}", MU::NOTICE, details: subnet_obj
689
+ MU.structToHash(ext_subnet).diff(MU.structToHash(subnet_obj))
679
690
  need_apply = true
680
691
 
681
692
  end
682
693
 
683
694
  if need_apply
684
- MU::Cloud::Azure.network(credentials: @config['credentials']).subnets.create_or_update(
685
- @resource_group,
686
- @cloud_id.to_s,
687
- subnet_name,
688
- subnet_obj
689
- )
695
+ begin
696
+ MU::Cloud::Azure.network(credentials: @config['credentials']).subnets.create_or_update(
697
+ @resource_group,
698
+ @cloud_id.to_s,
699
+ subnet_name,
700
+ subnet_obj
701
+ )
702
+ rescue ::MU::Cloud::Azure::APIError => e
703
+ if e.message.match(/InUseSubnetCannotBeUpdated: /)
704
+ MU.log "Cannot alter an in-use Azure subnet", MU::WARN
705
+ else
706
+ raise e
707
+ end
708
+ end
690
709
  end
691
710
  }
692
711
  }
@@ -304,7 +304,7 @@ module MU
304
304
  role_name: baserole.role_name,
305
305
  policy_name: name
306
306
  )
307
- policies[name] = URI.decode_www_form(resp.policy_document)
307
+ policies[name] = URI.decode(resp.policy_document)
308
308
  }
309
309
  }
310
310
  end
@@ -352,8 +352,7 @@ module MU
352
352
  )
353
353
  f.unlink
354
354
  rescue ::Google::Apis::ClientError => e
355
- # XXX comment for NCBI tests
356
- # raise MU::MommaCat::DeployInitializeError, "Got #{e.inspect} trying to write #{name} to #{adminBucketName(credentials)}"
355
+ raise MU::MommaCat::DeployInitializeError, "Got #{e.inspect} trying to write #{name} to #{adminBucketName(credentials)}"
357
356
  end
358
357
  end
359
358
 
@@ -406,7 +405,7 @@ module MU
406
405
  MU.log e.message, MU::WARN, details: e.inspect
407
406
  if e.inspect.match(/body: "Not Found"/)
408
407
  raise MuError, "Google admin bucket #{adminBucketName(credentials)} or key #{name} does not appear to exist or is not visible with #{credentials ? credentials : "default"} credentials"
409
- elsif e.message.match(/notFound: /)
408
+ elsif e.message.match(/notFound: |Unknown user:/)
410
409
  if retries < 5
411
410
  sleep 5
412
411
  retries += 1
@@ -464,7 +464,7 @@ module MU
464
464
  )
465
465
  end
466
466
 
467
- MU.log %Q{How to interact with your Kubernetes cluster\nkubectl --kubeconfig "#{kube_conf}" get events --all-namespaces\nkubectl --kubeconfig "#{kube_conf}" get all\nkubectl --kubeconfig "#{kube_conf}" create -f some_k8s_deploy.yml\nkubectl --kubeconfig "#{kube_conf}" get nodes}, MU::SUMMARY
467
+ MU.log %Q{How to interact with your GKE cluster\nkubectl --kubeconfig "#{kube_conf}" get events --all-namespaces\nkubectl --kubeconfig "#{kube_conf}" get all\nkubectl --kubeconfig "#{kube_conf}" create -f some_k8s_deploy.yml\nkubectl --kubeconfig "#{kube_conf}" get nodes}, MU::SUMMARY
468
468
  end
469
469
 
470
470
 
@@ -1059,6 +1059,14 @@ module MU
1059
1059
  }
1060
1060
  end
1061
1061
 
1062
+ if cluster['dependencies']
1063
+ cluster['dependencies'].each { |dep|
1064
+ if dep['type'] == "vpc"
1065
+ dep['phase'] = "groom"
1066
+ end
1067
+ }
1068
+ end
1069
+
1062
1070
  if (cluster['pod_ip_block_name'] or cluster['services_ip_block_name']) and
1063
1071
  cluster['custom_subnet']
1064
1072
  MU.log "GKE cluster #{cluster['name']} cannot specify pod_ip_block_name or services_ip_block_name when using a custom subnet", MU::ERR
@@ -423,6 +423,12 @@ end
423
423
 
424
424
  if acl['vpc']
425
425
  acl['vpc']['project'] ||= acl['project']
426
+ acl['vpc'] = MU::Cloud::Google::VPC.pickVPC(
427
+ acl['vpc'],
428
+ acl,
429
+ "firewall_rule",
430
+ config
431
+ )
426
432
  end
427
433
 
428
434
  acl['rules'] ||= []
@@ -491,12 +491,10 @@ module MU
491
491
  MU::Cloud::Google.admin_directory(credentials: credentials).delete_role(customer, id)
492
492
  end
493
493
  end
494
- elsif id.match(/^projects\//)
494
+ elsif id.match(/^projects\/.*?\/roles\//)
495
495
  begin
496
496
  resp = MU::Cloud::Google.iam(credentials: credentials).get_project_role(id)
497
497
  rescue ::Google::Apis::ClientError => e
498
- #MU.log e.message, MU::ERR, details: id
499
- #next
500
498
  next if e.message.match(/notFound/)
501
499
  raise e
502
500
  end
@@ -242,6 +242,8 @@ next if !create
242
242
  subnet_cfg = config['vpc']
243
243
  if config['vpc']['subnets'] and
244
244
  !subnet_cfg['subnet_name'] and !subnet_cfg['subnet_id']
245
+ # XXX if illegal subnets somehow creep in here, we'll need to be
246
+ # picky by region or somesuch
245
247
  subnet_cfg = config['vpc']['subnets'].sample
246
248
 
247
249
  end
@@ -249,6 +251,7 @@ next if !create
249
251
  if subnet.nil?
250
252
  raise MuError, "Couldn't find subnet details for #{subnet_cfg['subnet_name'] || subnet_cfg['subnet_id']} while configuring Server #{config['name']} (VPC: #{vpc.mu_name})"
251
253
  end
254
+
252
255
  base_iface_obj = {
253
256
  :network => vpc.url,
254
257
  :subnetwork => subnet.url
@@ -268,11 +271,19 @@ next if !create
268
271
  def create
269
272
  @project_id = MU::Cloud::Google.projectLookup(@config['project'], @deploy).cloud_id
270
273
 
271
- sa = MU::Config::Ref.get(@config['service_account'])
274
+ sa = nil
275
+ retries = 0
276
+ begin
277
+ sa = MU::Config::Ref.get(@config['service_account'])
278
+ if !sa or !sa.kitten or !sa.kitten.cloud_desc
279
+ sleep 10
280
+ end
281
+ end while !sa or !sa.kitten or !sa.kitten.cloud_desc and retries < 5
272
282
 
273
283
  if !sa or !sa.kitten or !sa.kitten.cloud_desc
274
284
  raise MuError, "Failed to get service account cloud id from #{@config['service_account'].to_s}"
275
285
  end
286
+
276
287
 
277
288
  @service_acct = MU::Cloud::Google.compute(:ServiceAccount).new(
278
289
  email: sa.kitten.cloud_desc.email,
@@ -344,7 +355,7 @@ next if !create
344
355
 
345
356
  instanceobj = MU::Cloud::Google.compute(:Instance).new(desc)
346
357
 
347
- MU.log "Creating instance #{@mu_name}", MU::NOTICE, details: instanceobj
358
+ MU.log "Creating instance #{@mu_name} in #{@project_id} #{@config['availability_zone']}", details: instanceobj
348
359
 
349
360
  begin
350
361
  instance = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_instance(
@@ -409,8 +420,10 @@ next if !create
409
420
  return {
410
421
  "cloud" => "Google",
411
422
  "size" => "g1-small",
412
- "run_list" => [ "mu-utility::nat" ],
423
+ "run_list" => [ "mu-nat" ],
424
+ "groomer" => "Ansible",
413
425
  "platform" => "centos7",
426
+ "src_dst_check" => false,
414
427
  "ssh_user" => "centos",
415
428
  "associate_public_ip" => true,
416
429
  "static_ip" => { "assign_ip" => true },
@@ -1339,7 +1352,10 @@ next if !create
1339
1352
  MU::Cloud.availableClouds.each { |cloud|
1340
1353
  next if cloud == "Google"
1341
1354
  cloudbase = Object.const_get("MU").const_get("Cloud").const_get(cloud)
1342
- foreign_types = (cloudbase.listInstanceTypes)[cloudbase.myRegion]
1355
+ foreign_types = (cloudbase.listInstanceTypes).values.first
1356
+ if foreign_types.size == 1
1357
+ foreign_types = foreign_types.values.first
1358
+ end
1343
1359
  if foreign_types and foreign_types.size > 0 and foreign_types.has_key?(size)
1344
1360
  vcpu = foreign_types[size]["vcpu"]
1345
1361
  mem = foreign_types[size]["memory"]
@@ -1378,6 +1394,7 @@ next if !create
1378
1394
  ok = true
1379
1395
 
1380
1396
  server['project'] ||= MU::Cloud::Google.defaultProject(server['credentials'])
1397
+
1381
1398
  size = validateInstanceType(server["size"], server["region"], project: server['project'], credentials: server['credentials'])
1382
1399
 
1383
1400
  if size.nil?
@@ -1458,6 +1475,10 @@ next if !create
1458
1475
  end
1459
1476
  end
1460
1477
 
1478
+ if server['vpc']
1479
+ server['vpc']['project'] ||= server['project']
1480
+ end
1481
+
1461
1482
  if server['image_id'].nil?
1462
1483
  img_id = MU::Cloud.getStockImage("Google", platform: server['platform'])
1463
1484
  if img_id
@@ -199,7 +199,7 @@ module MU
199
199
  end
200
200
  else
201
201
  @config['type'] ||= "service"
202
- return MU::Cloud::Google.iam(credentials: @config['credentials']).get_project_service_account(@cloud_id)
202
+ MU::Cloud::Google.iam(credentials: @config['credentials']).get_project_service_account(@cloud_id)
203
203
  end
204
204
 
205
205
  end
@@ -1,5 +1,5 @@
1
1
  #!/bin/sh
2
- # Copyright:: Copyright (c) 2014 eGlobalTech, Inc., all rights reserved
2
+ # Copyright:: Copyright (c) 2017 eGlobalTech, Inc., all rights reserved
3
3
  #
4
4
  # Licensed under the BSD-3 license (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -16,6 +16,13 @@
16
16
  updates_run=0
17
17
  need_reboot=0
18
18
  instance_id="`curl http://metadata.google.internal/computeMetadata/v1/instance/name`"
19
+
20
+ for f in /etc/rc.local /etc/rc.d/rc.local;do
21
+ if [ -f $f ];then
22
+ chmod 755 $f
23
+ fi
24
+ done
25
+
19
26
  if [ -f /etc/debian_version ];then
20
27
  if ! grep '^/bin/sh /var/lib/cloud/instance/user-data.txt$' /etc/rc.local > /dev/null;then
21
28
  echo "/bin/sh /var/lib/cloud/instance/user-data.txt" >> /etc/rc.local
@@ -65,9 +72,7 @@ elif [ -x /usr/bin/yum ];then
65
72
 
66
73
  sed -i 's/^Defaults.*requiretty$/Defaults !requiretty/' /etc/sudoers
67
74
 
68
- if [ $version == 7 ];then
69
- chmod 755 /etc/rc.d/rc.local
70
- fi
75
+ chmod 755 /etc/rc.d/rc.local
71
76
  if [ ! -f /usr/bin/curl ] ;then /usr/bin/yum -y install curl;fi
72
77
  # Ugh, rando EPEL mirror
73
78
  if [ ! -f /etc/yum.repos.d/epel.repo ];then
@@ -127,7 +132,6 @@ print Base64.urlsafe_encode64(key.public_encrypt(File.read("<%= $mu.muID %>-secr
127
132
  ' > encrypt_deploy_secret.rb
128
133
 
129
134
  deploykey="<%= $mu.deployKey %>"
130
- instance_id="`curl http://metadata.google.internal/computeMetadata/v1/instance/name`"
131
135
 
132
136
  # Make double-sure sshd is actually up
133
137
  service sshd restart
@@ -147,7 +147,7 @@ module MU
147
147
  # Called automatically by {MU::Deploy#createResources}
148
148
  def groom
149
149
 
150
- rtb = @config['route_tables'].first
150
+ rtb = @config['route_tables'].first # there's only ever one
151
151
 
152
152
  rtb['routes'].each { |route|
153
153
  # If we had a sibling server being spun up as a NAT, rig up the
@@ -236,7 +236,7 @@ end
236
236
  resp = {}
237
237
  if args[:cloud_id] and args[:project]
238
238
  begin
239
- vpc = MU::Cloud::Google.compute(credentials: args[:credentials]).get_network(
239
+ vpc = MU::Cloud::Google.compute(credentials: args[:credentials]).get_network(
240
240
  args[:project],
241
241
  args[:cloud_id].to_s.sub(/^.*?\/([^\/]+)$/, '\1')
242
242
  )
@@ -255,7 +255,7 @@ end
255
255
 
256
256
  if vpcs and vpcs.items
257
257
  vpcs.items.each { |v|
258
- resp[vpc.name] = v
258
+ resp[v.name] = v
259
259
  }
260
260
  end
261
261
  end
@@ -405,36 +405,48 @@ end
405
405
  dummy_ok: true,
406
406
  calling_deploy: @deploy
407
407
  )
408
- # XXX wat
408
+
409
409
  return nil if found.nil? || found.empty?
410
- if found.size > 1
410
+
411
+ if found.size == 1
412
+ return found.first
413
+ elsif found.size > 1
411
414
  found.each { |nat|
415
+ next if !nat.cloud_desc
412
416
  # Try some cloud-specific criteria
413
- cloud_desc = nat.cloud_desc
414
- if !nat_host_ip.nil? and
415
- # XXX this is AWS code, is wrong here
416
- (cloud_desc.private_ip_address == nat_host_ip or cloud_desc.public_ip_address == nat_host_ip)
417
- return nat
418
- elsif cloud_desc.vpc_id == @cloud_id
419
- # XXX Strictly speaking we could have different NATs in
420
- # different subnets, so this can be wrong in corner cases.
421
- return nat
422
- end
417
+ nat.cloud_desc.network_interfaces.each { |iface|
418
+ if !nat_ip.nil?
419
+ return nat if iface.network_ip == nat_ip
420
+ if iface.access_configs
421
+ iface.access_configs.each { |public_iface|
422
+ return if public_iface.nat_ip == nat_ip
423
+ }
424
+ end
425
+ end
426
+ if iface.network == @url
427
+ # XXX Strictly speaking we could have different NATs in
428
+ # different subnets, so this can be wrong in corner cases.
429
+ return nat
430
+ end
431
+ }
423
432
  }
424
- elsif found.size == 1
425
- return found.first
426
433
  end
434
+
427
435
  return nil
428
436
  end
429
437
 
430
438
  # Check for a subnet in this VPC matching one or more of the specified
431
439
  # criteria, and return it if found.
432
- def getSubnet(cloud_id: nil, name: nil, tag_key: nil, tag_value: nil, ip_block: nil)
440
+ def getSubnet(cloud_id: nil, name: nil, tag_key: nil, tag_value: nil, ip_block: nil, region: nil)
433
441
  if !cloud_id.nil? and cloud_id.match(/^https:\/\//)
442
+ cloud_id.match(/\/regions\/([^\/]+)\/subnetworks\/([^\/]+)$/)
443
+ region = Regexp.last_match[1]
444
+ cloud_id = Regexp.last_match[2]
434
445
  cloud_id.gsub!(/.*?\//, "")
435
446
  end
436
- MU.log "getSubnet(cloud_id: #{cloud_id}, name: #{name}, tag_key: #{tag_key}, tag_value: #{tag_value}, ip_block: #{ip_block})", MU::DEBUG, details: caller[0]
447
+ MU.log "getSubnet(cloud_id: #{cloud_id}, name: #{name}, tag_key: #{tag_key}, tag_value: #{tag_value}, ip_block: #{ip_block}, region: #{region})", MU::DEBUG, details: caller[0]
437
448
  subnets.each { |subnet|
449
+ next if region and subnet.az != region
438
450
  if !cloud_id.nil? and !subnet.cloud_id.nil? and subnet.cloud_id.to_s == cloud_id.to_s
439
451
  return subnet
440
452
  elsif !name.nil? and !subnet.name.nil? and
@@ -694,6 +706,68 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
694
706
  [toplevel_required, schema]
695
707
  end
696
708
 
709
+ # If the VPC a config block was set to one that's been "split," try to
710
+ # figure out which of the new VPCs we really want to be in. For use by
711
+ # resource types that don't go in subnets, but do tie to VPCs.
712
+ # @param vpc_block [Hash]
713
+ # @param configurator [MU::Config]
714
+ # @return [Hash]
715
+ def self.pickVPC(vpc_block, my_config, my_type, configurator)
716
+ _shortclass, cfg_name, cfg_plural, _classname = MU::Cloud.getResourceNames(my_type)
717
+ return if vpc_block.nil?
718
+ vpc_block['name'] ||= vpc_block['vpc_name']
719
+ return if !vpc_block['name']
720
+
721
+ vpcs = configurator.haveLitterMate?(
722
+ nil,
723
+ "vpcs",
724
+ has_multiple: true
725
+ )
726
+ # drop all virtual vpcs that aren't real anymore
727
+ vpcs.reject! { |v| v['virtual_name'] == v['name'] }
728
+ # drop the ones that have nothing to do with us
729
+ vpcs.reject! { |v| v['virtual_name'] != vpc_block['name'] }
730
+
731
+ return vpc_block if vpcs.size == 0
732
+
733
+ # see if one of this thing's siblings declared a subnet_pref we can
734
+ # use to guess which one we should marry ourselves to
735
+ configurator.kittens.each_pair { |type, siblings|
736
+ siblings.each { |sibling|
737
+ next if !sibling['dependencies']
738
+ sibling['dependencies'].each { |dep|
739
+ if [cfg_name, cfg_plural].include?(dep['type']) and
740
+ dep['name'] == my_config['name']
741
+ vpcs.each { |v|
742
+ if sibling['vpc']['name'] == v['name']
743
+ vpc_block['name'] = v['name']
744
+ return vpc_block
745
+ end
746
+ }
747
+ if sibling['vpc']['subnet_pref']
748
+ vpcs.each { |v|
749
+ gateways = v['route_tables'].map { |rtb|
750
+ rtb['routes'].map { |r| r["gateway"] }
751
+ }.flatten.uniq
752
+ if ["public", "all_public"].include?(sibling['vpc']['subnet_pref']) and
753
+ gateways.include?("#INTERNET")
754
+ vpc_block['name'] = v['name']
755
+ return vpc_block
756
+ elsif ["private", "all_private"].include?(sibling['vpc']['subnet_pref']) and
757
+ !gateways.include?("#INTERNET")
758
+ vpc_block['name'] = v['name']
759
+ return vpc_block
760
+ end
761
+ }
762
+
763
+ end
764
+ end
765
+ }
766
+ }
767
+ }
768
+
769
+ vpc_block
770
+ end
697
771
 
698
772
  # Cloud-specific pre-processing of {MU::Config::BasketofKittens::vpcs}, bare and unvalidated.
699
773
  # @param vpc [Hash]: The resource to process and validate
@@ -720,7 +794,9 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
720
794
  vpc['route_tables'].each { |t|
721
795
  is_public = false
722
796
  t['routes'].each { |r|
723
- if !vpc["virtual_name"] and !vpc["create_nat_gateway"] and
797
+ if !vpc["virtual_name"] and
798
+ !vpc["create_nat_gateway"] and
799
+ !vpc['bastion'] and
724
800
  r["gateway"] == "#NAT"
725
801
  r["gateway"] = "#DENY"
726
802
  end
@@ -781,6 +857,11 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
781
857
  next if ["name", "route_tables", "subnets", "ip_block"].include?(key)
782
858
  newvpc[key] = val
783
859
  }
860
+ if vpc["bastion"] and
861
+ !tbl["routes"].map { |r| r["gateway"] }.include?("#INTERNET")
862
+ newvpc["bastion"] = vpc["bastion"]
863
+ vpc.delete("bastion")
864
+ end
784
865
  newvpc['peers'] ||= []
785
866
  # Add the peer connections we're generating, in addition
786
867
  peernames.each { |peer|
@@ -809,7 +890,7 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
809
890
  else
810
891
  ok = false if !genStandardSubnetACLs(vpc['parent_block'] || vpc['ip_block'], vpc['name'], configurator, vpc["project"], credentials: vpc['credentials'])
811
892
  end
812
- if has_nat and !has_deny
893
+ if has_nat and !has_deny and !vpc['bastion']
813
894
  vpc['route_tables'].first["routes"] << {
814
895
  "gateway"=>"#DENY",
815
896
  "destination_network"=>"0.0.0.0/0"