cloud-mu 3.0.0beta → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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"