cloud-mu 3.1.5 → 3.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +5 -1
  3. data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
  4. data/ansible/roles/mu-windows/files/config.xml +76 -0
  5. data/ansible/roles/mu-windows/tasks/main.yml +16 -0
  6. data/bin/mu-adopt +2 -1
  7. data/bin/mu-configure +16 -0
  8. data/bin/mu-node-manage +15 -16
  9. data/cloud-mu.gemspec +2 -2
  10. data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
  11. data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
  12. data/cookbooks/mu-tools/recipes/eks.rb +2 -2
  13. data/cookbooks/mu-tools/recipes/windows-client.rb +25 -22
  14. data/extras/clean-stock-amis +25 -19
  15. data/extras/image-generators/AWS/win2k12.yaml +2 -0
  16. data/extras/image-generators/AWS/win2k16.yaml +2 -0
  17. data/extras/image-generators/AWS/win2k19.yaml +2 -0
  18. data/modules/mommacat.ru +1 -1
  19. data/modules/mu.rb +6 -5
  20. data/modules/mu/adoption.rb +19 -4
  21. data/modules/mu/cleanup.rb +181 -293
  22. data/modules/mu/cloud.rb +58 -17
  23. data/modules/mu/clouds/aws.rb +36 -1
  24. data/modules/mu/clouds/aws/container_cluster.rb +30 -21
  25. data/modules/mu/clouds/aws/role.rb +1 -1
  26. data/modules/mu/clouds/aws/vpc.rb +5 -1
  27. data/modules/mu/clouds/azure.rb +10 -0
  28. data/modules/mu/clouds/cloudformation.rb +10 -0
  29. data/modules/mu/clouds/google.rb +18 -4
  30. data/modules/mu/clouds/google/bucket.rb +2 -2
  31. data/modules/mu/clouds/google/container_cluster.rb +10 -7
  32. data/modules/mu/clouds/google/database.rb +3 -3
  33. data/modules/mu/clouds/google/firewall_rule.rb +3 -3
  34. data/modules/mu/clouds/google/function.rb +3 -3
  35. data/modules/mu/clouds/google/loadbalancer.rb +4 -4
  36. data/modules/mu/clouds/google/role.rb +18 -9
  37. data/modules/mu/clouds/google/server.rb +16 -14
  38. data/modules/mu/clouds/google/server_pool.rb +4 -4
  39. data/modules/mu/clouds/google/user.rb +2 -2
  40. data/modules/mu/clouds/google/vpc.rb +9 -13
  41. data/modules/mu/config.rb +1 -1
  42. data/modules/mu/config/container_cluster.rb +5 -0
  43. data/modules/mu/config/doc_helpers.rb +1 -1
  44. data/modules/mu/config/ref.rb +12 -6
  45. data/modules/mu/config/schema_helpers.rb +8 -3
  46. data/modules/mu/config/server.rb +7 -0
  47. data/modules/mu/config/tail.rb +1 -0
  48. data/modules/mu/config/vpc.rb +15 -7
  49. data/modules/mu/config/vpc.yml +0 -1
  50. data/modules/mu/defaults/AWS.yaml +48 -48
  51. data/modules/mu/deploy.rb +1 -1
  52. data/modules/mu/groomer.rb +1 -1
  53. data/modules/mu/groomers/ansible.rb +69 -4
  54. data/modules/mu/groomers/chef.rb +48 -4
  55. data/modules/mu/master.rb +75 -3
  56. data/modules/mu/mommacat.rb +104 -855
  57. data/modules/mu/mommacat/naming.rb +28 -0
  58. data/modules/mu/mommacat/search.rb +463 -0
  59. data/modules/mu/mommacat/storage.rb +185 -183
  60. data/modules/tests/super_simple_bok.yml +1 -3
  61. metadata +8 -5
@@ -474,7 +474,6 @@ module MU
474
474
  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
475
475
  end
476
476
 
477
-
478
477
  # Locate an existing ContainerCluster or ContainerClusters and return an array containing matching GCP resource descriptors for those that match.
479
478
  # @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching ContainerClusters
480
479
  def self.find(**args)
@@ -747,15 +746,15 @@ module MU
747
746
  # @return [void]
748
747
  def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
749
748
 
750
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
751
- return if !MU::Cloud::Google::Habitat.isLive?(flags["project"], credentials)
749
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
750
+ return if !MU::Cloud::Google::Habitat.isLive?(flags["habitat"], credentials)
752
751
  clusters = []
753
752
 
