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.
- checksums.yaml +4 -4
- data/Berksfile +16 -54
- data/Berksfile.lock +14 -62
- data/bin/mu-aws-setup +131 -108
- data/bin/mu-configure +311 -74
- data/bin/mu-gcp-setup +84 -62
- data/bin/mu-load-config.rb +46 -2
- data/bin/mu-self-update +11 -9
- data/bin/mu-upload-chef-artifacts +4 -4
- data/{mu.gemspec → cloud-mu.gemspec} +2 -2
- data/cookbooks/awscli/Berksfile +8 -0
- data/cookbooks/mu-activedirectory/Berksfile +11 -0
- data/cookbooks/mu-firewall/Berksfile +9 -0
- data/cookbooks/mu-firewall/metadata.rb +1 -1
- data/cookbooks/mu-glusterfs/Berksfile +10 -0
- data/cookbooks/mu-jenkins/Berksfile +14 -0
- data/cookbooks/mu-master/Berksfile +23 -0
- data/cookbooks/mu-master/attributes/default.rb +1 -1
- data/cookbooks/mu-master/metadata.rb +2 -2
- data/cookbooks/mu-master/recipes/default.rb +1 -1
- data/cookbooks/mu-master/recipes/init.rb +7 -3
- data/cookbooks/mu-master/recipes/ssl-certs.rb +1 -0
- data/cookbooks/mu-mongo/Berksfile +10 -0
- data/cookbooks/mu-openvpn/Berksfile +11 -0
- data/cookbooks/mu-php54/Berksfile +13 -0
- data/cookbooks/mu-splunk/Berksfile +10 -0
- data/cookbooks/mu-tools/Berksfile +21 -0
- data/cookbooks/mu-tools/files/default/Mu_CA.pem +15 -15
- data/cookbooks/mu-utility/Berksfile +9 -0
- data/cookbooks/mu-utility/metadata.rb +2 -1
- data/cookbooks/nagios/Berksfile +7 -4
- data/cookbooks/s3fs/Berksfile +9 -0
- data/environments/dev.json +6 -6
- data/environments/prod.json +6 -6
- data/modules/mu.rb +20 -42
- data/modules/mu/cleanup.rb +102 -100
- data/modules/mu/cloud.rb +90 -28
- data/modules/mu/clouds/aws.rb +449 -218
- data/modules/mu/clouds/aws/alarm.rb +29 -17
- data/modules/mu/clouds/aws/cache_cluster.rb +78 -64
- data/modules/mu/clouds/aws/collection.rb +25 -18
- data/modules/mu/clouds/aws/container_cluster.rb +73 -66
- data/modules/mu/clouds/aws/database.rb +124 -116
- data/modules/mu/clouds/aws/dnszone.rb +27 -20
- data/modules/mu/clouds/aws/firewall_rule.rb +30 -22
- data/modules/mu/clouds/aws/folder.rb +18 -3
- data/modules/mu/clouds/aws/function.rb +77 -23
- data/modules/mu/clouds/aws/group.rb +19 -12
- data/modules/mu/clouds/aws/habitat.rb +153 -0
- data/modules/mu/clouds/aws/loadbalancer.rb +59 -52
- data/modules/mu/clouds/aws/log.rb +30 -23
- data/modules/mu/clouds/aws/msg_queue.rb +29 -20
- data/modules/mu/clouds/aws/notifier.rb +222 -0
- data/modules/mu/clouds/aws/role.rb +178 -90
- data/modules/mu/clouds/aws/search_domain.rb +40 -24
- data/modules/mu/clouds/aws/server.rb +169 -137
- data/modules/mu/clouds/aws/server_pool.rb +60 -83
- data/modules/mu/clouds/aws/storage_pool.rb +59 -31
- data/modules/mu/clouds/aws/user.rb +36 -27
- data/modules/mu/clouds/aws/userdata/linux.erb +101 -93
- data/modules/mu/clouds/aws/vpc.rb +250 -189
- data/modules/mu/clouds/azure.rb +132 -0
- data/modules/mu/clouds/cloudformation.rb +65 -1
- data/modules/mu/clouds/cloudformation/alarm.rb +8 -0
- data/modules/mu/clouds/cloudformation/cache_cluster.rb +7 -0
- data/modules/mu/clouds/cloudformation/collection.rb +7 -0
- data/modules/mu/clouds/cloudformation/database.rb +7 -0
- data/modules/mu/clouds/cloudformation/dnszone.rb +7 -0
- data/modules/mu/clouds/cloudformation/firewall_rule.rb +9 -2
- data/modules/mu/clouds/cloudformation/loadbalancer.rb +7 -0
- data/modules/mu/clouds/cloudformation/log.rb +7 -0
- data/modules/mu/clouds/cloudformation/server.rb +7 -0
- data/modules/mu/clouds/cloudformation/server_pool.rb +7 -0
- data/modules/mu/clouds/cloudformation/vpc.rb +7 -0
- data/modules/mu/clouds/google.rb +214 -110
- data/modules/mu/clouds/google/container_cluster.rb +42 -24
- data/modules/mu/clouds/google/database.rb +15 -6
- data/modules/mu/clouds/google/firewall_rule.rb +17 -25
- data/modules/mu/clouds/google/group.rb +13 -5
- data/modules/mu/clouds/google/habitat.rb +105 -0
- data/modules/mu/clouds/google/loadbalancer.rb +28 -20
- data/modules/mu/clouds/google/server.rb +93 -354
- data/modules/mu/clouds/google/server_pool.rb +18 -10
- data/modules/mu/clouds/google/user.rb +22 -14
- data/modules/mu/clouds/google/vpc.rb +97 -69
- data/modules/mu/config.rb +133 -38
- data/modules/mu/config/alarm.rb +25 -0
- data/modules/mu/config/cache_cluster.rb +5 -3
- data/modules/mu/config/cache_cluster.yml +23 -0
- data/modules/mu/config/database.rb +25 -16
- data/modules/mu/config/database.yml +3 -3
- data/modules/mu/config/function.rb +1 -2
- data/modules/mu/config/{project.rb → habitat.rb} +10 -10
- data/modules/mu/config/notifier.rb +85 -0
- data/modules/mu/config/notifier.yml +9 -0
- data/modules/mu/config/role.rb +1 -1
- data/modules/mu/config/search_domain.yml +2 -2
- data/modules/mu/config/server.rb +13 -1
- data/modules/mu/config/server.yml +3 -3
- data/modules/mu/config/server_pool.rb +3 -1
- data/modules/mu/config/storage_pool.rb +3 -1
- data/modules/mu/config/storage_pool.yml +19 -0
- data/modules/mu/config/vpc.rb +70 -8
- data/modules/mu/groomers/chef.rb +2 -3
- data/modules/mu/kittens.rb +500 -122
- data/modules/mu/master.rb +5 -5
- data/modules/mu/mommacat.rb +151 -91
- data/modules/tests/super_complex_bok.yml +12 -0
- data/modules/tests/super_simple_bok.yml +12 -0
- data/spec/mu/clouds/azure_spec.rb +82 -0
- data/spec/spec_helper.rb +105 -0
- metadata +26 -5
- data/modules/mu/clouds/aws/notification.rb +0 -139
- 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
|
-
|
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 =
|
97
|
+
name = deploy.getResourceName(rolename, max_length: 30).downcase
|
95
98
|
|
96
99
|
saobj = MU::Cloud::Google.iam(:CreateServiceAccountRequest).new(
|
97
|
-
account_id:
|
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
|
-
|
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
|
-
|
139
|
-
|
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
|
-
|
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
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
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,
|
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:
|
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:
|
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
|
)
|