cloud-mu 3.1.3 → 3.3.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 (212) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +15 -3
  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 +21 -13
  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 +4 -4
  21. data/bin/mu-node-manage +15 -16
  22. data/bin/mu-run-tests +147 -37
  23. data/cloud-mu.gemspec +22 -20
  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 +3 -2
  27. data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
  28. data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
  29. data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
  30. data/cookbooks/mu-tools/recipes/eks.rb +2 -2
  31. data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
  32. data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
  33. data/cookbooks/mu-tools/recipes/windows-client.rb +163 -164
  34. data/cookbooks/mu-tools/resources/disk.rb +1 -1
  35. data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
  36. data/extras/clean-stock-amis +25 -19
  37. data/extras/generate-stock-images +1 -0
  38. data/extras/image-generators/AWS/win2k12.yaml +18 -13
  39. data/extras/image-generators/AWS/win2k16.yaml +18 -13
  40. data/extras/image-generators/AWS/win2k19.yaml +21 -0
  41. data/extras/image-generators/Google/centos6.yaml +1 -0
  42. data/extras/image-generators/Google/centos7.yaml +1 -1
  43. data/modules/mommacat.ru +6 -16
  44. data/modules/mu.rb +158 -111
  45. data/modules/mu/adoption.rb +404 -71
  46. data/modules/mu/cleanup.rb +221 -306
  47. data/modules/mu/cloud.rb +129 -1633
  48. data/modules/mu/cloud/database.rb +49 -0
  49. data/modules/mu/cloud/dnszone.rb +44 -0
  50. data/modules/mu/cloud/machine_images.rb +212 -0
  51. data/modules/mu/cloud/providers.rb +81 -0
  52. data/modules/mu/cloud/resource_base.rb +926 -0
  53. data/modules/mu/cloud/server.rb +40 -0
  54. data/modules/mu/cloud/server_pool.rb +1 -0
  55. data/modules/mu/cloud/ssh_sessions.rb +228 -0
  56. data/modules/mu/cloud/winrm_sessions.rb +237 -0
  57. data/modules/mu/cloud/wrappers.rb +169 -0
  58. data/modules/mu/config.rb +171 -1767
  59. data/modules/mu/config/alarm.rb +2 -6
  60. data/modules/mu/config/bucket.rb +32 -3
  61. data/modules/mu/config/cache_cluster.rb +2 -2
  62. data/modules/mu/config/cdn.rb +100 -0
  63. data/modules/mu/config/collection.rb +4 -4
  64. data/modules/mu/config/container_cluster.rb +9 -4
  65. data/modules/mu/config/database.rb +84 -105
  66. data/modules/mu/config/database.yml +1 -2
  67. data/modules/mu/config/dnszone.rb +10 -9
  68. data/modules/mu/config/doc_helpers.rb +516 -0
  69. data/modules/mu/config/endpoint.rb +5 -4
  70. data/modules/mu/config/firewall_rule.rb +103 -4
  71. data/modules/mu/config/folder.rb +4 -4
  72. data/modules/mu/config/function.rb +19 -10
  73. data/modules/mu/config/group.rb +4 -4
  74. data/modules/mu/config/habitat.rb +4 -4
  75. data/modules/mu/config/job.rb +89 -0
  76. data/modules/mu/config/loadbalancer.rb +60 -14
  77. data/modules/mu/config/log.rb +4 -4
  78. data/modules/mu/config/msg_queue.rb +4 -4
  79. data/modules/mu/config/nosqldb.rb +4 -4
  80. data/modules/mu/config/notifier.rb +10 -21
  81. data/modules/mu/config/ref.rb +411 -0
  82. data/modules/mu/config/role.rb +4 -4
  83. data/modules/mu/config/schema_helpers.rb +509 -0
  84. data/modules/mu/config/search_domain.rb +4 -4
  85. data/modules/mu/config/server.rb +98 -71
  86. data/modules/mu/config/server.yml +1 -0
  87. data/modules/mu/config/server_pool.rb +5 -9
  88. data/modules/mu/config/storage_pool.rb +1 -1
  89. data/modules/mu/config/tail.rb +200 -0
  90. data/modules/mu/config/user.rb +4 -4
  91. data/modules/mu/config/vpc.rb +71 -27
  92. data/modules/mu/config/vpc.yml +0 -1
  93. data/modules/mu/defaults/AWS.yaml +91 -68
  94. data/modules/mu/defaults/Azure.yaml +1 -0
  95. data/modules/mu/defaults/Google.yaml +3 -2
  96. data/modules/mu/deploy.rb +43 -26
  97. data/modules/mu/groomer.rb +17 -2
  98. data/modules/mu/groomers/ansible.rb +188 -41
  99. data/modules/mu/groomers/chef.rb +116 -55
  100. data/modules/mu/logger.rb +127 -148
  101. data/modules/mu/master.rb +410 -2
  102. data/modules/mu/master/chef.rb +3 -4
  103. data/modules/mu/master/ldap.rb +3 -3
  104. data/modules/mu/master/ssl.rb +12 -3
  105. data/modules/mu/mommacat.rb +218 -2612
  106. data/modules/mu/mommacat/daemon.rb +403 -0
  107. data/modules/mu/mommacat/naming.rb +473 -0
  108. data/modules/mu/mommacat/search.rb +495 -0
  109. data/modules/mu/mommacat/storage.rb +722 -0
  110. data/modules/mu/{clouds → providers}/README.md +1 -1
  111. data/modules/mu/{clouds → providers}/aws.rb +380 -122
  112. data/modules/mu/{clouds → providers}/aws/alarm.rb +7 -5
  113. data/modules/mu/{clouds → providers}/aws/bucket.rb +297 -59
  114. data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +37 -71
  115. data/modules/mu/providers/aws/cdn.rb +782 -0
  116. data/modules/mu/{clouds → providers}/aws/collection.rb +26 -25
  117. data/modules/mu/{clouds → providers}/aws/container_cluster.rb +724 -744
  118. data/modules/mu/providers/aws/database.rb +1744 -0
  119. data/modules/mu/{clouds → providers}/aws/dnszone.rb +88 -70
  120. data/modules/mu/providers/aws/endpoint.rb +1072 -0
  121. data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +220 -247
  122. data/modules/mu/{clouds → providers}/aws/folder.rb +8 -8
  123. data/modules/mu/{clouds → providers}/aws/function.rb +300 -142
  124. data/modules/mu/{clouds → providers}/aws/group.rb +31 -29
  125. data/modules/mu/{clouds → providers}/aws/habitat.rb +18 -15
  126. data/modules/mu/providers/aws/job.rb +466 -0
  127. data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +66 -56
  128. data/modules/mu/{clouds → providers}/aws/log.rb +17 -14
  129. data/modules/mu/{clouds → providers}/aws/msg_queue.rb +29 -19
  130. data/modules/mu/{clouds → providers}/aws/nosqldb.rb +114 -16
  131. data/modules/mu/{clouds → providers}/aws/notifier.rb +142 -65
  132. data/modules/mu/{clouds → providers}/aws/role.rb +158 -118
  133. data/modules/mu/{clouds → providers}/aws/search_domain.rb +201 -59
  134. data/modules/mu/{clouds → providers}/aws/server.rb +844 -1139
  135. data/modules/mu/{clouds → providers}/aws/server_pool.rb +74 -65
  136. data/modules/mu/{clouds → providers}/aws/storage_pool.rb +26 -44
  137. data/modules/mu/{clouds → providers}/aws/user.rb +24 -25
  138. data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
  139. data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +5 -4
  140. data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +2 -1
  141. data/modules/mu/{clouds → providers}/aws/vpc.rb +525 -931
  142. data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
  143. data/modules/mu/{clouds → providers}/azure.rb +29 -9
  144. data/modules/mu/{clouds → providers}/azure/container_cluster.rb +3 -8
  145. data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +18 -11
  146. data/modules/mu/{clouds → providers}/azure/habitat.rb +8 -6
  147. data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +5 -5
  148. data/modules/mu/{clouds → providers}/azure/role.rb +8 -10
  149. data/modules/mu/{clouds → providers}/azure/server.rb +97 -49
  150. data/modules/mu/{clouds → providers}/azure/user.rb +6 -8
  151. data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
  152. data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
  153. data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
  154. data/modules/mu/{clouds → providers}/azure/vpc.rb +16 -21
  155. data/modules/mu/{clouds → providers}/cloudformation.rb +18 -7
  156. data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
  157. data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
  158. data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
  159. data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
  160. data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
  161. data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
  162. data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
  163. data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
  164. data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
  165. data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
  166. data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +5 -7
  167. data/modules/mu/{clouds → providers}/docker.rb +0 -0
  168. data/modules/mu/{clouds → providers}/google.rb +68 -30
  169. data/modules/mu/{clouds → providers}/google/bucket.rb +13 -15
  170. data/modules/mu/{clouds → providers}/google/container_cluster.rb +85 -78
  171. data/modules/mu/{clouds → providers}/google/database.rb +11 -21
  172. data/modules/mu/{clouds → providers}/google/firewall_rule.rb +15 -14
  173. data/modules/mu/{clouds → providers}/google/folder.rb +20 -17
  174. data/modules/mu/{clouds → providers}/google/function.rb +140 -168
  175. data/modules/mu/{clouds → providers}/google/group.rb +29 -34
  176. data/modules/mu/{clouds → providers}/google/habitat.rb +21 -22
  177. data/modules/mu/{clouds → providers}/google/loadbalancer.rb +19 -21
  178. data/modules/mu/{clouds → providers}/google/role.rb +94 -58
  179. data/modules/mu/{clouds → providers}/google/server.rb +243 -156
  180. data/modules/mu/{clouds → providers}/google/server_pool.rb +26 -45
  181. data/modules/mu/{clouds → providers}/google/user.rb +95 -31
  182. data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
  183. data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
  184. data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
  185. data/modules/mu/{clouds → providers}/google/vpc.rb +103 -79
  186. data/modules/tests/aws-jobs-functions.yaml +46 -0
  187. data/modules/tests/bucket.yml +4 -0
  188. data/modules/tests/centos6.yaml +15 -0
  189. data/modules/tests/centos7.yaml +15 -0
  190. data/modules/tests/centos8.yaml +12 -0
  191. data/modules/tests/ecs.yaml +23 -0
  192. data/modules/tests/eks.yaml +1 -1
  193. data/modules/tests/functions/node-function/lambda_function.js +10 -0
  194. data/modules/tests/functions/python-function/lambda_function.py +12 -0
  195. data/modules/tests/includes-and-params.yaml +2 -1
  196. data/modules/tests/microservice_app.yaml +288 -0
  197. data/modules/tests/rds.yaml +108 -0
  198. data/modules/tests/regrooms/aws-iam.yaml +201 -0
  199. data/modules/tests/regrooms/bucket.yml +19 -0
  200. data/modules/tests/regrooms/rds.yaml +123 -0
  201. data/modules/tests/server-with-scrub-muisms.yaml +2 -1
  202. data/modules/tests/super_complex_bok.yml +2 -2
  203. data/modules/tests/super_simple_bok.yml +3 -5
  204. data/modules/tests/win2k12.yaml +17 -5
  205. data/modules/tests/win2k16.yaml +25 -0
  206. data/modules/tests/win2k19.yaml +25 -0
  207. data/requirements.txt +1 -0
  208. data/spec/mu/clouds/azure_spec.rb +2 -2
  209. metadata +240 -154
  210. data/extras/image-generators/AWS/windows.yaml +0 -18
  211. data/modules/mu/clouds/aws/database.rb +0 -1985
  212. data/modules/mu/clouds/aws/endpoint.rb +0 -592