754
753
  # Make sure we catch regional *and* zone clusters
755
- found = MU::Cloud::Google.container(credentials: credentials).list_project_location_clusters("projects/#{flags['project']}/locations/#{region}")
754
+ found = MU::Cloud::Google.container(credentials: credentials).list_project_location_clusters("projects/#{flags['habitat']}/locations/#{region}")
756
755
  clusters.concat(found.clusters) if found and found.clusters
757
756
  MU::Cloud::Google.listAZs(region).each { |az|
758
- found = MU::Cloud::Google.container(credentials: credentials).list_project_location_clusters("projects/#{flags['project']}/locations/#{az}")
757
+ found = MU::Cloud::Google.container(credentials: credentials).list_project_location_clusters("projects/#{flags['habitat']}/locations/#{az}")
759
758
  clusters.concat(found.clusters) if found and found.clusters
760
759
  }
761
760
 
@@ -1097,7 +1096,7 @@ module MU
1097
1096
  }
1098
1097
  if !match
1099
1098
  MU.log "No version matching #{cluster['kubernetes']['version']} available, will try floating minor revision", MU::WARN
1100
- cluster['kubernetes']['version'].sub!(/^(\d+\.\d+\.).*/i, '\1')
1099
+ cluster['kubernetes']['version'].sub!(/^(\d+\.\d+)\..*/i, '\1')
1101
1100
  master_versions.each { |v|
1102
1101
  if v.match(/^#{Regexp.quote(cluster['kubernetes']['version'])}/)
1103
1102
  match = true
@@ -1145,6 +1144,10 @@ module MU
1145
1144
  cluster['instance_type'] = MU::Cloud::Google::Server.validateInstanceType(cluster["instance_type"], cluster["region"], project: cluster['project'], credentials: cluster['credentials'])
1146
1145
  ok = false if cluster['instance_type'].nil?
1147
1146
 
1147
+ if !MU::Master.kubectl
1148
+ MU.log "Since I can't find a kubectl executable, you will have to handle all service account, user, and role bindings manually!", MU::WARN
1149
+ end
1150
+
1148
1151
  ok
1149
1152
  end
1150
1153
 
@@ -1236,7 +1239,7 @@ module MU
1236
1239
  # Take this opportunity to ensure that the 'client' service account
1237
1240
  # used by certificate authentication exists and has appropriate
1238
1241
  # privilege
1239
- if @username and @password
1242
+ if @username and @password and MU::Master.kubectl
1240
1243
  File.open(client_binding, "w"){ |k|
1241
1244
  k.puts <<-EOF
1242
1245
  kind: ClusterRoleBinding
@@ -108,13 +108,13 @@ module MU
108
108
  # @param region [String]: The cloud provider region in which to operate
109
109
  # @return [void]
110
110
  def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
111
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
111
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
112
112
 
113
- # instances = MU::Cloud::Google.sql(credentials: credentials).list_instances(flags['project'], filter: %Q{userLabels.mu-id:"#{MU.deploy_id.downcase}"})
113
+ # instances = MU::Cloud::Google.sql(credentials: credentials).list_instances(flags['habitat'], filter: %Q{userLabels.mu-id:"#{MU.deploy_id.downcase}"})
114
114
  # if instances and instances.items
115
115
  # instances.items.each { |instance|
116
116
  # MU.log "Deleting Cloud SQL instance #{instance.name}"
117
- # MU::Cloud::Google.sql(credentials: credentials).delete_instance(flags['project'], instance.name) if !noop
117
+ # MU::Cloud::Google.sql(credentials: credentials).delete_instance(flags['habitat'], instance.name) if !noop
118
118
  # }
119
119
  # end
120
120
  end
@@ -208,8 +208,8 @@ end
208
208
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
209
209
  # @return [void]
210
210
  def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
211
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
212
- return if !MU::Cloud::Google::Habitat.isLive?(flags["project"], credentials)
211
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
212
+ return if !MU::Cloud::Google::Habitat.isLive?(flags["habitat"], credentials)
213
213
  filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
214
214
  if !ignoremaster and MU.mu_public_ip
215
215
  filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
@@ -218,7 +218,7 @@ end
218
218
 
219
219
  MU::Cloud::Google.compute(credentials: credentials).delete(
220
220
  "firewall",
221
- flags["project"],
221
+ flags["habitat"],
222
222
  nil,
223
223
  noop
224
224
  )
@@ -234,10 +234,10 @@ module example.com/cloudfunction
234
234
  # @param region [String]: The cloud provider region
235
235
  # @return [void]
236
236
  def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
237
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
238
- return if !MU::Cloud::Google::Habitat.isLive?(flags["project"], credentials)
237
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
238
+ return if !MU::Cloud::Google::Habitat.isLive?(flags["habitat"], credentials)
239
239
  # Make sure we catch regional *and* zone functions
240
- found = MU::Cloud::Google::Function.find(credentials: credentials, region: region, project: flags["project"])
240
+ found = MU::Cloud::Google::Function.find(credentials: credentials, region: region, project: flags["habitat"])
241
241
  found.each_pair { |cloud_id, desc|
242
242
  if (desc.description and desc.description == MU.deploy_id) or
243
243
  (desc.labels and desc.labels["mu-id"] == MU.deploy_id.downcase and (ignoremaster or desc.labels["mu-master-ip"] == MU.mu_public_ip.gsub(/\./, "_"))) or
@@ -147,8 +147,8 @@ module MU
147
147
  # @param region [String]: The cloud provider region
148
148
  # @return [void]
149
149
  def self.cleanup(noop: false, ignoremaster: false, region: nil, credentials: nil, flags: {})
150
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
151
- return if !MU::Cloud::Google::Habitat.isLive?(flags["project"], credentials)
150
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
151
+ return if !MU::Cloud::Google::Habitat.isLive?(flags["habitat"], credentials)
152
152
  filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
153
153
  if !ignoremaster and MU.mu_public_ip
154
154
  filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
@@ -159,7 +159,7 @@ module MU
159
159
  ["forwarding_rule", "region_backend_service"].each { |type|
160
160
  MU::Cloud::Google.compute(credentials: credentials).delete(
161
161
  type,
162
- flags["project"],
162
+ flags["habitat"],
163
163
  region,
164
164
  noop
165
165
  )
@@ -170,7 +170,7 @@ module MU
170
170
  ["global_forwarding_rule", "target_http_proxy", "target_https_proxy", "url_map", "backend_service", "health_check", "http_health_check", "https_health_check"].each { |type|
171
171
  MU::Cloud::Google.compute(credentials: credentials).delete(
172
172
  type,
173
- flags["project"],
173
+ flags["habitat"],
174
174
  nil,
175
175
  noop
176
176
  )
@@ -731,25 +731,34 @@ module MU
731
731
  bindings[scopetype].each_pair { |scope_id, entity_types|
732
732
  # If we've been given a habitat filter, skip over bindings
733
733
  # that don't match it.
734
- if scopetype == "projects" and args[:habitats] and
735
- !args[:habitats].empty? and
736
- !args[:habitats].include?(scope_id)
737
- next
734
+ if scopetype == "projects"
735
+ if (args[:habitats] and !args[:habitats].empty? and
736
+ !args[:habitats].include?(scope_id)) or
737
+ !MU::Cloud::Google.listHabitats(@credentials).include?(scope_id)
738
+ next
739
+ end
738
740
  end
739
741
 
740
742
  entity_types.each_pair { |entity_type, entities|
741
743
  mu_entitytype = (entity_type == "serviceAccount" ? "user" : entity_type)+"s"
742
744
  entities.each { |entity|
745
+ foreign = if entity_type == "serviceAccount" and entity.match(/@(.*?)\.iam\.gserviceaccount\.com/)
746
+ !MU::Cloud::Google.listHabitats(@credentials).include?(Regexp.last_match[1])
747
+ end
743
748
  entity_ref = if entity_type == "organizations"
744
749
  { "id" => ((org == my_org.name and @config['credentials']) ? @config['credentials'] : org) }
745
750
  elsif entity_type == "domain"
746
751
  { "id" => entity }
747
752
  else
748
- MU::Config::Ref.get(
749
- id: entity,
750
- cloud: "Google",
751
- type: mu_entitytype
752
- )
753
+ if foreign
754
+ { "id" => entity }
755
+ else
756
+ MU::Config::Ref.get(
757
+ id: entity,
758
+ cloud: "Google",
759
+ type: mu_entitytype
760
+ )
761
+ end
753
762
  end
754
763
  refmap ||= {}
755
764
  refmap[entity_ref] ||= {}
@@ -1016,7 +1016,6 @@ next if !create
1016
1016
  item: @config['windows_auth_vault']['item'],
1017
1017
  field: @config["windows_auth_vault"]["password_field"]
1018
1018
  )
1019
- MU.log "RETURNINATING FROM CACHE", MU::WARN, details: win_admin_password
1020
1019
  return win_admin_password if win_admin_password
1021
1020
  rescue MU::Groomer::MuNoSuchSecret, MU::Groomer::RunError
1022
1021
  end
@@ -1276,8 +1275,8 @@ MU.log "RETURNINATING FROM CACHE", MU::WARN, details: win_admin_password
1276
1275
  # @param region [String]: The cloud provider region
1277
1276
  # @return [void]
1278
1277
  def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
1279
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
1280
- return if !MU::Cloud::Google::Habitat.isLive?(flags["project"], credentials)
1278
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
1279
+ return if !MU::Cloud::Google::Habitat.isLive?(flags["habitat"], credentials)
1281
1280
 
1282
1281
  # XXX make damn sure MU.deploy_id is set
1283
1282
  filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
@@ -1288,13 +1287,12 @@ MU.log "RETURNINATING FROM CACHE", MU::WARN, details: win_admin_password
1288
1287
  MU::Cloud::Google.listAZs(region).each { |az|
1289
1288
  disks = []
1290
1289
  resp = MU::Cloud::Google.compute(credentials: credentials).list_instances(
1291
- flags["project"],
1290
+ flags["habitat"],
1292
1291
  az,
1293
1292
  filter: filter
1294
1293
  )
1295
1294
  if !resp.items.nil? and resp.items.size > 0
1296
1295
  resp.items.each { |instance|
1297
- saname = instance.tags.items.first.gsub(/[^a-z]/, "") # XXX this nonsense again
1298
1296
  MU.log "Terminating instance #{instance.name}"
1299
1297
  if !instance.disks.nil? and instance.disks.size > 0
1300
1298
  instance.disks.each { |disk|
@@ -1302,17 +1300,21 @@ MU.log "RETURNINATING FROM CACHE", MU::WARN, details: win_admin_password
1302
1300
  }
1303
1301
  end
1304
1302
  MU::Cloud::Google.compute(credentials: credentials).delete_instance(
1305
- flags["project"],
1303
+ flags["habitat"],
1306
1304
  az,
1307
1305
  instance.name
1308
1306
  ) if !noop
1309
- MU.log "Removing service account #{saname}"
1310
- begin
1311
- MU::Cloud::Google.iam(credentials: credentials).delete_project_service_account(
1312
- "projects/#{flags["project"]}/serviceAccounts/#{saname}@#{flags["project"]}.iam.gserviceaccount.com"
1313
- ) if !noop
1314
- rescue ::Google::Apis::ClientError => e
1315
- raise e if !e.message.match(/^notFound: /)
1307
+ if instance.service_accounts
1308
+ instance.service_accounts.each { |sa|
1309
+ MU.log "Removing service account #{sa.email}"
1310
+ begin
1311
+ MU::Cloud::Google.iam(credentials: credentials).delete_project_service_account(
1312
+ "projects/#{flags["habitat"]}/serviceAccounts/#{sa.email}"
1313
+ ) if !noop
1314
+ rescue ::Google::Apis::ClientError => e
1315
+ raise e if !e.message.match(/^notFound: /)
1316
+ end
1317
+ }
1316
1318
  end
1317
1319
  # XXX wait-loop on pending?
1318
1320
  # pp deletia
@@ -1325,7 +1327,7 @@ MU.log "RETURNINATING FROM CACHE", MU::WARN, details: win_admin_password
1325
1327
  # XXX honor snapshotting
1326
1328
  MU::Cloud::Google.compute(credentials: credentials).delete(
1327
1329
  "disk",
1328
- flags["project"],
1330
+ flags["habitat"],
1329
1331
  az,
1330
1332
  noop
1331
1333
  ) if !noop
@@ -432,8 +432,8 @@ end
432
432
  # @param region [String]: The cloud provider region
433
433
  # @return [void]
434
434
  def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
435
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
436
- return if !MU::Cloud::Google::Habitat.isLive?(flags["project"], credentials)
435
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
436
+ return if !MU::Cloud::Google::Habitat.isLive?(flags["habitat"], credentials)
437
437
  filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
438
438
  if !ignoremaster and MU.mu_public_ip
439
439
  filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
@@ -444,7 +444,7 @@ end
444
444
  ["region_autoscaler", "region_instance_group_manager"].each { |type|
445
445
  MU::Cloud::Google.compute(credentials: credentials).delete(
446
446
  type,
447
- flags["project"],
447
+ flags["habitat"],
448
448
  region,
449
449
  noop
450
450
  )
@@ -452,7 +452,7 @@ end
452
452
  else
453
453
  MU::Cloud::Google.compute(credentials: credentials).delete(
454
454
  "instance_template",
455
- flags["project"],
455
+ flags["habitat"],
456
456
  noop
457
457
  )
458
458
  end
@@ -281,9 +281,9 @@ module MU
281
281
  end
282
282
  end
283
283
 
284
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
284
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
285
285
  resp = MU::Cloud::Google.iam(credentials: credentials).list_project_service_accounts(
286
- "projects/"+flags["project"]
286
+ "projects/"+flags["habitat"]
287
287
  )
288
288
 
289
289
  if resp and resp.accounts and MU.deploy_id
@@ -113,7 +113,7 @@ module MU
113
113
  # Describe this VPC
114
114
  # @return [Hash]
115
115
  def notify
116
- base = MU.structToHash(cloud_desc)
116
+ base = MU.structToHash(cloud_desc, stringify_keys: true)
117
117
  base["cloud_id"] = @cloud_id
118
118
  base["project_id"] = habitat_id
119
119
  base.merge!(@config.to_h)
@@ -301,14 +301,10 @@ end
301
301
  @deploy.deployment["vpcs"][@config['name']]["subnets"] and
302
302
  @deploy.deployment["vpcs"][@config['name']]["subnets"].size > 0
303
303
  @deploy.deployment["vpcs"][@config['name']]["subnets"].each { |desc|
304
- subnet = {}
305
- subnet["ip_block"] = desc['ip_block']
306
- subnet["name"] = desc["name"]
304
+ subnet = desc.clone
307
305
  subnet['mu_name'] = @config['scrub_mu_isms'] ? @cloud_id+subnet['name'].downcase : MU::Cloud::Google.nameStr(@deploy.getResourceName(subnet['name'], max_length: 61))
308
- subnet["cloud_id"] = desc['cloud_id']
309
306
  subnet["cloud_id"] ||= desc['self_link'].gsub(/.*?\/([^\/]+)$/, '\1')
310
307
  subnet["cloud_id"] ||= subnet['mu_name']
311
- subnet['az'] = desc["az"]
312
308
  subnet['az'] ||= desc["region"].gsub(/.*?\/([^\/]+)$/, '\1')
313
309
  @subnets << MU::Cloud::Google::VPC::Subnet.new(self, subnet, precache_description: false)
314
310
  }
@@ -542,15 +538,15 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
542
538
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
543
539
  # @return [void]
544
540
  def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
545
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
546
- return if !MU::Cloud::Google::Habitat.isLive?(flags["project"], credentials)
541
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
542
+ return if !MU::Cloud::Google::Habitat.isLive?(flags["habitat"], credentials)
547
543
  filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
548
544
  if !ignoremaster and MU.mu_public_ip
549
545
  filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
550
546
  end
551
547
  MU.log "Placeholder: Google VPC artifacts do not support labels, so ignoremaster cleanup flag has no effect", MU::DEBUG, details: filter
552
548
 
553
- purge_subnets(noop, project: flags['project'], credentials: credentials)
549
+ purge_subnets(noop, project: flags['habitat'], credentials: credentials)
554
550
  ["route", "network"].each { |type|
555
551
  # XXX tagged routes aren't showing up in list, and the networks that own them
556
552
  # fail to delete silently
@@ -559,7 +555,7 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
559
555
  begin
560
556
  MU::Cloud::Google.compute(credentials: credentials).delete(
561
557
  type,
562
- flags["project"],
558
+ flags["habitat"],
563
559
  nil,
564
560
  noop
565
561
  )
@@ -569,13 +565,13 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
569
565
  MU.log e.message, MU::WARN
570
566
  if e.message.match(/Failed to delete network (.+)/)
571
567
  network_name = Regexp.last_match[1]
572
- fwrules = MU::Cloud::Google::FirewallRule.find(project: flags['project'], credentials: credentials)
568
+ fwrules = MU::Cloud::Google::FirewallRule.find(project: flags['habitat'], credentials: credentials)
573
569
  fwrules.reject! { |_name, desc|
574
570
  !desc.network.match(/.*?\/#{Regexp.quote(network_name)}$/)
575
571
  }
576
572
  fwrules.keys.each { |name|
577
573
  MU.log "Attempting to delete firewall rule #{name} so that VPC #{network_name} can be removed", MU::NOTICE
578
- MU::Cloud::Google.compute(credentials: credentials).delete_firewall(flags['project'], name)
574
+ MU::Cloud::Google.compute(credentials: credentials).delete_firewall(flags['habitat'], name)
579
575
  }
580
576
  end
581
577
  end
@@ -1120,7 +1116,7 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
1120
1116
  # Describe this VPC Subnet
1121
1117
  # @return [Hash]
1122
1118
  def notify
1123
- MU.structToHash(cloud_desc)
1119
+ MU.structToHash(cloud_desc, stringify_keys: true)
1124
1120
  end
1125
1121
 
1126
1122
  # Return the +self_link+ to this subnet
@@ -77,7 +77,7 @@ module MU
77
77
  if config.is_a?(Hash)
78
78
  newhash = {}
79
79
  config.each_pair { |key, val|
80
- next if remove_runtime_keys and key.match(/^#MU_/)
80
+ next if remove_runtime_keys and (key.nil? or key.match(/^#MU_/))
81
81
  next if val.is_a?(Array) and val.empty?
82
82
  newhash[key] = self.manxify(val, remove_runtime_keys: remove_runtime_keys)
83
83
  }
@@ -104,6 +104,11 @@ module MU
104
104
  cluster["min_size"] ||= [cluster["instance_count"], cluster["min_size"]].reject { |c| c.nil? }.min
105
105
  end
106
106
 
107
+ if cluster['kubernetes_resources'] and !MU::Master.kubectl
108
+ MU.log "Cannot apply kubernetes resources without a working kubectl executable", MU::ERR
109
+ ok = false
110
+ end
111
+
107
112
  ok
108
113
  end
109
114
 
@@ -239,7 +239,7 @@ $CONFIGURABLES
239
239
 
240
240
  if class_hierarchy.size == 1
241
241
 
242
- _shortclass, cfg_name, cfg_plural, _classname = MU::Cloud.getResourceNames(name)
242
+ _shortclass, cfg_name, cfg_plural, _classname = MU::Cloud.getResourceNames(name, false)
243
243
  if cfg_name
244
244
  example_path = MU.myRoot+"/modules/mu/config/"+cfg_name+".yml"
245
245
  if File.exist?(example_path)
@@ -255,7 +255,7 @@ module MU
255
255
  if @obj
256
256
  @deploy_id ||= @obj.deploy_id
257
257
  @id ||= @obj.cloud_id
258
- @name ||= @obj.config['name']
258
+ @name ||= @obj.config['name'] if @obj.config
259
259
  return @obj
260
260
  end
261
261
 
@@ -266,6 +266,7 @@ module MU
266
266
  @mommacat ||= mommacat
267
267
  @obj.intoDeploy(@mommacat) # make real sure these are set
268
268
  @deploy_id ||= mommacat.deploy_id
269
+
269
270
  if !@name
270
271
  if @obj.config and @obj.config['name']
271
272
  @name = @obj.config['name']
@@ -283,6 +284,7 @@ end
283
284
  end
284
285
 
285
286
  if !@obj and !(@cloud == "Google" and @id and @type == "users" and MU::Cloud::Google::User.cannedServiceAcctName?(@id)) and !shallow
287
+ try_deploy_id = @deploy_id
286
288
 
287
289
  begin
288
290
  hab_arg = if @habitat.nil?
@@ -300,22 +302,26 @@ end
300
302
  @type,
301
303
  name: @name,
302
304
  cloud_id: @id,
303
- deploy_id: @deploy_id,
305
+ deploy_id: try_deploy_id,
304
306
  region: @region,
305
307
  habitats: hab_arg,
306
308
  credentials: @credentials,
307
309
  dummy_ok: (["habitats", "folders", "users", "groups", "vpcs"].include?(@type))
308
310
  )
309
311
  @obj ||= found.first if found
312
+ rescue MU::MommaCat::MultipleMatches => e
313
+ if try_deploy_id.nil? and MU.deploy_id
314
+ MU.log "Attempting to narrow down #{@cloud} #{@type} to #{MU.deploy_id}", MU::NOTICE
315
+ try_deploy_id = MU.deploy_id
316
+ retry
317
+ else
318
+ raise e
319
+ end
310
320
  rescue ThreadError => e
311
321
  # Sometimes MommaCat calls us in a potential deadlock situation;
312
322
  # don't be the cause of a fatal error if so, we don't need this
313
323
  # object that badly.
314
324
  raise e if !e.message.match(/recursive locking/)
315
- rescue SystemExit
316
- # XXX this is temporary, to cope with some debug stuff that's in findStray
317
- # for the nonce
318
- return
319
325
  end
320
326
  end
321
327