cloud-mu 3.1.6 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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?
|