@@ -87,7 +87,7 @@ module MU
87
87
  img = fetchImage(image_id, credentials: credentials)
88
88
  return DateTime.new if img.nil?
89
89
  return DateTime.parse(img.creation_timestamp)
90
- rescue ::Google::Apis::ClientError => e
90
+ rescue ::Google::Apis::ClientError
91
91
  end
92
92
 
93
93
  return DateTime.new
@@ -164,19 +164,26 @@ module MU
164
164
  def self.diskConfig(config, create = true, disk_as_url = true, credentials: nil)
165
165
  disks = []
166
166
  if config['image_id'].nil? and config['basis'].nil?
167
- pp config.keys
168
167
  raise MuError, "Can't generate disk configuration for server #{config['name']} without an image ID or basis specified"
169
168
  end
170
169
 
171
170
  img = fetchImage(config['image_id'] || config['basis']['launch_config']['image_id'], credentials: credentials)
172
171
 
173
- # XXX slurp settings from /dev/sda or w/e by convention?
172
+ # if img.source_disk and img.source_disk.match(/projects\/([^\/]+)\/zones\/([^\/]+)\/disks\/(.*)/)
173
+ # _junk, proj, az, name = Regexp.last_match
174
+ # disk_desc = MU::Cloud::Google.compute(credentials: credentials).get_disk(proj, az, name)
175
+ # pp disk_desc
176
+ # raise "nah"
177
+ # end
178
+
174
179
  disktype = "projects/#{config['project']}/zones/#{config['availability_zone']}/diskTypes/pd-standard"
