cloud-mu 3.1.6 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/mu-adopt +4 -12
- data/bin/mu-azure-tests +57 -0
- data/bin/mu-cleanup +2 -4
- data/bin/mu-configure +37 -1
- data/bin/mu-deploy +3 -3
- data/bin/mu-findstray-tests +25 -0
- data/bin/mu-gen-docs +2 -4
- data/bin/mu-run-tests +23 -10
- data/cloud-mu.gemspec +2 -2
- data/cookbooks/mu-tools/libraries/helper.rb +1 -1
- data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
- data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
- data/extras/generate-stock-images +1 -0
- data/modules/mu.rb +82 -95
- data/modules/mu/adoption.rb +356 -56
- data/modules/mu/cleanup.rb +21 -20
- data/modules/mu/cloud.rb +79 -1753
- data/modules/mu/cloud/database.rb +49 -0
- data/modules/mu/cloud/dnszone.rb +46 -0
- data/modules/mu/cloud/machine_images.rb +212 -0
- data/modules/mu/cloud/providers.rb +81 -0
- data/modules/mu/cloud/resource_base.rb +920 -0
- data/modules/mu/cloud/server.rb +40 -0
- data/modules/mu/cloud/server_pool.rb +1 -0
- data/modules/mu/cloud/ssh_sessions.rb +228 -0
- data/modules/mu/cloud/winrm_sessions.rb +237 -0
- data/modules/mu/cloud/wrappers.rb +165 -0
- data/modules/mu/config.rb +122 -80
- data/modules/mu/config/alarm.rb +2 -6
- data/modules/mu/config/bucket.rb +1 -1
- data/modules/mu/config/cache_cluster.rb +1 -1
- data/modules/mu/config/collection.rb +1 -1
- data/modules/mu/config/container_cluster.rb +2 -2
- data/modules/mu/config/database.rb +83 -104
- data/modules/mu/config/database.yml +1 -2
- data/modules/mu/config/dnszone.rb +1 -1
- data/modules/mu/config/doc_helpers.rb +4 -5
- data/modules/mu/config/endpoint.rb +1 -1
- data/modules/mu/config/firewall_rule.rb +3 -19
- data/modules/mu/config/folder.rb +1 -1
- data/modules/mu/config/function.rb +1 -1
- data/modules/mu/config/group.rb +1 -1
- data/modules/mu/config/habitat.rb +1 -1
- data/modules/mu/config/loadbalancer.rb +57 -11
- data/modules/mu/config/log.rb +1 -1
- data/modules/mu/config/msg_queue.rb +1 -1
- data/modules/mu/config/nosqldb.rb +1 -1
- data/modules/mu/config/notifier.rb +1 -1
- data/modules/mu/config/ref.rb +30 -4
- data/modules/mu/config/role.rb +1 -1
- data/modules/mu/config/schema_helpers.rb +30 -34
- data/modules/mu/config/search_domain.rb +1 -1
- data/modules/mu/config/server.rb +4 -12
- data/modules/mu/config/server_pool.rb +3 -7
- data/modules/mu/config/storage_pool.rb +1 -1
- data/modules/mu/config/tail.rb +10 -0
- data/modules/mu/config/user.rb +1 -1
- data/modules/mu/config/vpc.rb +12 -17
- data/modules/mu/defaults/AWS.yaml +32 -32
- data/modules/mu/defaults/Azure.yaml +1 -0
- data/modules/mu/defaults/Google.yaml +1 -0
- data/modules/mu/deploy.rb +16 -15
- data/modules/mu/groomer.rb +15 -0
- data/modules/mu/groomers/chef.rb +3 -0
- data/modules/mu/logger.rb +120 -144
- data/modules/mu/master.rb +1 -1
- data/modules/mu/mommacat.rb +54 -25
- data/modules/mu/mommacat/daemon.rb +10 -7
- data/modules/mu/mommacat/naming.rb +82 -3
- data/modules/mu/mommacat/search.rb +47 -15
- data/modules/mu/mommacat/storage.rb +72 -41
- data/modules/mu/{clouds → providers}/README.md +1 -1
- data/modules/mu/{clouds → providers}/aws.rb +114 -47
- data/modules/mu/{clouds → providers}/aws/alarm.rb +1 -1
- data/modules/mu/{clouds → providers}/aws/bucket.rb +2 -2
- data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +10 -46
- data/modules/mu/{clouds → providers}/aws/collection.rb +3 -3
- data/modules/mu/{clouds → providers}/aws/container_cluster.rb +15 -33
- data/modules/mu/providers/aws/database.rb +1744 -0
- data/modules/mu/{clouds → providers}/aws/dnszone.rb +2 -5
- data/modules/mu/{clouds → providers}/aws/endpoint.rb +2 -11
- data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +33 -29
- data/modules/mu/{clouds → providers}/aws/folder.rb +0 -0
- data/modules/mu/{clouds → providers}/aws/function.rb +2 -10
- data/modules/mu/{clouds → providers}/aws/group.rb +9 -13
- data/modules/mu/{clouds → providers}/aws/habitat.rb +1 -1
- data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +41 -33
- data/modules/mu/{clouds → providers}/aws/log.rb +2 -2
- data/modules/mu/{clouds → providers}/aws/msg_queue.rb +2 -8
- data/modules/mu/{clouds → providers}/aws/nosqldb.rb +0 -0
- data/modules/mu/{clouds → providers}/aws/notifier.rb +0 -0
- data/modules/mu/{clouds → providers}/aws/role.rb +7 -7
- data/modules/mu/{clouds → providers}/aws/search_domain.rb +8 -13
- data/modules/mu/{clouds → providers}/aws/server.rb +55 -90
- data/modules/mu/{clouds → providers}/aws/server_pool.rb +10 -33
- data/modules/mu/{clouds → providers}/aws/storage_pool.rb +19 -36
- data/modules/mu/{clouds → providers}/aws/user.rb +8 -12
- data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/aws/vpc.rb +135 -70
- data/modules/mu/{clouds → providers}/aws/vpc_subnet.rb +0 -0
- data/modules/mu/{clouds → providers}/azure.rb +4 -1
- data/modules/mu/{clouds → providers}/azure/container_cluster.rb +1 -5
- data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +8 -1
- data/modules/mu/{clouds → providers}/azure/habitat.rb +0 -0
- data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +0 -0
- data/modules/mu/{clouds → providers}/azure/role.rb +0 -0
- data/modules/mu/{clouds → providers}/azure/server.rb +30 -23
- data/modules/mu/{clouds → providers}/azure/user.rb +1 -1
- data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/vpc.rb +4 -6
- data/modules/mu/{clouds → providers}/cloudformation.rb +1 -1
- data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
- data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
- data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
- data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +3 -3
- data/modules/mu/{clouds → providers}/docker.rb +0 -0
- data/modules/mu/{clouds → providers}/google.rb +14 -6
- data/modules/mu/{clouds → providers}/google/bucket.rb +1 -1
- data/modules/mu/{clouds → providers}/google/container_cluster.rb +28 -13
- data/modules/mu/{clouds → providers}/google/database.rb +1 -8
- data/modules/mu/{clouds → providers}/google/firewall_rule.rb +2 -2
- data/modules/mu/{clouds → providers}/google/folder.rb +4 -8
- data/modules/mu/{clouds → providers}/google/function.rb +3 -3
- data/modules/mu/{clouds → providers}/google/group.rb +8 -16
- data/modules/mu/{clouds → providers}/google/habitat.rb +3 -7
- data/modules/mu/{clouds → providers}/google/loadbalancer.rb +1 -1
- data/modules/mu/{clouds → providers}/google/role.rb +42 -34
- data/modules/mu/{clouds → providers}/google/server.rb +25 -10
- data/modules/mu/{clouds → providers}/google/server_pool.rb +10 -10
- data/modules/mu/{clouds → providers}/google/user.rb +31 -21
- data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/google/vpc.rb +37 -2
- data/modules/tests/centos6.yaml +11 -0
- data/modules/tests/centos7.yaml +11 -0
- data/modules/tests/centos8.yaml +12 -0
- data/modules/tests/rds.yaml +108 -0
- data/modules/tests/regrooms/rds.yaml +123 -0
- data/spec/mu/clouds/azure_spec.rb +2 -2
- metadata +108 -89
- data/modules/mu/clouds/aws/database.rb +0 -1974
data/modules/mu/master.rb
CHANGED
@@ -602,7 +602,7 @@ module MU
|
|
602
602
|
return
|
603
603
|
end
|
604
604
|
if ssh_key_name.nil? or ssh_key_name.empty?
|
605
|
-
MU.log "Failed to extract ssh_key_name for #{
|
605
|
+
MU.log "Failed to extract ssh_key_name for #{server.mu_name} in addHostToSSHConfig", MU::ERR
|
606
606
|
return
|
607
607
|
end
|
608
608
|
|
data/modules/mu/mommacat.rb
CHANGED
@@ -167,6 +167,7 @@ module MU
|
|
167
167
|
@need_deploy_flush = false
|
168
168
|
@node_cert_semaphore = Mutex.new
|
169
169
|
@deployment = deployment_data
|
170
|
+
|
170
171
|
@deployment['mu_public_ip'] = MU.mu_public_ip
|
171
172
|
@private_key = nil
|
172
173
|
@public_key = nil
|
@@ -182,6 +183,7 @@ module MU
|
|
182
183
|
@appname ||= @original_config['name'] if @original_config
|
183
184
|
@timestamp = timestamp
|
184
185
|
@environment = environment
|
186
|
+
@original_config['environment'] ||= @environment if @original_config
|
185
187
|
|
186
188
|
if set_context_to_me
|
187
189
|
MU::MommaCat.setThreadContext(self)
|
@@ -253,8 +255,7 @@ module MU
|
|
253
255
|
seen << resource['credentials']
|
254
256
|
else
|
255
257
|
cloudconst = @original_config['cloud'] ? @original_config['cloud'] : MU::Config.defaultCloud
|
256
|
-
|
257
|
-
seen << cloudclass.credConfig(name_only: true)
|
258
|
+
seen << MU::Cloud.cloudClass(cloudconst).credConfig(name_only: true)
|
258
259
|
end
|
259
260
|
}
|
260
261
|
end
|
@@ -289,11 +290,10 @@ module MU
|
|
289
290
|
habitats << hab_ref.id
|
290
291
|
end
|
291
292
|
elsif resource['cloud']
|
292
|
-
cloudclass = Object.const_get("MU").const_get("Cloud").const_get(resource['cloud'])
|
293
293
|
# XXX this should be a general method implemented by each cloud
|
294
294
|
# provider
|
295
295
|
if resource['cloud'] == "Google"
|
296
|
-
habitats <<
|
296
|
+
habitats << MU::Cloud.cloudClass(resource['cloud']).defaultProject(resource['credentials'])
|
297
297
|
end
|
298
298
|
end
|
299
299
|
}
|
@@ -317,13 +317,11 @@ module MU
|
|
317
317
|
if @original_config[type]
|
318
318
|
@original_config[type].each { |resource|
|
319
319
|
if resource['cloud']
|
320
|
-
|
321
|
-
resclass = Object.const_get("MU").const_get("Cloud").const_get(resource['cloud']).const_get(res_type.to_s)
|
322
|
-
if resclass.isGlobal?
|
320
|
+
if MU::Cloud.resourceClass(resource['cloud'], res_type).isGlobal?
|
323
321
|
# XXX why was I doing this, urgh
|
324
322
|
next
|
325
323
|
elsif !resource['region']
|
326
|
-
regions <<
|
324
|
+
regions << MU::Cloud.cloudClass(resource['cloud']).myRegion(resource['credentials'])
|
327
325
|
end
|
328
326
|
end
|
329
327
|
if resource['region']
|
@@ -401,7 +399,7 @@ module MU
|
|
401
399
|
# @param type [String]:
|
402
400
|
# @param name [String]:
|
403
401
|
# @param object [MU::Cloud]:
|
404
|
-
def addKitten(type, name, object)
|
402
|
+
def addKitten(type, name, object, do_notify: false)
|
405
403
|
if !type or !name or !object or !object.mu_name
|
406
404
|
raise MuError, "Nil arguments to addKitten are not allowed (got type: #{type}, name: #{name}, and '#{object}' to add)"
|
407
405
|
end
|
@@ -409,7 +407,7 @@ module MU
|
|
409
407
|
_shortclass, _cfg_name, type, _classname, attrs = MU::Cloud.getResourceNames(type)
|
410
408
|
object.intoDeploy(self)
|
411
409
|
|
412
|
-
|
410
|
+
add_block = Proc.new {
|
413
411
|
@kittens[type] ||= {}
|
414
412
|
@kittens[type][object.habitat] ||= {}
|
415
413
|
if attrs[:has_multiples]
|
@@ -418,7 +416,20 @@ module MU
|
|
418
416
|
else
|
419
417
|
@kittens[type][object.habitat][name] = object
|
420
418
|
end
|
419
|
+
if do_notify
|
420
|
+
notify(type, name, object.notify, triggering_node: object, delayed_save: true)
|
421
|
+
end
|
421
422
|
}
|
423
|
+
|
424
|
+
begin
|
425
|
+
@kitten_semaphore.synchronize {
|
426
|
+
add_block.call()
|
427
|
+
}
|
428
|
+
rescue ThreadError => e
|
429
|
+
# already locked by a parent call to this method, so this should be safe
|
430
|
+
raise e if !e.message.match(/recursive locking/)
|
431
|
+
add_block.call()
|
432
|
+
end
|
422
433
|
end
|
423
434
|
|
424
435
|
# Encrypt a string with the deployment's public key.
|
@@ -536,10 +547,9 @@ module MU
|
|
536
547
|
# @param remove [Boolean]: Remove this resource from the deploy structure, instead of adding it.
|
537
548
|
# @return [void]
|
538
549
|
def notify(type, key, data, mu_name: nil, remove: false, triggering_node: nil, delayed_save: false)
|
539
|
-
return if @no_artifacts
|
540
550
|
|
541
551
|
begin
|
542
|
-
MU::MommaCat.lock("deployment-notification")
|
552
|
+
MU::MommaCat.lock("deployment-notification", deploy_id: @deploy_id) if !@no_artifacts
|
543
553
|
|
544
554
|
if !@need_deploy_flush or @deployment.nil? or @deployment.empty?
|
545
555
|
loadDeploy(true) # make sure we're saving the latest and greatest
|
@@ -578,7 +588,7 @@ module MU
|
|
578
588
|
@deployment[type][key] = data
|
579
589
|
MU.log "Adding to @deployment[#{type}][#{key}]", MU::DEBUG, details: data
|
580
590
|
end
|
581
|
-
save!(key) if !delayed_save
|
591
|
+
save!(key) if !delayed_save and !@no_artifacts
|
582
592
|
else
|
583
593
|
have_deploy = true
|
584
594
|
if @deployment[type].nil? or @deployment[type][key].nil?
|
@@ -603,10 +613,10 @@ module MU
|
|
603
613
|
end
|
604
614
|
}
|
605
615
|
end
|
606
|
-
save! if !delayed_save
|
616
|
+
save! if !delayed_save and !@no_artifacts
|
607
617
|
end
|
608
618
|
ensure
|
609
|
-
MU::MommaCat.unlock("deployment-notification")
|
619
|
+
MU::MommaCat.unlock("deployment-notification", deploy_id: @deploy_id) if !@no_artifacts
|
610
620
|
end
|
611
621
|
end
|
612
622
|
|
@@ -614,18 +624,37 @@ module MU
|
|
614
624
|
# @param subject [String]: The subject line of the message.
|
615
625
|
# @param msg [String]: The message body.
|
616
626
|
# @return [void]
|
617
|
-
def sendAdminSlack(subject, msg: "")
|
618
|
-
if
|
619
|
-
(
|
627
|
+
def sendAdminSlack(subject, msg: "", scrub_mu_isms: true, snippets: [], noop: false)
|
628
|
+
if MU.muCfg['slack'] and MU.muCfg['slack']['webhook'] and
|
629
|
+
(!MU.muCfg['slack']['skip_environments'] or !MU.muCfg['slack']['skip_environments'].any?{ |s| s.casecmp(MU.environment)==0 })
|
620
630
|
require 'slack-notifier'
|
621
|
-
|
631
|
+
slackargs = nil
|
632
|
+
keyword_args = { channel: MU.muCfg['slack']['channel'] }
|
633
|
+
begin
|
634
|
+
slack = Slack::Notifier.new MU.muCfg['slack']['webhook']
|
635
|
+
prefix = scrub_mu_isms ? subject : "#{MU.appname} \*\"#{MU.handle}\"\* (`#{MU.deploy_id}`) - #{subject}"
|
636
|
+
|
637
|
+
text = if msg and !msg.empty?
|
638
|
+
"#{prefix}:\n\n```#{msg}```"
|
639
|
+
else
|
640
|
+
prefix
|
641
|
+
end
|
622
642
|
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
643
|
+
if snippets and snippets.size > 0
|
644
|
+
keyword_args[:attachments] = snippets
|
645
|
+
end
|
646
|
+
|
647
|
+
if !noop
|
648
|
+
slack.ping(text, **keyword_args)
|
649
|
+
else
|
650
|
+
MU.log "Would send to #{MU.muCfg['slack']['channel']}", MU::NOTICE, details: [ text, keyword_args ]
|
651
|
+
end
|
652
|
+
rescue Slack::Notifier::APIError => e
|
653
|
+
MU.log "Failed to send message to slack: #{e.message}", MU::ERR, details: keyword_args
|
654
|
+
return false
|
627
655
|
end
|
628
656
|
end
|
657
|
+
true
|
629
658
|
end
|
630
659
|
|
631
660
|
# Send an email notification to a deployment's administrators.
|
@@ -754,7 +783,7 @@ MAIL_HEAD_END
|
|
754
783
|
end
|
755
784
|
|
756
785
|
siblings = findLitterMate(type: "server", return_all: true)
|
757
|
-
return if siblings.nil? or siblings.empty?
|
786
|
+
return if siblings.nil? or (siblings.respond_to?(:empty?) and siblings.empty?)
|
758
787
|
|
759
788
|
update_servers = []
|
760
789
|
siblings.each_pair { |mu_name, node|
|
@@ -838,7 +867,7 @@ MAIL_HEAD_END
|
|
838
867
|
end
|
839
868
|
|
840
869
|
if resource and resource.config and resource.config['cloud']
|
841
|
-
cloudclass =
|
870
|
+
cloudclass = MU::Cloud.cloudClass(resource.config['cloud'])
|
842
871
|
|
843
872
|
cloudclass.writeDeploySecret(@deploy_id, cert.to_pem, cert_cn+".crt", credentials: resource.config['credentials'])
|
844
873
|
cloudclass.writeDeploySecret(@deploy_id, key.to_pem, cert_cn+".key", credentials: resource.config['credentials'])
|
@@ -33,7 +33,7 @@ module MU
|
|
33
33
|
my_key = OpenSSL::PKey::RSA.new(@private_key)
|
34
34
|
|
35
35
|
begin
|
36
|
-
if my_key.private_decrypt(ciphertext).force_encoding("UTF-8") == @deploy_secret.force_encoding("UTF-8")
|
36
|
+
if my_key.private_decrypt(ciphertext).force_encoding("UTF-8").chomp == @deploy_secret.force_encoding("UTF-8").chomp
|
37
37
|
MU.log "Matched ciphertext for #{MU.deploy_id}", MU::INFO
|
38
38
|
return true
|
39
39
|
else
|
@@ -165,11 +165,11 @@ module MU
|
|
165
165
|
if e.class.name != "MU::Cloud::AWS::Server::BootstrapTempFail" and !File.exist?(deploy_dir+"/.cleanup."+cloud_id) and !File.exist?(deploy_dir+"/.cleanup")
|
166
166
|
MU.log "Grooming FAILED for #{kitten.mu_name} (#{e.inspect})", MU::ERR, details: e.backtrace
|
167
167
|
sendAdminSlack("Grooming FAILED for `#{kitten.mu_name}` with `#{e.message}` :crying_cat_face:", msg: e.backtrace.join("\n"))
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
168
|
+
sendAdminMail("Grooming FAILED for #{kitten.mu_name} on #{MU.appname} \"#{MU.handle}\" (#{MU.deploy_id})",
|
169
|
+
msg: e.inspect,
|
170
|
+
data: e.backtrace,
|
171
|
+
debug: true
|
172
|
+
)
|
173
173
|
raise e if reraise_fail
|
174
174
|
else
|
175
175
|
MU.log "Grooming of #{kitten.mu_name} interrupted by cleanup or planned reboot"
|
@@ -342,6 +342,8 @@ module MU
|
|
342
342
|
return $?.exitstatus
|
343
343
|
end
|
344
344
|
|
345
|
+
@@notified_on_pid = {}
|
346
|
+
|
345
347
|
# Return true if the Momma Cat daemon appears to be running
|
346
348
|
# @return [Boolean]
|
347
349
|
def self.status
|
@@ -352,7 +354,8 @@ module MU
|
|
352
354
|
pid = File.read(daemonPidFile).chomp.to_i
|
353
355
|
begin
|
354
356
|
Process.getpgid(pid)
|
355
|
-
MU.log "Momma Cat running with pid #{pid.to_s}"
|
357
|
+
MU.log "Momma Cat running with pid #{pid.to_s}", (@@notified_on_pid[pid] ? MU::DEBUG : MU::INFO) # shush
|
358
|
+
@@notified_on_pid[pid] = true
|
356
359
|
return true
|
357
360
|
rescue Errno::ESRCH
|
358
361
|
end
|
@@ -19,6 +19,16 @@ module MU
|
|
19
19
|
# the normal synchronous deploy sequence invoked by *mu-deploy*.
|
20
20
|
class MommaCat
|
21
21
|
|
22
|
+
# Lookup table to translate the word "habitat" back to its
|
23
|
+
# provider-specific jargon
|
24
|
+
HABITAT_SYNONYMS = {
|
25
|
+
"AWS" => "account",
|
26
|
+
"CloudFormation" => "account",
|
27
|
+
"Google" => "project",
|
28
|
+
"Azure" => "subscription",
|
29
|
+
"VMWare" => "sddc"
|
30
|
+
}
|
31
|
+
|
22
32
|
# Given a cloud provider's native descriptor for a resource, make some
|
23
33
|
# reasonable guesses about what the thing's name should be.
|
24
34
|
def self.guessName(desc, resourceclass, cloud_id: nil, tag_value: nil)
|
@@ -47,6 +57,74 @@ module MU
|
|
47
57
|
|
48
58
|
end
|
49
59
|
|
60
|
+
# Given a piece of a BoK resource descriptor Hash, come up with shorthand
|
61
|
+
# strings to give it a name for human readers. If nothing reasonable can be
|
62
|
+
# extracted, returns nil.
|
63
|
+
# @param obj [Hash]
|
64
|
+
# @param array_of [String]
|
65
|
+
# @param habitat_translate [String]
|
66
|
+
# @return [Array<String,nil>]
|
67
|
+
def self.getChunkName(obj, array_of = nil, habitat_translate: nil)
|
68
|
+
return [nil, nil] if obj.nil?
|
69
|
+
if [String, Integer, Boolean].include?(obj.class)
|
70
|
+
return [obj, nil]
|
71
|
+
end
|
72
|
+
obj_type = array_of || obj['type']
|
73
|
+
obj_name = obj['name'] || obj['id'] || obj['mu_name'] || obj['cloud_id']
|
74
|
+
|
75
|
+
name_string = if obj_name
|
76
|
+
if obj_type
|
77
|
+
"#{obj_type}[#{obj_name}]"
|
78
|
+
else
|
79
|
+
obj_name.dup
|
80
|
+
end
|
81
|
+
else
|
82
|
+
found_it = nil
|
83
|
+
using = nil
|
84
|
+
["entity", "role"].each { |subtype|
|
85
|
+
if obj[subtype] and obj[subtype].is_a?(Hash)
|
86
|
+
found_it = if obj[subtype]["id"]
|
87
|
+
obj[subtype]['id'].dup
|
88
|
+
elsif obj[subtype]["type"] and obj[subtype]["name"]
|
89
|
+
"#{obj[subtype]['type']}[#{obj[subtype]['name']}]"
|
90
|
+
end
|
91
|
+
break
|
92
|
+
end
|
93
|
+
}
|
94
|
+
found_it
|
95
|
+
end
|
96
|
+
if name_string
|
97
|
+
name_string.gsub!(/\[.+?\](\[.+?\]$)/, '\1')
|
98
|
+
if habitat_translate and HABITAT_SYNONYMS[habitat_translate]
|
99
|
+
name_string.sub!(/^habitats?\[(.+?)\]/i, HABITAT_SYNONYMS[habitat_translate]+'[\1]')
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
location_list = []
|
104
|
+
|
105
|
+
location = if obj['project']
|
106
|
+
obj['project']
|
107
|
+
elsif obj['habitat'] and (obj['habitat']['id'] or obj['habitat']['name'])
|
108
|
+
obj['habitat']['name'] || obj['habitat']['id']
|
109
|
+
else
|
110
|
+
hab_str = nil
|
111
|
+
['projects', 'habitats'].each { |key|
|
112
|
+
|
113
|
+
if obj[key] and obj[key].is_a?(Array)
|
114
|
+
location_list = obj[key].sort.map { |p|
|
115
|
+
(p["name"] || p["id"]).gsub(/^.*?[^\/]+\/([^\/]+)$/, '\1')
|
116
|
+
}
|
117
|
+
hab_str = location_list.join(", ")
|
118
|
+
name_string.gsub!(/^.*?[^\/]+\/([^\/]+)$/, '\1') if name_string
|
119
|
+
break
|
120
|
+
end
|
121
|
+
}
|
122
|
+
hab_str
|
123
|
+
end
|
124
|
+
|
125
|
+
[name_string, location, location_list]
|
126
|
+
end
|
127
|
+
|
50
128
|
# Generate a three-character string which can be used to unique-ify the
|
51
129
|
# names of resources which might potentially collide, e.g. Windows local
|
52
130
|
# hostnames, Amazon Elastic Load Balancers, or server pool instances.
|
@@ -218,17 +296,18 @@ module MU
|
|
218
296
|
# SSH config entries, etc.
|
219
297
|
# @param server [MU::Cloud::Server]: The {MU::Cloud::Server} we'll be setting up.
|
220
298
|
# @param sync_wait [Boolean]: Whether to wait for DNS to fully synchronize before returning.
|
221
|
-
def self.nameKitten(server, sync_wait: false)
|
299
|
+
def self.nameKitten(server, sync_wait: false, no_dns: false)
|
222
300
|
node, config, _deploydata = server.describe
|
223
301
|
|
224
302
|
mu_zone = nil
|
225
303
|
# XXX GCP!
|
226
|
-
if MU::Cloud::AWS.hosted? and !MU::Cloud::AWS.isGovCloud?
|
304
|
+
if !no_dns and MU::Cloud::AWS.hosted? and !MU::Cloud::AWS.isGovCloud?
|
227
305
|
zones = MU::Cloud::DNSZone.find(cloud_id: "platform-mu")
|
228
306
|
mu_zone = zones.values.first if !zones.nil?
|
229
307
|
end
|
308
|
+
|
230
309
|
if !mu_zone.nil?
|
231
|
-
MU::Cloud::DNSZone.genericMuDNSEntry(name: node, target: server.canonicalIP, cloudclass: MU::Cloud::Server, sync_wait: sync_wait)
|
310
|
+
MU::Cloud::DNSZone.genericMuDNSEntry(name: node.gsub(/[^a-z0-9!"\#$%&'\(\)\*\+,\-\/:;<=>\?@\[\]\^_`{\|}~\.]/, '-').gsub(/--|^-/, ''), target: server.canonicalIP, cloudclass: MU::Cloud::Server, sync_wait: sync_wait)
|
232
311
|
else
|
233
312
|
MU::Master.addInstanceToEtcHosts(server.canonicalIP, node)
|
234
313
|
end
|
@@ -60,7 +60,7 @@ module MU
|
|
60
60
|
)
|
61
61
|
_shortclass, _cfg_name, type, _classname, _attrs = MU::Cloud.getResourceNames(type, true)
|
62
62
|
|
63
|
-
cloudclass = MU::Cloud.
|
63
|
+
cloudclass = MU::Cloud.cloudClass(cloud)
|
64
64
|
return nil if cloudclass.virtual?
|
65
65
|
|
66
66
|
if (tag_key and !tag_value) or (!tag_key and tag_value)
|
@@ -107,6 +107,7 @@ module MU
|
|
107
107
|
matches = []
|
108
108
|
|
109
109
|
credlist.each { |creds|
|
110
|
+
# next if region and region.is_a?(Array) and !region.empty? and !region.include?(r)
|
110
111
|
cloud_descs = search_cloud_provider(type, cloud, habitats, region, cloud_id: cloud_id, tag_key: tag_key, tag_value: tag_value, credentials: creds, flags: flags)
|
111
112
|
|
112
113
|
cloud_descs.each_pair.each { |p, regions|
|
@@ -127,6 +128,8 @@ module MU
|
|
127
128
|
matches
|
128
129
|
end
|
129
130
|
|
131
|
+
@object_load_fails = false
|
132
|
+
|
130
133
|
# Return the resource object of another member of this deployment
|
131
134
|
# @param type [String,Symbol]: The type of resource
|
132
135
|
# @param name [String]: The name of the resource as defined in its 'name' Basket of Kittens field
|
@@ -135,7 +138,7 @@ module MU
|
|
135
138
|
# @param created_only [Boolean]: Only return the littermate if its cloud_id method returns a value
|
136
139
|
# @param return_all [Boolean]: Return a Hash of matching objects indexed by their mu_name, instead of a single match. Only valid for resource types where has_multiples is true.
|
137
140
|
# @return [MU::Cloud]
|
138
|
-
def findLitterMate(type: nil, name: nil, mu_name: nil, cloud_id: nil, created_only: false, return_all: false, credentials: nil, habitat: nil, **flags)
|
141
|
+
def findLitterMate(type: nil, name: nil, mu_name: nil, cloud_id: nil, created_only: false, return_all: false, credentials: nil, habitat: nil, debug: false, **flags)
|
139
142
|
_shortclass, _cfg_name, type, _classname, attrs = MU::Cloud.getResourceNames(type)
|
140
143
|
|
141
144
|
# If we specified a habitat, which we may also have done by its shorthand
|
@@ -159,17 +162,33 @@ module MU
|
|
159
162
|
}
|
160
163
|
|
161
164
|
@kitten_semaphore.synchronize {
|
162
|
-
return nil if !@kittens.has_key?(type)
|
163
|
-
matches = []
|
164
165
|
|
166
|
+
if !@kittens.has_key?(type)
|
167
|
+
return nil if !@original_config or @original_config[type].nil? or @original_config[type].empty?
|
168
|
+
begin
|
169
|
+
loadObjects(false)
|
170
|
+
rescue ThreadError => e
|
171
|
+
if e.message !~ /deadlock/
|
172
|
+
raise e
|
173
|
+
end
|
174
|
+
end
|
175
|
+
if @object_load_fails or !@kittens[type]
|
176
|
+
MU.log "#{@deploy_id}'s original config has #{@original_config[type].size == 1 ? "a" : @original_config[type].size.to_s} #{type}, but loadObjects could not populate anything from deployment metadata", MU::ERR if !@object_load_fails
|
177
|
+
@object_load_fails = true
|
178
|
+
return nil
|
179
|
+
end
|
180
|
+
end
|
181
|
+
matches = {}
|
165
182
|
@kittens[type].each { |habitat_group, sib_classes|
|
166
183
|
next if habitat and habitat_group and habitat_group != habitat
|
167
184
|
sib_classes.each_pair { |sib_class, cloud_objs|
|
185
|
+
|
168
186
|
if attrs[:has_multiples]
|
169
187
|
next if !name.nil? and name != sib_class or cloud_objs.empty?
|
170
188
|
if !name.nil?
|
171
189
|
if return_all
|
172
|
-
|
190
|
+
matches.merge!(cloud_objs.clone)
|
191
|
+
next
|
173
192
|
elsif cloud_objs.size == 1 and does_match.call(cloud_objs.values.first)
|
174
193
|
return cloud_objs.values.first
|
175
194
|
end
|
@@ -177,19 +196,24 @@ module MU
|
|
177
196
|
|
178
197
|
cloud_objs.each_value { |obj|
|
179
198
|
if does_match.call(obj)
|
180
|
-
|
199
|
+
if return_all
|
200
|
+
matches.merge!(cloud_objs.clone)
|
201
|
+
else
|
202
|
+
return obj.clone
|
203
|
+
end
|
181
204
|
end
|
182
205
|
}
|
183
|
-
# has_multiples is false
|
206
|
+
# has_multiples is false, "cloud_objs" is actually a singular object
|
184
207
|
elsif (name.nil? and does_match.call(cloud_objs)) or [sib_class, cloud_objs.virtual_name(name)].include?(name.to_s)
|
185
|
-
matches
|
208
|
+
matches[cloud_objs.config['name']] = cloud_objs.clone
|
186
209
|
end
|
187
210
|
}
|
188
211
|
}
|
189
212
|
|
190
|
-
return matches
|
213
|
+
return matches if return_all and matches.size >= 1
|
214
|
+
|
215
|
+
return matches.values.first if matches.size == 1
|
191
216
|
|
192
|
-
return matches if return_all and matches.size > 1
|
193
217
|
}
|
194
218
|
|
195
219
|
return nil
|
@@ -213,7 +237,7 @@ module MU
|
|
213
237
|
end
|
214
238
|
|
215
239
|
def self.generate_dummy_object(type, cloud, name, mu_name, cloud_id, desc, region, habitat, tag_value, calling_deploy, credentials)
|
216
|
-
resourceclass = MU::Cloud.
|
240
|
+
resourceclass = MU::Cloud.resourceClass(cloud, type)
|
217
241
|
|
218
242
|
use_name = if (name.nil? or name.empty?)
|
219
243
|
if !mu_name.nil?
|
@@ -269,15 +293,23 @@ module MU
|
|
269
293
|
private_class_method :generate_dummy_object
|
270
294
|
|
271
295
|
def self.search_cloud_provider(type, cloud, habitats, region, cloud_id: nil, tag_key: nil, tag_value: nil, credentials: nil, flags: nil)
|
272
|
-
cloudclass = MU::Cloud.
|
273
|
-
resourceclass = MU::Cloud.
|
296
|
+
cloudclass = MU::Cloud.cloudClass(cloud)
|
297
|
+
resourceclass = MU::Cloud.resourceClass(cloud, type)
|
274
298
|
|
275
299
|
# Decide what regions we'll search, if applicable for this resource
|
276
300
|
# type.
|
277
301
|
regions = if resourceclass.isGlobal?
|
278
302
|
[nil]
|
279
303
|
else
|
280
|
-
|
304
|
+
if region
|
305
|
+
if region.is_a?(Array) and !region.empty?
|
306
|
+
region
|
307
|
+
else
|
308
|
+
[region]
|
309
|
+
end
|
310
|
+
else
|
311
|
+
cloudclass.listRegions(credentials: credentials)
|
312
|
+
end
|
281
313
|
end
|
282
314
|
|
283
315
|
# Decide what habitats (accounts/projects/subscriptions) we'll
|
@@ -288,7 +320,7 @@ module MU
|
|
288
320
|
habitats << nil
|
289
321
|
end
|
290
322
|
if resourceclass.canLiveIn.include?(:Habitat)
|
291
|
-
habitats.concat(cloudclass.listHabitats(credentials))
|
323
|
+
habitats.concat(cloudclass.listHabitats(credentials, use_cache: false))
|
292
324
|
end
|
293
325
|
end
|
294
326
|
habitats << nil if habitats.empty?
|