cloud-mu 1.9.0.pre.beta → 2.0.0.pre.alpha

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 (114) hide show
  1. checksums.yaml +4 -4
  2. data/Berksfile +16 -54
  3. data/Berksfile.lock +14 -62
  4. data/bin/mu-aws-setup +131 -108
  5. data/bin/mu-configure +311 -74
  6. data/bin/mu-gcp-setup +84 -62
  7. data/bin/mu-load-config.rb +46 -2
  8. data/bin/mu-self-update +11 -9
  9. data/bin/mu-upload-chef-artifacts +4 -4
  10. data/{mu.gemspec → cloud-mu.gemspec} +2 -2
  11. data/cookbooks/awscli/Berksfile +8 -0
  12. data/cookbooks/mu-activedirectory/Berksfile +11 -0
  13. data/cookbooks/mu-firewall/Berksfile +9 -0
  14. data/cookbooks/mu-firewall/metadata.rb +1 -1
  15. data/cookbooks/mu-glusterfs/Berksfile +10 -0
  16. data/cookbooks/mu-jenkins/Berksfile +14 -0
  17. data/cookbooks/mu-master/Berksfile +23 -0
  18. data/cookbooks/mu-master/attributes/default.rb +1 -1
  19. data/cookbooks/mu-master/metadata.rb +2 -2
  20. data/cookbooks/mu-master/recipes/default.rb +1 -1
  21. data/cookbooks/mu-master/recipes/init.rb +7 -3
  22. data/cookbooks/mu-master/recipes/ssl-certs.rb +1 -0
  23. data/cookbooks/mu-mongo/Berksfile +10 -0
  24. data/cookbooks/mu-openvpn/Berksfile +11 -0
  25. data/cookbooks/mu-php54/Berksfile +13 -0
  26. data/cookbooks/mu-splunk/Berksfile +10 -0
  27. data/cookbooks/mu-tools/Berksfile +21 -0
  28. data/cookbooks/mu-tools/files/default/Mu_CA.pem +15 -15
  29. data/cookbooks/mu-utility/Berksfile +9 -0
  30. data/cookbooks/mu-utility/metadata.rb +2 -1
  31. data/cookbooks/nagios/Berksfile +7 -4
  32. data/cookbooks/s3fs/Berksfile +9 -0
  33. data/environments/dev.json +6 -6
  34. data/environments/prod.json +6 -6
  35. data/modules/mu.rb +20 -42
  36. data/modules/mu/cleanup.rb +102 -100
  37. data/modules/mu/cloud.rb +90 -28
  38. data/modules/mu/clouds/aws.rb +449 -218
  39. data/modules/mu/clouds/aws/alarm.rb +29 -17
  40. data/modules/mu/clouds/aws/cache_cluster.rb +78 -64
  41. data/modules/mu/clouds/aws/collection.rb +25 -18
  42. data/modules/mu/clouds/aws/container_cluster.rb +73 -66
  43. data/modules/mu/clouds/aws/database.rb +124 -116
  44. data/modules/mu/clouds/aws/dnszone.rb +27 -20
  45. data/modules/mu/clouds/aws/firewall_rule.rb +30 -22
  46. data/modules/mu/clouds/aws/folder.rb +18 -3
  47. data/modules/mu/clouds/aws/function.rb +77 -23
  48. data/modules/mu/clouds/aws/group.rb +19 -12
  49. data/modules/mu/clouds/aws/habitat.rb +153 -0
  50. data/modules/mu/clouds/aws/loadbalancer.rb +59 -52
  51. data/modules/mu/clouds/aws/log.rb +30 -23
  52. data/modules/mu/clouds/aws/msg_queue.rb +29 -20
  53. data/modules/mu/clouds/aws/notifier.rb +222 -0
  54. data/modules/mu/clouds/aws/role.rb +178 -90
  55. data/modules/mu/clouds/aws/search_domain.rb +40 -24
  56. data/modules/mu/clouds/aws/server.rb +169 -137
  57. data/modules/mu/clouds/aws/server_pool.rb +60 -83
  58. data/modules/mu/clouds/aws/storage_pool.rb +59 -31
  59. data/modules/mu/clouds/aws/user.rb +36 -27
  60. data/modules/mu/clouds/aws/userdata/linux.erb +101 -93
  61. data/modules/mu/clouds/aws/vpc.rb +250 -189
  62. data/modules/mu/clouds/azure.rb +132 -0
  63. data/modules/mu/clouds/cloudformation.rb +65 -1
  64. data/modules/mu/clouds/cloudformation/alarm.rb +8 -0
  65. data/modules/mu/clouds/cloudformation/cache_cluster.rb +7 -0
  66. data/modules/mu/clouds/cloudformation/collection.rb +7 -0
  67. data/modules/mu/clouds/cloudformation/database.rb +7 -0
  68. data/modules/mu/clouds/cloudformation/dnszone.rb +7 -0
  69. data/modules/mu/clouds/cloudformation/firewall_rule.rb +9 -2
  70. data/modules/mu/clouds/cloudformation/loadbalancer.rb +7 -0
  71. data/modules/mu/clouds/cloudformation/log.rb +7 -0
  72. data/modules/mu/clouds/cloudformation/server.rb +7 -0
  73. data/modules/mu/clouds/cloudformation/server_pool.rb +7 -0
  74. data/modules/mu/clouds/cloudformation/vpc.rb +7 -0
  75. data/modules/mu/clouds/google.rb +214 -110
  76. data/modules/mu/clouds/google/container_cluster.rb +42 -24
  77. data/modules/mu/clouds/google/database.rb +15 -6
  78. data/modules/mu/clouds/google/firewall_rule.rb +17 -25
  79. data/modules/mu/clouds/google/group.rb +13 -5
  80. data/modules/mu/clouds/google/habitat.rb +105 -0
  81. data/modules/mu/clouds/google/loadbalancer.rb +28 -20
  82. data/modules/mu/clouds/google/server.rb +93 -354
  83. data/modules/mu/clouds/google/server_pool.rb +18 -10
  84. data/modules/mu/clouds/google/user.rb +22 -14
  85. data/modules/mu/clouds/google/vpc.rb +97 -69
  86. data/modules/mu/config.rb +133 -38
  87. data/modules/mu/config/alarm.rb +25 -0
  88. data/modules/mu/config/cache_cluster.rb +5 -3
  89. data/modules/mu/config/cache_cluster.yml +23 -0
  90. data/modules/mu/config/database.rb +25 -16
  91. data/modules/mu/config/database.yml +3 -3
  92. data/modules/mu/config/function.rb +1 -2
  93. data/modules/mu/config/{project.rb → habitat.rb} +10 -10
  94. data/modules/mu/config/notifier.rb +85 -0
  95. data/modules/mu/config/notifier.yml +9 -0
  96. data/modules/mu/config/role.rb +1 -1
  97. data/modules/mu/config/search_domain.yml +2 -2
  98. data/modules/mu/config/server.rb +13 -1
  99. data/modules/mu/config/server.yml +3 -3
  100. data/modules/mu/config/server_pool.rb +3 -1
  101. data/modules/mu/config/storage_pool.rb +3 -1
  102. data/modules/mu/config/storage_pool.yml +19 -0
  103. data/modules/mu/config/vpc.rb +70 -8
  104. data/modules/mu/groomers/chef.rb +2 -3
  105. data/modules/mu/kittens.rb +500 -122
  106. data/modules/mu/master.rb +5 -5
  107. data/modules/mu/mommacat.rb +151 -91
  108. data/modules/tests/super_complex_bok.yml +12 -0
  109. data/modules/tests/super_simple_bok.yml +12 -0
  110. data/spec/mu/clouds/azure_spec.rb +82 -0
  111. data/spec/spec_helper.rb +105 -0
  112. metadata +26 -5
  113. data/modules/mu/clouds/aws/notification.rb +0 -139
  114. data/modules/mu/config/notification.rb +0 -44