175
- disktype = "pd-standard" if !disk_as_url
176
- # disk_type: projects/project/zones/#{config['availability_zone']}/diskTypes/pd-standard Other values include pd-ssd and local-ssd
180
+
181
+
182
+ disktype.gsub!(/.*?\/([^\/])$/, '\1') if !disk_as_url
183
+
177
184
  imageobj = MU::Cloud::Google.compute(:AttachedDiskInitializeParams).new(
178
185
  source_image: img.self_link,
179
- disk_size_gb: 10, # this is binary? 2gb, that says
186
+ disk_size_gb: img.disk_size_gb,
180
187
  disk_type: disktype,
181
188
  )
182
189
  disks << MU::Cloud::Google.compute(:AttachedDisk).new(
@@ -247,15 +254,22 @@ next if !create
247
254
  subnet_cfg = config['vpc']['subnets'].sample
248
255
 
249
256
  end
257
+
250
258
  subnet = vpc.getSubnet(name: subnet_cfg['subnet_name'], cloud_id: subnet_cfg['subnet_id'])
251
259
  if subnet.nil?
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})"
260
+ if config['vpc']['name']
261
+ subnet = vpc.getSubnet(name: config['vpc']['name']+subnet_cfg['subnet_name'], cloud_id: subnet_cfg['subnet_id'])
262
+ end
263
+ if subnet.nil?
264
+ 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})"
265
+ end
253
266
  end
254
267
 
255
268
  base_iface_obj = {
256
269
  :network => vpc.url,
257
270
  :subnetwork => subnet.url
258
271
  }
272
+
259
273
  if config['associate_public_ip']