@@ -89,21 +89,26 @@ module MU
89
89
  # @param rolename [String]:
90
90
  # @param project [String]:
91
91
  # @param scopes [Array<String>]: https://developers.google.com/identity/protocols/googlescopes
92
- def self.createServiceAccount(rolename, project: MU::Cloud::Google.defaultProject, scopes: ["https://www.googleapis.com/auth/compute.readonly", "https://www.googleapis.com/auth/logging.write", "https://www.googleapis.com/auth/cloud-platform"])
92
+ # XXX this should be a MU::Cloud::Google::User resource
93
+ def self.createServiceAccount(rolename, deploy, project: nil, scopes: ["https://www.googleapis.com/auth/compute.readonly", "https://www.googleapis.com/auth/logging.write", "https://www.googleapis.com/auth/cloud-platform"], credentials: nil)
94
+ project ||= MU::Cloud::Google.defaultProject(credentials)
95
+
93
96
  #https://www.googleapis.com/auth/devstorage.read_only ?
94
- name = MU::Cloud::Google.nameStr(rolename)
97
+ name = deploy.getResourceName(rolename, max_length: 30).downcase
95
98
 
96
99
  saobj = MU::Cloud::Google.iam(:CreateServiceAccountRequest).new(
97
- account_id: rolename.gsub(/[^a-z]/, ""), # XXX this mangling isn't required in the console, so why is it here?
100
+ account_id: name.gsub(/[^a-z]/, ""), # XXX this mangling isn't required in the console, so why is it here?
98
101
  service_account: MU::Cloud::Google.iam(:ServiceAccount).new(
99
102
  display_name: rolename,
100
103
  # do NOT specify project_id or name, we know that much
101
104
  )
102
105
  )