260
274
  base_iface_obj[:access_configs] = [
261
275
  MU::Cloud::Google.compute(:AccessConfig).new
@@ -322,7 +336,7 @@ next if !create
322
336
  end
323
337
  metadata["startup-script"] = @userdata if @userdata and !@userdata.empty?
324
338
 
325
- deploykey = @config['ssh_user']+":"+@deploy.ssh_public_key
339
+ deploykey = @config["ssh_user"]+":"+@deploy.ssh_public_key
326
340
  if metadata["ssh-keys"]
327
341
  metadata["ssh-keys"] += "\n"+deploykey
328
342
  else
@@ -348,7 +362,7 @@ next if !create
348
362
  desc[:labels]["name"] = @mu_name.downcase
349
363
 
350
364
  if @config['network_tags'] and @config['network_tags'].size > 0
351
- desc[:tags] = U::Cloud::Google.compute(:Tags).new(
365
+ desc[:tags] = MU::Cloud::Google.compute(:Tags).new(
352
366
  items: @config['network_tags']
353
367
  )
354
368
  end
@@ -369,7 +383,7 @@ next if !create
369
383
  sleep 10
370
384
  end
371
385
  rescue ::Google::Apis::ClientError => e
372
- MU.log e.message, MU::ERR
386
+ MU.log e.message+" inserting instance into #{@project_id}/#{@config['availability_zone']}", MU::ERR, details: instanceobj
373
387
  raise e
374
388
  end while @cloud_id.nil?
375
389
 
@@ -394,7 +408,7 @@ next if !create
394
408
 
395
409
  notify
396
410
 
397
- rescue Exception => e
411
+ rescue StandardError => e
398
412
  if !cloud_desc.nil? and !done
399
413
  MU.log "Aborted before I could finish setting up #{@config['name']}, cleaning it up. Stack trace will print once cleanup is complete.", MU::WARN if !@deploy.nocleanup
400
414
  MU::MommaCat.unlockAll
@@ -445,7 +459,7 @@ next if !create
445
459
  )
446
460
  begin
447
461
  sleep 5
448
- end while cloud_desc.status != "TERMINATED" # means STOPPED
462
+ end while cloud_desc(use_cache: false).status != "TERMINATED" # means STOPPED
449
463
  end
450
464
 
451
465
  # Ask the Google API to start this node
@@ -462,30 +476,30 @@ next if !create
462
476
  end
463
477
 
464
478
  # Ask the Google API to restart this node
465
- # XXX unimplemented
466
- def reboot(hard = false)
479
+ # @param _hard [Boolean]: [IGNORED] Force a stop/start. This is the only available way to restart an instance in Google, so this flag is ignored.
480
+ def reboot(_hard = false)
467
481
  return if @cloud_id.nil?
468
-
482
+ stop
483
+ start
469
484
  end
470
485
 
471
486
  # Figure out what's needed to SSH into this server.
472
487
  # @return [Array<String>]: nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name, alternate_names
473
488
  def getSSHConfig
474
- node, config, deploydata = describe(cloud_id: @cloud_id)
489
+ describe(cloud_id: @cloud_id)
475
490
  # XXX add some awesome alternate names from metadata and make sure they end
476
491
  # up in MU::MommaCat's ssh config wangling
477
- ssh_keydir = Etc.getpwuid(Process.uid).dir+"/.ssh"
478
492
  return nil if @config.nil? or @deploy.nil?
479
493
 
480
494
  nat_ssh_key = nat_ssh_user = nat_ssh_host = nil
481
- if !@config["vpc"].nil? and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'], credentials: @config['credentials'])
495
+ if !@config["vpc"].nil? and !MU::Cloud.resourceClass("Google", "VPC").haveRouteToInstance?(cloud_desc, credentials: @config['credentials'])
482
496
 
483
497
  if !@nat.nil?
484
498
  if @nat.cloud_desc.nil?
485
499
  MU.log "NAT was missing cloud descriptor when called in #{@mu_name}'s getSSHConfig", MU::ERR
486
500
  return nil
487
501
  end
488
- foo, bar, baz, nat_ssh_host, nat_ssh_user, nat_ssh_key = @nat.getSSHConfig
502
+ _foo, _bar, _baz, nat_ssh_host, nat_ssh_user, nat_ssh_key = @nat.getSSHConfig
489
503
  if nat_ssh_user.nil? and !nat_ssh_host.nil?
490
504
  MU.log "#{@config["name"]} (#{MU.deploy_id}) is configured to use #{@config['vpc']} NAT #{nat_ssh_host}, but username isn't specified. Guessing root.", MU::ERR, details: caller
491
505
  nat_ssh_user = "root"
@@ -495,7 +509,8 @@ next if !create
495
509
 
496
510
  if @config['ssh_user'].nil?
497
511
  if windows?
498
- @config['ssh_user'] = "Administrator"
512
+ @config['ssh_user'] = @config['windows_admin_user']
513
+ @config['ssh_user'] ||= "Administrator"
499
514
  else
500
515
  @config['ssh_user'] = "root"
501
516
  end
@@ -512,26 +527,24 @@ next if !create
512
527
  @cloud_id = instance_id
513
528
  end
514
529
 
515
- instance = cloud_desc
516
-
517
- node, config, deploydata = describe(cloud_id: @cloud_id)
530
+ node, _config, deploydata = describe(cloud_id: @cloud_id)
518
531
  instance = cloud_desc
519
532
  raise MuError, "Couldn't find instance of #{@mu_name} (#{@cloud_id})" if !instance
520
533
  return false if !MU::MommaCat.lock(@cloud_id+"-orchestrate", true)
521
534
  return false if !MU::MommaCat.lock(@cloud_id+"-groom", true)
522
535
 
523
536
  # MU::Cloud::AWS.createStandardTags(@cloud_id, region: @config['region'])
524
- # MU::MommaCat.createTag(@cloud_id, "Name", node, region: @config['region'])
537
+ # MU::Cloud::AWS.createTag(@cloud_id, "Name", node, region: @config['region'])
525
538
  #
526
539
  # if @config['optional_tags']
527
540
  # MU::MommaCat.listOptionalTags.each { |key, value|
528
- # MU::MommaCat.createTag(@cloud_id, key, value, region: @config['region'])
541
+ # MU::Cloud::AWS.createTag(@cloud_id, key, value, region: @config['region'])
529
542
  # }
530
543
  # end
531
544
  #
532
545
  # if !@config['tags'].nil?
533
546
  # @config['tags'].each { |tag|
534
- # MU::MommaCat.createTag(@cloud_id, tag['key'], tag['value'], region: @config['region'])
547
+ # MU::Cloud::AWS.createTag(@cloud_id, tag['key'], tag['value'], region: @config['region'])
535
548
  # }
536
549
  # end
537
550
  # MU.log "Tagged #{node} (#{@cloud_id}) with MU-ID=#{MU.deploy_id}", MU::DEBUG
@@ -609,8 +622,8 @@ next if !create
609
622
  @named = true
610
623
  end
611
624
 
612
- nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name = getSSHConfig
613
- if !nat_ssh_host and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'], credentials: @config['credentials'])
625
+ _nat_ssh_key, _nat_ssh_user, nat_ssh_host, _canonical_ip, _ssh_user, _ssh_key_name = getSSHConfig
626
+ if !nat_ssh_host and !MU::Cloud.resourceClass("Google", "VPC").haveRouteToInstance?(cloud_desc, credentials: @config['credentials'])
614
627
  # XXX check if canonical_ip is in the private ranges
615
628
  # raise MuError, "#{node} has no NAT host configured, and I have no other route to it"
616
629
  end
@@ -641,8 +654,8 @@ next if !create
641
654
  # Locate an existing instance or instances and return an array containing matching AWS resource descriptors for those that match.
642
655
  # @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching instances
643
656
  def self.find(**args)
644
- args[:project] ||= args[:habitat]
645
- args[:project] ||= MU::Cloud::Google.defaultProject(args[:credentials])
657
+ args = MU::Cloud::Google.findLocationArgs(args)
658
+
646
659
  if !args[:region].nil? and MU::Cloud::Google.listRegions.include?(args[:region])
647
660
  regions = [args[:region]]
648
661
  else
@@ -720,9 +733,6 @@ next if !create
720
733
  # Return a description of this resource appropriate for deployment
721
734
  # metadata. Arguments reflect the return values of the MU::Cloud::[Resource].describe method
722
735
  def notify
723
- node, config, deploydata = describe(cloud_id: @cloud_id, update_cache: true)
724
- deploydata = {} if deploydata.nil?
725
-
726
736
  if cloud_desc.nil?
727
737
  raise MuError, "Failed to load instance metadata for #{@config['mu_name']}/#{@cloud_id}"
728
738
  end
@@ -783,7 +793,7 @@ next if !create
783
793
 
784
794
  MU::MommaCat.lock(@cloud_id+"-groom")
785
795
 
786
- node, config, deploydata = describe(cloud_id: @cloud_id)
796
+ node, _config, deploydata = describe(cloud_id: @cloud_id)
787
797
 
788
798
  if node.nil? or node.empty?
789
799
  raise MuError, "MU::Cloud::Google::Server.groom was called without a mu_name"
@@ -798,29 +808,6 @@ next if !create
798
808
 
799
809
  # punchAdminNAT
800
810
 
801
- # MU::Cloud::AWS::Server.tagVolumes(@cloud_id)
802
-
803
- # If we have a loadbalancer configured, attach us to it
804
- # if !@config['loadbalancers'].nil?
805
- # if @loadbalancers.nil?
806
- # raise MuError, "#{@mu_name} is configured to use LoadBalancers, but none have been loaded by dependencies()"
807
- # end
808
- # @loadbalancers.each { |lb|
809
- # lb.registerNode(@cloud_id)
810
- # }
811
- # end
812
-
813
- # Let us into any databases we depend on.
814
- # This is probelmtic with autscaling - old ips are not removed, and access to the database can easily be given at the BoK level
815
- # if @dependencies.has_key?("database")
816
- # @dependencies['database'].values.each { |db|
817
- # db.allowHost(@deploydata["private_ip_address"]+"/32")
818
- # if @deploydata["public_ip_address"]
819
- # db.allowHost(@deploydata["public_ip_address"]+"/32")
820
- # end
821
- # }
822
- # end
823
-
824
811
  @groomer.saveDeployData
825
812
 
826
813
  begin
@@ -859,9 +846,9 @@ next if !create
859
846
  project: @project_id,
860
847
  exclude_storage: img_cfg['image_exclude_storage'],
861
848
  make_public: img_cfg['public'],
862
- tags: @config['tags'],
849
+ tags: @tags,
863
850
  zone: @config['availability_zone'],
864
- family: @config['family'],
851
+ family: img_cfg['family'],
865
852
  credentials: @config['credentials']
866
853
  )
867
854
  @deploy.notify("images", @config['name'], {"image_id" => image_id})
@@ -897,50 +884,50 @@ next if !create
897
884
  raise MuError, "Failed to find instance '#{instance_id}' in createImage"
898
885
  end
899
886
 
900
- labels = {}
901
- MU::MommaCat.listStandardTags.each_pair { |key, value|
902
- if !value.nil?
903
- labels[key.downcase] = value.downcase.gsub(/[^a-z0-9\-\_]/i, "_")
904
- end
905
- }
887
+ labels = Hash[tags.keys.map { |k|
888
+ [k.downcase, tags[k].downcase.gsub(/[^-_a-z0-9]/, '-')] }
889
+ ]
890
+ labels["name"] = name
906
891
 
907
892
  bootdisk = nil
908
893
  threads = []
909
894
  parent_thread_id = Thread.current.object_id
910
- instance[instance_id].disks.each { |disk|
911
- threads << Thread.new {
912
- Thread.abort_on_exception = false
913
- MU.dupGlobals(parent_thread_id)
914
- if disk.boot
915
- bootdisk = disk.source
916
- else
917
- snapobj = MU::Cloud::Google.compute(:Snapshot).new(
918
- name: name+"-"+disk.device_name,
919
- description: "Mu image created from #{name} (#{disk.device_name})"
920
- )
921
- diskname = disk.source.gsub(/.*?\//, "")
922
- MU.log "Creating snapshot of #{diskname} in #{zone}", MU::NOTICE, details: snapobj
923
- snap = MU::Cloud::Google.compute(credentials: credentials).create_disk_snapshot(
924
- project,
925
- zone,
926
- diskname,
927
- snapobj
928
- )
929
- MU::Cloud::Google.compute(credentials: credentials).set_snapshot_labels(
930
- project,
931
- snap.name,
932
- MU::Cloud::Google.compute(:GlobalSetLabelsRequest).new(
933
- label_fingerprint: snap.label_fingerprint,
934
- labels: labels.merge({
935
- "mu-device-name" => disk.device_name,
936
- "mu-parent-image" => name,
937
- "mu-orig-zone" => zone
938
- })
895
+ if !exclude_storage
896
+ instance[instance_id].disks.each { |disk|
897
+ threads << Thread.new {
898
+ Thread.abort_on_exception = false
899
+ MU.dupGlobals(parent_thread_id)
900
+ if disk.boot
901
+ bootdisk = disk.source
902
+ else
903
+ snapobj = MU::Cloud::Google.compute(:Snapshot).new(
904
+ name: name+"-"+disk.device_name,
905
+ description: "Mu image created from #{name} (#{disk.device_name})"
939
906
  )
940
- )
941
- end
907
+ diskname = disk.source.gsub(/.*?\//, "")
908
+ MU.log "Creating snapshot of #{diskname} in #{zone}", MU::NOTICE, details: snapobj
909
+ snap = MU::Cloud::Google.compute(credentials: credentials).create_disk_snapshot(
910
+ project,
911
+ zone,
912
+ diskname,
913
+ snapobj
914
+ )
915
+ MU::Cloud::Google.compute(credentials: credentials).set_snapshot_labels(
916
+ project,
917
+ snap.name,
918
+ MU::Cloud::Google.compute(:GlobalSetLabelsRequest).new(
919
+ label_fingerprint: snap.label_fingerprint,
920
+ labels: labels.merge({
921
+ "mu-device-name" => disk.device_name,
922
+ "mu-parent-image" => name,
923
+ "mu-orig-zone" => zone
924
+ })
925
+ )
926
+ )
927
+ end
928
+ }
942
929
  }
943
- }
930
+ end
944
931
  threads.each do |t|
945
932
  t.join
946
933
  end
@@ -954,10 +941,28 @@ next if !create
954
941
  }
955
942
  image_desc[:family] = family if family
956
943
 
957
- newimage = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_image(
944
+ MU.log "Creating image of #{name}", MU::NOTICE, details: image_desc
945
+ newimage = MU::Cloud::Google.compute(credentials: credentials).insert_image(
958
946
  project,
959
947
  MU::Cloud::Google.compute(:Image).new(image_desc)
960
948
  )
949
+
950
+ if make_public
951
+ MU.log "Making image #{newimage.name} public"
952
+ MU::Cloud::Google.compute(credentials: credentials).set_image_iam_policy(
953
+ project,
954
+ newimage.name,
955
+ MU::Cloud::Google.compute(:GlobalSetPolicyRequest).new(
956
+ bindings: [
957
+ MU::Cloud::Google.compute(:Binding).new(
958
+ members: ["allAuthenticatedUsers"],
959
+ role: "roles/compute.imageUser"
960
+ )
961
+ ],
962
+ )
963
+ )
964
+ end
965
+
961
966
  newimage.name
962
967
  end
963
968
 
@@ -966,7 +971,7 @@ next if !create
966
971
  # bastion hosts that may be in the path, see getSSHConfig if that's what
967
972
  # you need.
968
973
  def canonicalIP
969
- mu_name, config, deploydata = describe(cloud_id: @cloud_id)
974
+ describe(cloud_id: @cloud_id)
970
975
 
971
976
  if !cloud_desc
972
977
  raise MuError, "Couldn't retrieve cloud descriptor for server #{self}"
@@ -987,7 +992,7 @@ next if !create
987
992
  # Our deploydata gets corrupted often with server pools, this will cause us to use the wrong IP to identify a node
988
993
  # which will cause us to create certificates, DNS records and other artifacts with incorrect information which will cause our deploy to fail.
989
994
  # The cloud_id is always correct so lets use 'cloud_desc' to get the correct IPs
990
- if MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, credentials: @config['credentials']) or public_ips.size == 0
995
+ if MU::Cloud.resourceClass("Google", "VPC").haveRouteToInstance?(cloud_desc, credentials: @config['credentials']) or public_ips.size == 0
991
996
  @config['canonical_ip'] = private_ips.first
992
997
  return private_ips.first
993
998
  else
@@ -996,10 +1001,109 @@ next if !create
996
1001
  end
997
1002
  end
998
1003
 
1004
+ # Return all of the IP addresses, public and private, from all of our
1005
+ # network interfaces.
1006
+ # @return [Array<String>]
1007
+ def listIPs
1008
+ ips = []
1009
+ cloud_desc.network_interfaces.each { |iface|
1010
+ ips << iface.network_ip
1011
+ if iface.access_configs
1012
+ iface.access_configs.each { |acfg|
1013
+ ips << acfg.nat_ip if acfg.nat_ip
1014
+ }
1015
+ end
1016
+ }
1017
+ ips
1018
+ end
1019
+
999
1020
  # return [String]: A password string.
1000
- def getWindowsAdminPassword
1021
+ def getWindowsAdminPassword(use_cache: true)
1022
+ @config['windows_auth_vault'] ||= {
1023
+ "vault" => @mu_name,
1024
+ "item" => "windows_credentials",
1025
+ "password_field" => "password"
1026
+ }
1027
+
1028
+ if use_cache
1029
+ begin
1030
+ win_admin_password = @groomer.getSecret(
1031
+ vault: @config['windows_auth_vault']['vault'],
1032
+ item: @config['windows_auth_vault']['item'],
1033
+ field: @config["windows_auth_vault"]["password_field"]
1034
+ )
1035
+ return win_admin_password if win_admin_password
1036
+ rescue MU::Groomer::MuNoSuchSecret, MU::Groomer::RunError
1037
+ end
1038
+ end
1039
+
1040
+ require 'openssl/oaep'
1041
+ timeout = 300
1042
+
1043
+ serial_out = nil
1044
+ key = OpenSSL::PKey::RSA.generate 2048
1045
+
1046
+ missing_response = Proc.new {
1047
+ !serial_out or !serial_out.contents or serial_out.contents.empty? or JSON.parse(serial_out.contents)["userName"] != @config['windows_admin_username']
1048
+ }
1049
+
1050
+ did_metadata = false
1051
+ MU.retrier(loop_if: missing_response, wait: 10, max: timeout/10) {
1052
+ serial_out = MU::Cloud::Google.compute(credentials: @credentials).get_instance_serial_port_output(@project_id, @config['availability_zone'], @cloud_id, port: 4)
1053
+
1054
+ if missing_response.call and
1055
+ !cloud_desc(use_cache: false).metadata.items.map { |i| i.key }.include?("windows-keys")
1056
+ keybytes = Base64.decode64(key.public_key.export.gsub(/-----(?:BEGIN|END) PUBLIC KEY-----/, ''))
1057
+ modulus = keybytes.byteslice(33,256)
1058
+ exponent = keybytes.byteslice(291,3)
1059
+ keydata = {
1060
+ "userName" => @config['windows_admin_username'],
1061
+ "modulus" => Base64.strict_encode64(modulus),
1062
+ "exponent" => Base64.strict_encode64(exponent),
1063
+ "email" => MU.muCfg['mu_admin_email'],
1064
+ "expireOn" => (Time.now.utc+timeout).strftime('%Y-%m-%dT%H:%M:%SZ')
1065
+ }
1066
+
1067
+ new_items = cloud_desc.metadata.items.map { |item|
1068
+ MU::Cloud::Google.compute(:Metadata)::Item.new(
1069
+ key: item.key,
1070
+ value: item.value
1071
+ )
1072
+ }
1073
+ new_items.reject! { |item| item.key == "windows-keys" }
1074
+ new_items << MU::Cloud::Google.compute(:Metadata)::Item.new(
1075
+ key: "windows-keys",
1076
+ value: JSON.generate(keydata)
1077
+ )
1078
+ new_metadata = MU::Cloud::Google.compute(:Metadata).new(
1079
+ fingerprint: cloud_desc(use_cache: false).metadata.fingerprint,
1080
+ items: new_items
1081
+ )
1082
+
1083
+ MU::Cloud::Google.compute(credentials: @credentials).set_instance_metadata(@project_id, @config['availability_zone'], @cloud_id, new_metadata)
1084
+ end
1085
+ }
1086
+
1087
+ return nil if missing_response.call
1088
+
1089
+ pwdata = JSON.parse(serial_out.contents)
1090
+ if pwdata['encryptedPassword'] and pwdata['userName'] == @config['windows_admin_username']
1091
+ decrypted_pw = key.private_decrypt_oaep(Base64.strict_decode64(pwdata['encryptedPassword']))
1092
+ creds = {
1093
+ "username" => @config['windows_admin_username'],
1094
+ "password" => decrypted_pw,
1095
+ "sshd_username" => "sshd_service",
1096
+ "sshd_password" => decrypted_pw
1097
+ }
1098
+ @groomer.saveSecret(vault: @mu_name, item: "windows_credentials", data: creds, permissions: "name:#{@mu_name}")
1099
+
1100
+ return decrypted_pw
1101
+ end
1102
+
1103
+ nil
1001
1104
  end
1002
1105
 
1106
+
1003
1107
  # Add a volume to this instance
1004
1108
  # @param dev [String]: Device name to use when attaching to instance
1005
1109
  # @param size [String]: Size (in gb) of the new volume
@@ -1017,7 +1121,7 @@ next if !create
1017
1121
  description: description,
1018
1122
  zone: @config['availability_zone'],
1019
1123
  # type: "projects/#{config['project']}/zones/#{config['availability_zone']}/diskTypes/pd-ssd",
1020
- type: "projects/#{@project_id}/zones/#{@config['availability_zone']}/diskTypes/pd-standard",
1124
+ type: "projects/#{@project_id}/zones/#{@config['availability_zone']}/diskTypes/#{type}",
1021
1125
  # Other values include pd-ssd and local-ssd
1022
1126
  name: resname
1023
1127
  )
@@ -1045,7 +1149,7 @@ next if !create
1045
1149
  )
1046
1150
 
1047
1151
  MU.log "Attaching disk #{resname} to #{@cloud_id} at #{devname}"
1048
- attachment = MU::Cloud::Google.compute(credentials: @config['credentials']).attach_disk(
1152
+ MU::Cloud::Google.compute(credentials: @config['credentials']).attach_disk(
1049
1153
  @project_id,
1050
1154
  @config['availability_zone'],
1051
1155
  @cloud_id,
@@ -1064,7 +1168,7 @@ next if !create
1064
1168
  # Reverse-map our cloud description into a runnable config hash.
1065
1169
  # We assume that any values we have in +@config+ are placeholders, and
1066
1170
  # calculate our own accordingly based on what's live in the cloud.
1067
- def toKitten(rootparent: nil, billing: nil, habitats: nil)
1171
+ def toKitten(**_args)
1068
1172
  bok = {
1069
1173
  "cloud" => "Google",
1070
1174
  "credentials" => @config['credentials'],
@@ -1186,41 +1290,47 @@ next if !create
1186
1290
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
1187
1291
  # @param region [String]: The cloud provider region
1188
1292
  # @return [void]
1189
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
1190
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
1191
- return if !MU::Cloud::Google::Habitat.isLive?(flags["project"], credentials)
1192
- skipsnapshots = flags["skipsnapshots"]
1193
- onlycloud = flags["onlycloud"]
1293
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
1294
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
1295
+ return if !MU::Cloud.resourceClass("Google", "Habitat").isLive?(flags["habitat"], credentials)
1296
+
1194
1297
  # XXX make damn sure MU.deploy_id is set
1298
+ filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
1299
+ if !ignoremaster and MU.mu_public_ip
1300
+ filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
1301
+ end
1195
1302
 
1196
1303
  MU::Cloud::Google.listAZs(region).each { |az|
1197
1304
  disks = []
1198
1305
  resp = MU::Cloud::Google.compute(credentials: credentials).list_instances(
1199
- flags["project"],
1306
+ flags["habitat"],
1200
1307
  az,
1201
- filter: "description eq #{MU.deploy_id}"
1308
+ filter: filter
1202
1309
  )
1203
1310
  if !resp.items.nil? and resp.items.size > 0
1204
1311
  resp.items.each { |instance|
1205
- saname = instance.tags.items.first.gsub(/[^a-z]/, "") # XXX this nonsense again
1206
1312
  MU.log "Terminating instance #{instance.name}"
1207
1313
  if !instance.disks.nil? and instance.disks.size > 0
1208
1314
  instance.disks.each { |disk|
1209
1315
  disks << disk if !disk.auto_delete
1210
1316
  }
1211
1317
  end
1212
- deletia = MU::Cloud::Google.compute(credentials: credentials).delete_instance(
1213
- flags["project"],
1318
+ MU::Cloud::Google.compute(credentials: credentials).delete_instance(
1319
+ flags["habitat"],
1214
1320
  az,
1215
1321
  instance.name
1216
1322
  ) if !noop
1217
- MU.log "Removing service account #{saname}"
1218
- begin
1219
- MU::Cloud::Google.iam(credentials: credentials).delete_project_service_account(
1220
- "projects/#{flags["project"]}/serviceAccounts/#{saname}@#{flags["project"]}.iam.gserviceaccount.com"
1221
- ) if !noop
1222
- rescue ::Google::Apis::ClientError => e
1223
- raise e if !e.message.match(/^notFound: /)
1323
+ if instance.service_accounts
1324
+ instance.service_accounts.each { |sa|
1325
+ MU.log "Removing service account #{sa.email}"
1326
+ begin
1327
+ MU::Cloud::Google.iam(credentials: credentials).delete_project_service_account(
1328
+ "projects/#{flags["habitat"]}/serviceAccounts/#{sa.email}"
1329
+ ) if !noop
1330
+ rescue ::Google::Apis::ClientError => e
1331
+ raise e if !e.message.match(/^notFound: /)
1332
+ end
1333
+ }
1224
1334
  end
1225
1335
  # XXX wait-loop on pending?
1226
1336
  # pp deletia
@@ -1233,7 +1343,7 @@ next if !create
1233
1343
  # XXX honor snapshotting
1234
1344
  MU::Cloud::Google.compute(credentials: credentials).delete(
1235
1345
  "disk",
1236
- flags["project"],
1346
+ flags["habitat"],
1237
1347
  az,
1238
1348
  noop
1239
1349
  ) if !noop
@@ -1246,7 +1356,11 @@ next if !create
1246
1356
  def self.schema(config)
1247
1357
  toplevel_required = []
1248
1358
  schema = {
1249
- "roles" => MU::Cloud::Google::User.schema(config)[1]["roles"],
1359
+ "roles" => MU::Cloud.resourceClass("Google", "User").schema(config)[1]["roles"],
1360
+ "windows_admin_username" => {
1361
+ "type" => "string",
1362
+ "default" => "muadmin"
1363
+ },
1250
1364
  "create_image" => {
1251
1365
  "properties" => {
1252
1366
  "family" => {
@@ -1353,8 +1467,7 @@ next if !create
1353
1467
  foundmatch = false
1354
1468
  MU::Cloud.availableClouds.each { |cloud|
1355
1469
  next if cloud == "Google"
1356
- cloudbase = Object.const_get("MU").const_get("Cloud").const_get(cloud)
1357
- foreign_types = (cloudbase.listInstanceTypes).values.first
1470
+ foreign_types = (MU::Cloud.cloudClass(cloud).listInstanceTypes).values.first
1358
1471
  if foreign_types.size == 1
1359
1472
  foreign_types = foreign_types.values.first
1360
1473
  end
@@ -1411,6 +1524,7 @@ next if !create
1411
1524
  end
1412
1525
 
1413
1526
  if server['service_account']
1527
+ server['service_account'] = server['service_account'].to_h
1414
1528
  server['service_account']['cloud'] = "Google"
1415
1529
  server['service_account']['habitat'] ||= server['project']
1416
1530
  found = MU::Config::Ref.get(server['service_account'])
@@ -1419,37 +1533,12 @@ next if !create
1419
1533
  ok = false
1420
1534
  end
1421
1535
  else
1422
- user = {
1423
- "name" => server['name'],
1424
- "cloud" => "Google",
1425
- "project" => server["project"],
1426
- "credentials" => server["credentials"],
1427
- "type" => "service"
1428
- }
1429
- if user["name"].length < 6
1430
- user["name"] += Password.pronounceable(6)
1431
- end
1432
- if server['roles']
1433
- user['roles'] = server['roles'].dup
1434
- end
1435
- configurator.insertKitten(user, "users", true)
1436
- server['dependencies'] ||= []
1437
- server['service_account'] = MU::Config::Ref.get(
1438
- type: "users",
1439
- cloud: "Google",
1440
- name: user["name"],
1441
- project: user["project"],
1442
- credentials: user["credentials"]
1443
- )
1444
- server['dependencies'] << {
1445
- "type" => "user",
1446
- "name" => user["name"]
1447
- }
1536
+ server = MU::Cloud.resourceClass("Google", "User").genericServiceAccount(server, configurator)
1448
1537
  end
1449
1538
 
1450
1539
  subnets = nil
1451
1540
  if !server['vpc']
1452
- vpcs = MU::Cloud::Google::VPC.find(credentials: server['credentials'])
1541
+ vpcs = MU::Cloud.resourceClass("Google", "VPC").find(credentials: server['credentials'])
1453
1542
  if vpcs["default"]
1454
1543
  server["vpc"] ||= {}
1455
1544
  server["vpc"]["vpc_id"] = vpcs["default"].self_link
@@ -1464,7 +1553,7 @@ next if !create
1464
1553
  if !server['vpc']['subnet_id'] and server['vpc']['subnet_name'].nil?
1465
1554
  if !subnets
1466
1555
  if server["vpc"]["vpc_id"]
1467
- vpcs = MU::Cloud::Google::VPC.find(cloud_id: server["vpc"]["vpc_id"])
1556
+ vpcs = MU::Cloud.resourceClass("Google", "VPC").find(cloud_id: server["vpc"]["vpc_id"])
1468
1557
  subnets = vpcs["default"].subnetworks.sample
1469
1558
  end
1470
1559
  end
@@ -1509,7 +1598,7 @@ next if !create
1509
1598
  img_project = Regexp.last_match[1]
1510
1599
  img_name = Regexp.last_match[2]
1511
1600
  begin
1512
- img = MU::Cloud::Google.compute(credentials: server['credentials']).get_image(img_project, img_name)
1601
+ MU::Cloud::Google.compute(credentials: server['credentials']).get_image(img_project, img_name)
1513
1602
  snaps = MU::Cloud::Google.compute(credentials: server['credentials']).list_snapshots(
1514
1603
  img_project,
1515
1604
  filter: "name eq #{img_name}-.*"
@@ -1548,8 +1637,6 @@ next if !create
1548
1637
  ok
1549
1638
  end
1550
1639
 
1551
- private
1552
-
1553
1640
  end #class
1554
1641
  end #class
1555
1642
  end