103
- resp = MU::Cloud::Google.iam.create_service_account(
106
+
107
+ resp = MU::Cloud::Google.iam(credentials: credentials).create_service_account(
104
108
  "projects/#{project}",
105
109
  saobj
106
110
  )
111
+
107
112
  MU::Cloud::Google.compute(:ServiceAccount).new(
108
113
  email: resp.email,
109
114
  scopes: scopes
@@ -115,17 +120,17 @@ module MU
115
120
  # the latest version, if applicable.
116
121
  # @param image_id [String]: URL to a Google disk image
117
122
  # @return [Google::Apis::ComputeBeta::Image]
118
- def self.fetchImage(image_id)
123
+ def self.fetchImage(image_id, credentials: nil)
119
124
  img_proj = img_name = nil
120
125
  begin
121
126
  img_proj = image_id.gsub(/.*?\/?projects\/([^\/]+)\/.*/, '\1')
122
127
  img_name = image_id.gsub(/.*?([^\/]+)$/, '\1')
123
- img = MU::Cloud::Google.compute.get_image(img_proj, img_name)
128
+ img = MU::Cloud::Google.compute(credentials: credentials).get_image(img_proj, img_name)
124
129
  if !img.deprecated.nil? and !img.deprecated.replacement.nil?
125
130
  image_id = img.deprecated.replacement
126
131
  end
127
132
  end while !img.deprecated.nil? and img.deprecated.state == "DEPRECATED" and !img.deprecated.replacement.nil?
128
- MU::Cloud::Google.compute.get_image(img_proj, img_name)
133
+ MU::Cloud::Google.compute(credentials: credentials).get_image(img_proj, img_name)
129
134
  end
130
135
 
131
136
  # Generator for disk configuration parameters for a Compute instance
@@ -133,12 +138,14 @@ module MU
133
138
  # @param create [Boolean]: Actually create extra (non-root) disks, or just the one declared as the root disk of the image
134
139
  # @param disk_as_url [Boolean]: Whether to declare the disk type as a short string or full URL, which can vary depending on the calling resource
135
140
  # @return [Array]: The Compute :AttachedDisk objects describing disks that've been created
136
- def self.diskConfig(config, create = true, disk_as_url = true)
141
+ def self.diskConfig(config, create = true, disk_as_url = true, credentials: nil)
137
142
  disks = []
138
- puts config['image_id']
139
- puts config['basis']
143
+ if config['image_id'].nil? and config['basis'].nil?
144
+ pp config.keys
145
+ raise MuError, "Can't generate disk configuration for server #{config['name']} without an image ID or basis specified"
146
+ end
140
147
 
141
- img = fetchImage(config['image_id'] || config['basis']['launch_config']['image_id'])
148
+ img = fetchImage(config['image_id'] || config['basis']['launch_config']['image_id'], credentials: credentials)
142
149
 
143
150
  # XXX slurp settings from /dev/sda or w/e by convention?
144
151
  disktype = "projects/#{config['project']}/zones/#{config['availability_zone']}/diskTypes/pd-standard"
@@ -189,7 +196,7 @@ next if !create
189
196
  )
190
197
  MU.log "Creating disk #{diskname}", details: newdiskobj
191
198
 
192
- newdisk = MU::Cloud::Google.compute.insert_disk(
199
+ newdisk = MU::Cloud::Google.compute(credentials: credentials).insert_disk(
193
200
  config['project'],
194
201
  config['availability_zone'],
195
202
  newdiskobj
@@ -239,12 +246,14 @@ next if !create
239
246
 
240
247
  service_acct = MU::Cloud::Google::Server.createServiceAccount(
241
248
  @mu_name.downcase,
242
- project: @config['project']
249
+ @deploy,
250
+ project: @config['project'],
251
+ credentials: @config['credentials']
243
252
  )
244
- MU::Cloud::Google.grantDeploySecretAccess(service_acct.email)
253
+ MU::Cloud::Google.grantDeploySecretAccess(service_acct.email, credentials: @config['credentials'])
245
254
 
246
255
  begin
247
- disks = MU::Cloud::Google::Server.diskConfig(@config)
256
+ disks = MU::Cloud::Google::Server.diskConfig(@config, credentials: @config['credentials'])
248
257
  interfaces = MU::Cloud::Google::Server.interfaceConfig(@config, @vpc)
249
258
 
250
259
  if @config['routes']
@@ -291,16 +300,20 @@ next if !create
291
300
 
292
301
  MU.log "Creating instance #{@mu_name}"
293
302
  begin
294
- instance = MU::Cloud::Google.compute.insert_instance(
295
- @config['project'],
296
- @config['availability_zone'],
297
- instanceobj
298
- )
303
+ instance = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_instance(
304
+ @config['project'],
305
+ @config['availability_zone'],
306
+ instanceobj
307
+ )
308
+ if instance and instance.name
309
+ @cloud_id = instance.name
310
+ else
311
+ sleep 10
312
+ end
299
313
  rescue ::Google::Apis::ClientError => e
300
314
  MU.log e.message, MU::ERR
301
315
  raise e
302
- end
303
- @cloud_id = instance.name # XXX or instance.target_link... pick a convention, would you?
316
+ end while @cloud_id.nil?
304
317
 
305
318
  if !@config['async_groom']
306
319
  sleep 5
@@ -331,7 +344,7 @@ next if !create
331
344
  parent_thread_id = Thread.current.object_id
332
345
  Thread.new {
333
346
  MU.dupGlobals(parent_thread_id)
334
- MU::Cloud::Google::Server.cleanup(noop: false, ignoremaster: false, skipsnapshots: true)
347
+ MU::Cloud::Google::Server.cleanup(noop: false, ignoremaster: false, flags: { "skipsnapshots" => true } )
335
348
  }
336
349
  end
337
350
  end
@@ -365,7 +378,7 @@ next if !create
365
378
  # Ask the Google API to stop this node
366
379
  def stop
367
380
  MU.log "Stopping #{@cloud_id}"
368
- MU::Cloud::Google.compute.stop_instance(
381
+ MU::Cloud::Google.compute(credentials: @config['credentials']).stop_instance(
369
382
  @config['project'],
370
383
  @config['availability_zone'],
371
384
  @cloud_id
@@ -378,7 +391,7 @@ next if !create
378
391
  # Ask the Google API to start this node
379
392
  def start
380
393
  MU.log "Starting #{@cloud_id}"
381
- MU::Cloud::Google.compute.start_instance(
394
+ MU::Cloud::Google.compute(credentials: @config['credentials']).start_instance(
382
395
  @config['project'],
383
396
  @config['availability_zone'],
384
397
  @cloud_id
@@ -389,49 +402,10 @@ next if !create
389
402
  end
390
403
 
391
404
  # Ask the Google API to restart this node
405
+ # XXX unimplemented
392
406
  def reboot(hard = false)
393
407
  return if @cloud_id.nil?
394
408
 
395
- if hard
396
- groupname = nil
397
- if !@config['basis'].nil?
398
- resp = MU::Cloud::AWS.autoscale(@config['region']).describe_auto_scaling_instances(
399
- instance_ids: [@cloud_id]
400
- )
401
- groupname = resp.auto_scaling_instances.first.auto_scaling_group_name
402
- MU.log "Pausing Autoscale processes in #{groupname}", MU::NOTICE
403
- MU::Cloud::AWS.autoscale(@config['region']).suspend_processes(
404
- auto_scaling_group_name: groupname
405
- )
406
- end
407
- begin
408
- MU.log "Stopping #{@mu_name} (#{@cloud_id})", MU::NOTICE
409
- MU::Cloud::AWS.ec2(@config['region']).stop_instances(
410
- instance_ids: [@cloud_id]
411
- )
412
- MU::Cloud::AWS.ec2(@config['region']).wait_until(:instance_stopped, instance_ids: [@cloud_id]) do |waiter|
413
- waiter.before_attempt do |attempts|
414
- MU.log "Waiting for #{@mu_name} to stop for hard reboot"
415
- end
416
- end
417
- MU.log "Starting #{@mu_name} (#{@cloud_id})"
418
- MU::Cloud::AWS.ec2(@config['region']).start_instances(
419
- instance_ids: [@cloud_id]
420
- )
421
- ensure
422
- if !groupname.nil?
423
- MU.log "Resuming Autoscale processes in #{groupname}", MU::NOTICE
424
- MU::Cloud::AWS.autoscale(@config['region']).resume_processes(
425
- auto_scaling_group_name: groupname
426
- )
427
- end
428
- end
429
- else
430
- MU.log "Rebooting #{@mu_name} (#{@cloud_id})"
431
- MU::Cloud::AWS.ec2(@config['region']).reboot_instances(
432
- instance_ids: [@cloud_id]
433
- )
434
- end
435
409
  end
436
410
 
437
411
  # Figure out what's needed to SSH into this server.
@@ -444,7 +418,7 @@ next if !create
444
418
  return nil if @config.nil? or @deploy.nil?
445
419
 
446
420
  nat_ssh_key = nat_ssh_user = nat_ssh_host = nil
447
- if !@config["vpc"].nil? and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'])
421
+ if !@config["vpc"].nil? and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'], credentials: @config['credentials'])
448
422
 
449
423
  if !@nat.nil?
450
424
  if @nat.cloud_desc.nil?
@@ -576,255 +550,11 @@ next if !create
576
550
  end
577
551
 
578
552
  nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name = getSSHConfig
579
- if !nat_ssh_host and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'])
553
+ if !nat_ssh_host and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'], credentials: @config['credentials'])
580
554
  # XXX check if canonical_ip is in the private ranges
581
555
  # raise MuError, "#{node} has no NAT host configured, and I have no other route to it"
582
556
  end
583
557
 
584
- # # Set console termination protection. Autoscale nodes won't set this
585
- # # by default.
586
- # MU::Cloud::AWS.ec2(@config['region']).modify_instance_attribute(
587
- # instance_id: @cloud_id,
588
- # disable_api_termination: {:value => true}
589
- # )
590
-
591
- #MU.log "Let's deal with addressing", MU::WARN, details: cloud_desc
592
- # If we asked for a public IP address, make sure we get one
593
- # addrobj = MU::Cloud::Google.compute(:Address).new(
594
- # name: @mu_name+"-public-ip",
595
- # description: @deploy.deploy_id
596
- # )
597
- # addr_insert = MU::Cloud::Google.compute.insert_global_address(
598
- # @config['project'],
599
- ## @config['region'],
600
- # addrobj
601
- # )
602
- # pp addr_insert
603
- # raise "BOOP"
604
- # has_elastic_ip = false
605
- # if !instance.public_ip_address.nil?
606
- # begin
607
- # resp = MU::Cloud::AWS.ec2((@config['region'])).describe_addresses(public_ips: [instance.public_ip_address])
608
- # if resp.addresses.size > 0 and resp.addresses.first.instance_id == @cloud_id
609
- # has_elastic_ip = true
610
- # end
611
- # rescue Aws::EC2::Errors::InvalidAddressNotFound => e
612
- # # XXX this is ok to ignore, it means the public IP isn't Elastic
613
- # end
614
- # end
615
-
616
- # win_admin_password = nil
617
- # ec2config_password = nil
618
- # sshd_password = nil
619
- # if windows?
620
- # ssh_keydir = "#{Etc.getpwuid(Process.uid).dir}/.ssh"
621
- # ssh_key_name = @deploy.ssh_key_name
622
- #
623
- # if @config['use_cloud_provider_windows_password']
624
- # win_admin_password = getWindowsAdminPassword
625
- # elsif @config['windows_auth_vault'] && !@config['windows_auth_vault'].empty?
626
- # if @config["windows_auth_vault"].has_key?("password_field")
627
- # win_admin_password = @groomer.getSecret(
628
- # vault: @config['windows_auth_vault']['vault'],
629
- # item: @config['windows_auth_vault']['item'],
630
- # field: @config["windows_auth_vault"]["password_field"]
631
- # )
632
- # else
633
- # win_admin_password = getWindowsAdminPassword
634
- # end
635
- #
636
- # if @config["windows_auth_vault"].has_key?("ec2config_password_field")
637
- # ec2config_password = @groomer.getSecret(
638
- # vault: @config['windows_auth_vault']['vault'],
639
- # item: @config['windows_auth_vault']['item'],
640
- # field: @config["windows_auth_vault"]["ec2config_password_field"]
641
- # )
642
- # end
643
- #
644
- # if @config["windows_auth_vault"].has_key?("sshd_password_field")
645
- # sshd_password = @groomer.getSecret(
646
- # vault: @config['windows_auth_vault']['vault'],
647
- # item: @config['windows_auth_vault']['item'],
648
- # field: @config["windows_auth_vault"]["sshd_password_field"]
649
- # )
650
- # end
651
- # end
652
- #
653
- # win_admin_password = MU.generateWindowsPassword if win_admin_password.nil?
654
- # ec2config_password = MU.generateWindowsPassword if ec2config_password.nil?
655
- # sshd_password = MU.generateWindowsPassword if sshd_password.nil?
656
- #
657
- # # We're creating the vault here so when we run
658
- # # MU::Cloud::Server.initialSSHTasks and we need to set the Windows
659
- # # Admin password we can grab it from said vault.
660
- # creds = {
661
- # "username" => @config['windows_admin_username'],
662
- # "password" => win_admin_password,
663
- # "ec2config_username" => "ec2config",
664
- # "ec2config_password" => ec2config_password,
665
- # "sshd_username" => "sshd_service",
666
- # "sshd_password" => sshd_password
667
- # }
668
- # @groomer.saveSecret(vault: @mu_name, item: "windows_credentials", data: creds, permissions: "name:#{@mu_name}")
669
- # end
670
- #
671
- #
672
- #
673
- # # If we've asked for additional subnets (and this @config is not a
674
- # # member of a Server Pool, which has different semantics), create
675
- # # extra interfaces to accomodate.
676
- # if !@config['vpc']['subnets'].nil? and @config['basis'].nil?
677
- # device_index = 1
678
- # @vpc.subnets { |subnet|
679
- # subnet_id = subnet.cloud_id
680
- # MU.log "Adding network interface on subnet #{subnet_id} for #{node}"
681
- # iface = MU::Cloud::AWS.ec2(@config['region']).create_network_interface(subnet_id: subnet_id).network_interface
682
- # MU::MommaCat.createStandardTags(iface.network_interface_id, region: @config['region'])
683
- # MU::MommaCat.createTag(iface.network_interface_id, "Name", node+"-ETH"+device_index.to_s, region: @config['region'])
684
- #
685
- # if @config['optional_tags']
686
- # MU::MommaCat.listOptionalTags.each { |key, value|
687
- # MU::MommaCat.createTag(iface.network_interface_id, key, value, region: @config['region'])
688
- # }
689
- # end
690
- #
691
- # if !@config['tags'].nil?
692
- # @config['tags'].each { |tag|
693
- # MU::MommaCat.createTag(iface.network_interface_id, tag['key'], tag['value'], region: @config['region'])
694
- # }
695
- # end
696
- #
697
- # MU::Cloud::AWS.ec2(@config['region']).attach_network_interface(
698
- # network_interface_id: iface.network_interface_id,
699
- # instance_id: @cloud_id,
700
- # device_index: device_index
701
- # )
702
- # device_index = device_index + 1
703
- # }
704
- # end
705
- # elsif !@config['static_ip'].nil?
706
- # if !@config['static_ip']['ip'].nil?
707
- # public_ip = MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: true, ip: @config['static_ip']['ip'])
708
- # elsif !has_elastic_ip
709
- # public_ip = MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: true)
710
- # end
711
- # end
712
- #
713
- #
714
- # if !@config['image_then_destroy']
715
- # notify
716
- # end
717
- #
718
- # MU.log "EC2 instance #{node} has id #{@cloud_id}", MU::DEBUG
719
- #
720
- # @config["private_dns_name"] = instance.private_dns_name
721
- # @config["public_dns_name"] = instance.public_dns_name
722
- # @config["private_ip_address"] = instance.private_ip_address
723
- # @config["public_ip_address"] = instance.public_ip_address
724
- #
725
- # ext_mappings = MU.structToHash(instance.block_device_mappings)
726
- #
727
- # # Root disk on standard CentOS AMI
728
- # # tagVolumes(@cloud_id, "/dev/sda", "Name", "ROOT-"+MU.deploy_id+"-"+@config["name"].upcase)
729
- # # Root disk on standard Ubuntu AMI
730
- # # tagVolumes(@cloud_id, "/dev/sda1", "Name", "ROOT-"+MU.deploy_id+"-"+@config["name"].upcase)
731
- #
732
- # # Generic deploy ID tag
733
- # # tagVolumes(@cloud_id)
734
- #
735
- # # Tag volumes with all our standard tags.
736
- # # Maybe replace tagVolumes with this? There is one more place tagVolumes is called from
737
- # volumes = MU::Cloud::AWS.ec2(@config['region']).describe_volumes(filters: [name: "attachment.instance-id", values: [@cloud_id]])
738
- # volumes.each { |vol|
739
- # vol.volumes.each { |volume|
740
- # volume.attachments.each { |attachment|
741
- # MU::MommaCat.listStandardTags.each_pair { |key, value|
742
- # MU::MommaCat.createTag(attachment.volume_id, key, value, region: @config['region'])
743
- #
744
- # if attachment.device == "/dev/sda" or attachment.device == "/dev/sda1"
745
- # MU::MommaCat.createTag(attachment.volume_id, "Name", "ROOT-#{MU.deploy_id}-#{@config["name"].upcase}", region: @config['region'])
746
- # else
747
- # MU::MommaCat.createTag(attachment.volume_id, "Name", "#{MU.deploy_id}-#{@config["name"].upcase}-#{attachment.device.upcase}", region: @config['region'])
748
- # end
749
- # }
750
- #
751
- # if @config['optional_tags']
752
- # MU::MommaCat.listOptionalTags.each { |key, value|
753
- # MU::MommaCat.createTag(attachment.volume_id, key, value, region: @config['region'])
754
- # }
755
- # end
756
- #
757
- # if @config['tags']
758
- # @config['tags'].each { |tag|
759
- # MU::MommaCat.createTag(attachment.volume_id, tag['key'], tag['value'], region: @config['region'])
760
- # }
761
- # end
762
- # }
763
- # }
764
- # }
765
- #
766
- # canonical_name = instance.public_dns_name
767
- # canonical_name = instance.private_dns_name if !canonical_name or nat_ssh_host != nil
768
- # @config['canonical_name'] = canonical_name
769
- #
770
- # if !@config['add_private_ips'].nil?
771
- # instance.network_interfaces.each { |int|
772
- # if int.private_ip_address == instance.private_ip_address and int.private_ip_addresses.size < (@config['add_private_ips'] + 1)
773
- # MU.log "Adding #{@config['add_private_ips']} extra private IP addresses to #{@cloud_id}"
774
- # MU::Cloud::AWS.ec2(@config['region']).assign_private_ip_addresses(
775
- # network_interface_id: int.network_interface_id,
776
- # secondary_private_ip_address_count: @config['add_private_ips'],
777
- # allow_reassignment: false
778
- # )
779
- # end
780
- # }
781
- # notify
782
- # end
783
- #
784
- # windows? ? ssh_wait = 60 : ssh_wait = 30
785
- # windows? ? max_retries = 50 : max_retries = 35
786
- # begin
787
- # session = getSSHSession(max_retries, ssh_wait)
788
- # initialSSHTasks(session)
789
- # rescue BootstrapTempFail
790
- # sleep ssh_wait
791
- # retry
792
- # ensure
793
- # session.close if !session.nil?
794
- # end
795
- #
796
- # if @config["existing_deploys"] && !@config["existing_deploys"].empty?
797
- # @config["existing_deploys"].each { |ext_deploy|
798
- # if ext_deploy["cloud_id"]
799
- # found = MU::MommaCat.findStray(
800
- # @config['cloud'],
801
- # ext_deploy["cloud_type"],
802
- # cloud_id: ext_deploy["cloud_id"],
803
- # region: @config['region'],
804
- # dummy_ok: false
805
- # ).first
806
- #
807
- # MU.log "Couldn't find existing resource #{ext_deploy["cloud_id"]}, #{ext_deploy["cloud_type"]}", MU::ERR if found.nil?
808
- # @deploy.notify(ext_deploy["cloud_type"], found.config["name"], found.deploydata, mu_name: found.mu_name, triggering_node: @mu_name)
809
- # elsif ext_deploy["mu_name"] && ext_deploy["deploy_id"]
810
- # MU.log "#{ext_deploy["mu_name"]} / #{ext_deploy["deploy_id"]}"
811
- # found = MU::MommaCat.findStray(
812
- # @config['cloud'],
813
- # ext_deploy["cloud_type"],
814
- # deploy_id: ext_deploy["deploy_id"],
815
- # mu_name: ext_deploy["mu_name"],
816
- # region: @config['region'],
817
- # dummy_ok: false
818
- # ).first
819
- #
820
- # MU.log "Couldn't find existing resource #{ext_deploy["mu_name"]}/#{ext_deploy["deploy_id"]}, #{ext_deploy["cloud_type"]}", MU::ERR if found.nil?
821
- # @deploy.notify(ext_deploy["cloud_type"], found.config["name"], found.deploydata, mu_name: ext_deploy["mu_name"], triggering_node: @mu_name)
822
- # else
823
- # MU.log "Trying to find existing deploy, but either the cloud_id is not valid or no mu_name and deploy_id where provided", MU::ERR
824
- # end
825
- # }
826
- # end
827
-
828
558
  # See if this node already exists in our config management. If it does,
829
559
  # we're done.
830
560
  if @groomer.haveBootstrapped?
@@ -856,10 +586,10 @@ next if !create
856
586
  # @param ip [String]: An IP address associated with the instance
857
587
  # @param flags [Hash]: Optional flags
858
588
  # @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching instances
859
- def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, ip: nil, flags: {})
589
+ def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, ip: nil, flags: {}, credentials: nil)
860
590
  # XXX put that 'ip' value into flags
861
591
  instance = nil
862
- flags["project"] ||= MU::Cloud::Google.defaultProject
592
+ flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
863
593
  if !region.nil? and MU::Cloud::Google.listRegions.include?(region)
864
594
  regions = [region]
865
595
  else
@@ -881,7 +611,7 @@ next if !create
881
611
  MU::Cloud::Google.listAZs(region).each { |az|
882
612
  resp = nil
883
613
  begin
884
- resp = MU::Cloud::Google.compute.get_instance(
614
+ resp = MU::Cloud::Google.compute(credentials: credentials).get_instance(
885
615
  flags["project"],
886
616
  az,
887
617
  cloud_id
@@ -1065,13 +795,14 @@ next if !create
1065
795
  exclude_storage: img_cfg['image_exclude_storage'],
1066
796
  make_public: img_cfg['public'],
1067
797
  tags: @config['tags'],
1068
- zone: @config['availability_zone']
798
+ zone: @config['availability_zone'],
799
+ credentials: @config['credentials']
1069
800
  )
1070
801
  @deploy.notify("images", @config['name'], {"image_id" => image_id})
1071
802
  @config['image_created'] = true
1072
803
  if img_cfg['image_then_destroy']
1073
804
  MU.log "Image #{image_id} ready, removing source node #{node}"
1074
- MU::Cloud::Google.compute.delete_instance(
805
+ MU::Cloud::Google.compute(credentials: @config['credentials']).delete_instance(
1075
806
  @config['project'],
1076
807
  @config['availability_zone'],
1077
808
  @cloud_id
@@ -1093,7 +824,8 @@ next if !create
1093
824
  # @param region [String]: The cloud provider region
1094
825
  # @param tags [Array<String>]: Extra/override tags to apply to the image.
1095
826
  # @return [String]: The cloud provider identifier of the new machine image.
1096
- def self.createImage(name: nil, instance_id: nil, storage: {}, exclude_storage: false, project: MU::Cloud::Google.defaultProject, make_public: false, tags: [], region: nil, family: "mu", zone: MU::Cloud::Google.listAZs.sample)
827
+ def self.createImage(name: nil, instance_id: nil, storage: {}, exclude_storage: false, project: nil, make_public: false, tags: [], region: nil, family: "mu", zone: MU::Cloud::Google.listAZs.sample, credentials: nil)
828
+ project ||= MU::Cloud::Google.defaultProject(credentials)
1097
829
  instance = MU::Cloud::Server.find(cloud_id: instance_id, region: region)
1098
830
  if instance.nil?
1099
831
  raise MuError, "Failed to find instance '#{instance_id}' in createImage"
@@ -1122,13 +854,13 @@ next if !create
1122
854
  )
1123
855
  diskname = disk.source.gsub(/.*?\//, "")
1124
856
  MU.log "Creating snapshot of #{diskname} in #{zone}", MU::NOTICE, details: snapobj
1125
- snap = MU::Cloud::Google.compute.create_disk_snapshot(
857
+ snap = MU::Cloud::Google.compute(credentials: credentials).create_disk_snapshot(
1126
858
  project,
1127
859
  zone,
1128
860
  diskname,
1129
861
  snapobj
1130
862
  )
1131
- MU::Cloud::Google.compute.set_snapshot_labels(
863
+ MU::Cloud::Google.compute(credentials: credentials).set_snapshot_labels(
1132
864
  project,
1133
865
  snap.name,
1134
866
  MU::Cloud::Google.compute(:GlobalSetLabelsRequest).new(
@@ -1156,36 +888,36 @@ next if !create
1156
888
  family: family
1157
889
  )
1158
890
 
1159
- newimage = MU::Cloud::Google.compute.insert_image(
891
+ newimage = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_image(
1160
892
  project,
1161
893
  imageobj
1162
894
  )
1163
895
  newimage.name
1164
896
  end
1165
897
 
1166
- def cloud_desc
1167
- max_retries = 5
1168
- retries = 0
1169
- if !@cloud_id.nil?
1170
- begin
1171
- return MU::Cloud::Google.compute.get_instance(
1172
- @config['project'],
1173
- @config['availability_zone'],
1174
- @cloud_id
1175
- )
1176
- rescue ::Google::Apis::ClientError => e
1177
- if e.message.match(/^notFound: /)
1178
- return nil
1179
- else
1180
- raise e
1181
- end
1182
- end
1183
- end
1184
- nil
1185
- end
898
+ # def cloud_desc
899
+ # max_retries = 5
900
+ # retries = 0
901
+ # if !@cloud_id.nil?
902
+ # begin
903
+ # return MU::Cloud::Google.compute(credentials: @config['credentials']).get_instance(
904
+ # @config['project'],
905
+ # @config['availability_zone'],
906
+ # @cloud_id
907
+ # )
908
+ # rescue ::Google::Apis::ClientError => e
909
+ # if e.message.match(/^notFound: /)
910
+ # return nil
911
+ # else
912
+ # raise e
913
+ # end
914
+ # end
915
+ # end
916
+ # nil
917
+ # end
1186
918
 
1187
919
  def cloud_desc
1188
- MU::Cloud::Google::Server.find(cloud_id: @cloud_id).values.first
920
+ MU::Cloud::Google::Server.find(cloud_id: @cloud_id, credentials: @config['credentials']).values.first
1189
921
  end
1190
922
 
1191
923
  # Return the IP address that we, the Mu server, should be using to access
@@ -1214,7 +946,7 @@ next if !create
1214
946
  # Our deploydata gets corrupted often with server pools, this will cause us to use the wrong IP to identify a node
1215
947
  # which will cause us to create certificates, DNS records and other artifacts with incorrect information which will cause our deploy to fail.
1216
948
  # The cloud_id is always correct so lets use 'cloud_desc' to get the correct IPs
1217
- if MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc) or public_ips.size == 0
949
+ if MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, credentials: @config['credentials']) or public_ips.size == 0
1218
950
  @config['canonical_ip'] = private_ips.first
1219
951
  return private_ips.first
1220
952
  else
@@ -1223,8 +955,6 @@ next if !create
1223
955
  end
1224
956
  end
1225
957
 
1226
- # Retrieves the Cloud provider's randomly generated Windows password
1227
- # Will only work on stock Amazon Windows AMIs or custom AMIs that where created with Administrator Password set to random in EC2Config
1228
958
  # return [String]: A password string.
1229
959
  def getWindowsAdminPassword
1230
960
  end
@@ -1251,7 +981,7 @@ next if !create
1251
981
  )
1252
982
 
1253
983
  begin
1254
- newdisk = MU::Cloud::Google.compute.insert_disk(
984
+ newdisk = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_disk(
1255
985
  @config['project'],
1256
986
  @config['availability_zone'],
1257
987
  newdiskobj
@@ -1271,7 +1001,7 @@ next if !create
1271
1001
  source: newdisk.self_link,
1272
1002
  type: "PERSISTENT"
1273
1003
  )
1274
- attachment = MU::Cloud::Google.compute.attach_disk(
1004
+ attachment = MU::Cloud::Google.compute(credentials: @config['credentials']).attach_disk(
1275
1005
  @config['project'],
1276
1006
  @config['availability_zone'],
1277
1007
  @cloud_id,
@@ -1287,18 +1017,27 @@ next if !create
1287
1017
  true
1288
1018
  end
1289
1019
 
1020
+ # Does this resource type exist as a global (cloud-wide) artifact, or
1021
+ # is it localized to a region/zone?
1022
+ # @return [Boolean]
1023
+ def self.isGlobal?
1024
+ false
1025
+ end
1026
+
1290
1027
  # Remove all instances associated with the currently loaded deployment. Also cleans up associated volumes, droppings in the MU master's /etc/hosts and ~/.ssh, and in whatever Groomer was used.
1291
1028
  # @param noop [Boolean]: If true, will only print what would be done
1292
1029
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
1293
1030
  # @param region [String]: The cloud provider region
1294
1031
  # @return [void]
1295
- def self.cleanup(noop: false, ignoremaster: false, region: $MU_CFG['google']['region'], skipsnapshots: false, onlycloud: false, flags: {})
1296
- flags["project"] ||= MU::Cloud::Google.defaultProject
1032
+ def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
1033
+ flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
1034
+ skipsnapshots = flags["skipsnapshots"]
1035
+ onlycloud = flags["onlycloud"]
1297
1036
  # XXX make damn sure MU.deploy_id is set
1298
1037
 
1299
1038
  MU::Cloud::Google.listAZs(region).each { |az|
1300
1039
  disks = []
1301
- resp = MU::Cloud::Google.compute.list_instances(
1040
+ resp = MU::Cloud::Google.compute(credentials: credentials).list_instances(
1302
1041
  flags["project"],
1303
1042
  az,
1304
1043
  filter: "description eq #{MU.deploy_id}"
@@ -1312,14 +1051,14 @@ next if !create
1312
1051
  disks << disk if !disk.auto_delete
1313
1052
  }
1314
1053
  end
1315
- deletia = MU::Cloud::Google.compute.delete_instance(
1054
+ deletia = MU::Cloud::Google.compute(credentials: credentials).delete_instance(
1316
1055
  flags["project"],
1317
1056
  az,
1318
1057
  instance.name
1319
1058
  ) if !noop
1320
1059
  MU.log "Removing service account #{saname}"
1321
1060
  begin
1322
- MU::Cloud::Google.iam.delete_project_service_account(
1061
+ MU::Cloud::Google.iam(credentials: credentials).delete_project_service_account(
1323
1062
  "projects/#{flags["project"]}/serviceAccounts/#{saname}@#{flags["project"]}.iam.gserviceaccount.com"
1324
1063
  ) if !noop
1325
1064
  rescue ::Google::Apis::ClientError => e
@@ -1334,7 +1073,7 @@ next if !create
1334
1073
  # XXX make sure we don't miss anything that got created with dumb flags
1335
1074
  end
1336
1075
  # XXX honor snapshotting
1337
- MU::Cloud::Google.compute.delete(
1076
+ MU::Cloud::Google.compute(credentials: credentials).delete(
1338
1077
  "disk",
1339
1078
  flags["project"],
1340
1079
  az,
@@ -1456,7 +1195,7 @@ next if !create
1456
1195
 
1457
1196
  real_image = nil
1458
1197
  begin
1459
- real_image = MU::Cloud::Google::Server.fetchImage(server['image_id'].to_s)
1198
+ real_image = MU::Cloud::Google::Server.fetchImage(server['image_id'].to_s, credentials: server['credentials'])
1460
1199
  rescue ::Google::Apis::ClientError => e
1461
1200
  MU.log e.inspect, MU::WARN
1462
1201
  end
@@ -1470,7 +1209,7 @@ next if !create
1470
1209
  img_project = Regexp.last_match[1]
1471
1210
  img_name = Regexp.last_match[2]
1472
1211
  begin
1473
- snaps = MU::Cloud::Google.compute.list_snapshots(
1212
+ snaps = MU::Cloud::Google.compute(credentials: server['credentials']).list_snapshots(
1474
1213
  img_project,
1475
1214
  filter: "name eq #{img_name}-.*"
1476
1215
  )