modules/mu/mommacat.rb in cloud-mu-3.1.6 vs modules/mu/mommacat.rb in cloud-mu-3.2.0
- old
+ new
@@ -165,10 +165,11 @@
@secret_semaphore = Mutex.new
@notify_semaphore = Mutex.new
@need_deploy_flush = false
@node_cert_semaphore = Mutex.new
@deployment = deployment_data
+
@deployment['mu_public_ip'] = MU.mu_public_ip
@private_key = nil
@public_key = nil
@secrets = Hash.new
@secrets['instance_secret'] = Hash.new
@@ -180,10 +181,11 @@
@handle = MU.handle # pass this in
@appname = appname
@appname ||= @original_config['name'] if @original_config
@timestamp = timestamp
@environment = environment
+ @original_config['environment'] ||= @environment if @original_config
if set_context_to_me
MU::MommaCat.setThreadContext(self)
end
@@ -251,12 +253,11 @@
@original_config[type].each { |resource|
if resource['credentials']
seen << resource['credentials']
else
cloudconst = @original_config['cloud'] ? @original_config['cloud'] : MU::Config.defaultCloud
- Object.const_get("MU").const_get("Cloud").const_get(cloudconst)
- seen << cloudclass.credConfig(name_only: true)
+ seen << MU::Cloud.cloudClass(cloudconst).credConfig(name_only: true)
end
}
end
}
# XXX insert default for each cloud provider if not explicitly seen
@@ -287,15 +288,14 @@
hab_ref = MU::Config::Ref.get(resource['habitat'])
if hab_ref and hab_ref.id
habitats << hab_ref.id
end
elsif resource['cloud']
- cloudclass = Object.const_get("MU").const_get("Cloud").const_get(resource['cloud'])
# XXX this should be a general method implemented by each cloud
# provider
if resource['cloud'] == "Google"
- habitats << cloudclass.defaultProject(resource['credentials'])
+ habitats << MU::Cloud.cloudClass(resource['cloud']).defaultProject(resource['credentials'])
end
end
}
end
}
@@ -315,17 +315,15 @@
MU::Cloud.resource_types.each_pair { |res_type, attrs|
type = attrs[:cfg_plural]
if @original_config[type]
@original_config[type].each { |resource|
if resource['cloud']
- cloudclass = Object.const_get("MU").const_get("Cloud").const_get(resource['cloud'])
- resclass = Object.const_get("MU").const_get("Cloud").const_get(resource['cloud']).const_get(res_type.to_s)
- if resclass.isGlobal?
+ if MU::Cloud.resourceClass(resource['cloud'], res_type).isGlobal?
# XXX why was I doing this, urgh
next
elsif !resource['region']
- regions << cloudclass.myRegion
+ regions << MU::Cloud.cloudClass(resource['cloud']).myRegion(resource['credentials'])
end
end
if resource['region']
regions << resource['region'] if resource['region']
else
@@ -399,28 +397,41 @@
# Keep tabs on a {MU::Cloud} object so that it can be found easily by
# #findLitterMate.
# @param type [String]:
# @param name [String]:
# @param object [MU::Cloud]:
- def addKitten(type, name, object)
+ def addKitten(type, name, object, do_notify: false)
if !type or !name or !object or !object.mu_name
raise MuError, "Nil arguments to addKitten are not allowed (got type: #{type}, name: #{name}, and '#{object}' to add)"
end
_shortclass, _cfg_name, type, _classname, attrs = MU::Cloud.getResourceNames(type)
object.intoDeploy(self)
- @kitten_semaphore.synchronize {
+ add_block = Proc.new {
@kittens[type] ||= {}
@kittens[type][object.habitat] ||= {}
if attrs[:has_multiples]
@kittens[type][object.habitat][name] ||= {}
@kittens[type][object.habitat][name][object.mu_name] = object
else
@kittens[type][object.habitat][name] = object
end
+ if do_notify
+ notify(type, name, object.notify, triggering_node: object, delayed_save: true)
+ end
}
+
+ begin
+ @kitten_semaphore.synchronize {
+ add_block.call()
+ }
+ rescue ThreadError => e
+ # already locked by a parent call to this method, so this should be safe
+ raise e if !e.message.match(/recursive locking/)
+ add_block.call()
+ end
end
# Encrypt a string with the deployment's public key.
# @param ciphertext [String]: The string to encrypt
def encryptWithDeployKey(ciphertext)
@@ -534,14 +545,13 @@
# @param data [Hash]: The resource's metadata.
# @param triggering_node [MU::Cloud]: A cloud object calling this notify, usually on behalf of itself
# @param remove [Boolean]: Remove this resource from the deploy structure, instead of adding it.
# @return [void]
def notify(type, key, data, mu_name: nil, remove: false, triggering_node: nil, delayed_save: false)
- return if @no_artifacts
begin
- MU::MommaCat.lock("deployment-notification")
+ MU::MommaCat.lock("deployment-notification", deploy_id: @deploy_id) if !@no_artifacts
if !@need_deploy_flush or @deployment.nil? or @deployment.empty?
loadDeploy(true) # make sure we're saving the latest and greatest
end
@@ -576,11 +586,11 @@
MU.log "Adding to @deployment[#{type}][#{key}][#{mu_name}]", MU::DEBUG, details: data
else
@deployment[type][key] = data
MU.log "Adding to @deployment[#{type}][#{key}]", MU::DEBUG, details: data
end
- save!(key) if !delayed_save
+ save!(key) if !delayed_save and !@no_artifacts
else
have_deploy = true
if @deployment[type].nil? or @deployment[type][key].nil?
MU.log "MU::MommaCat.notify called to remove #{type} #{key}#{has_multiples ? " "+mu_name : ""} deployment struct, but no such data exist", MU::DEBUG
return
@@ -601,33 +611,52 @@
if @deployment[type].empty?
@deployment.delete(type)
end
}
end
- save! if !delayed_save
+ save! if !delayed_save and !@no_artifacts
end
ensure
- MU::MommaCat.unlock("deployment-notification")
+ MU::MommaCat.unlock("deployment-notification", deploy_id: @deploy_id) if !@no_artifacts
end
end
# Send a Slack notification to a deployment's administrators.
# @param subject [String]: The subject line of the message.
# @param msg [String]: The message body.
# @return [void]
- def sendAdminSlack(subject, msg: "")
- if $MU_CFG['slack'] and $MU_CFG['slack']['webhook'] and
- (!$MU_CFG['slack']['skip_environments'] or !$MU_CFG['slack']['skip_environments'].any?{ |s| s.casecmp(MU.environment)==0 })
+ def sendAdminSlack(subject, msg: "", scrub_mu_isms: true, snippets: [], noop: false)
+ if MU.muCfg['slack'] and MU.muCfg['slack']['webhook'] and
+ (!MU.muCfg['slack']['skip_environments'] or !MU.muCfg['slack']['skip_environments'].any?{ |s| s.casecmp(MU.environment)==0 })
require 'slack-notifier'
- slack = Slack::Notifier.new $MU_CFG['slack']['webhook']
+ slackargs = nil
+ keyword_args = { channel: MU.muCfg['slack']['channel'] }
+ begin
+ slack = Slack::Notifier.new MU.muCfg['slack']['webhook']
+ prefix = scrub_mu_isms ? subject : "#{MU.appname} \*\"#{MU.handle}\"\* (`#{MU.deploy_id}`) - #{subject}"
- if msg and !msg.empty?
- slack.ping "#{MU.appname} \*\"#{MU.handle}\"\* (`#{MU.deploy_id}`) - #{subject}:\n\n```#{msg}\n```", channel: $MU_CFG['slack']['channel']
- else
- slack.ping "#{MU.appname} \*\"#{MU.handle}\"\* (`#{MU.deploy_id}`) - #{subject}", channel: $MU_CFG['slack']['channel']
+ text = if msg and !msg.empty?
+ "#{prefix}:\n\n```#{msg}```"
+ else
+ prefix
+ end
+
+ if snippets and snippets.size > 0
+ keyword_args[:attachments] = snippets
+ end
+
+ if !noop
+ slack.ping(text, **keyword_args)
+ else
+ MU.log "Would send to #{MU.muCfg['slack']['channel']}", MU::NOTICE, details: [ text, keyword_args ]
+ end
+ rescue Slack::Notifier::APIError => e
+ MU.log "Failed to send message to slack: #{e.message}", MU::ERR, details: keyword_args
+ return false
end
end
+ true
end
# Send an email notification to a deployment's administrators.
# @param subject [String]: The subject line of the message.
# @param msg [String]: The message body.
@@ -752,11 +781,11 @@
if !triggering_node.nil? and triggering_node.is_a?(MU::Cloud::Server)
triggering_node = triggering_node.mu_name
end
siblings = findLitterMate(type: "server", return_all: true)
- return if siblings.nil? or siblings.empty?
+ return if siblings.nil? or (siblings.respond_to?(:empty?) and siblings.empty?)
update_servers = []
siblings.each_pair { |mu_name, node|
next if mu_name == triggering_node or node.groomer.nil?
next if nodeclasses.size > 0 and !nodeclasses.include?(node.config['name'])
@@ -836,10 +865,10 @@
winrm_cert = MU::Master::SSL.getCert(cert_cn+"-winrm", "/CN=#{resource.config['windows_admin_username']}/O=Mu/C=US", sans: ["otherName:1.3.6.1.4.1.311.20.2.3;UTF8:#{resource.config['windows_admin_username']}@localhost"], pfx: true)[0]
results[cert_cn+"-winrm"] = [winrm_key, winrm_cert]
end
if resource and resource.config and resource.config['cloud']
- cloudclass = Object.const_get("MU").const_get("Cloud").const_get(resource.config['cloud'])
+ cloudclass = MU::Cloud.cloudClass(resource.config['cloud'])
cloudclass.writeDeploySecret(@deploy_id, cert.to_pem, cert_cn+".crt", credentials: resource.config['credentials'])
cloudclass.writeDeploySecret(@deploy_id, key.to_pem, cert_cn+".key", credentials: resource.config['credentials'])
if pfx_cert
cloudclass.writeDeploySecret(@deploy_id, pfx_cert.to_der, cert_cn+".pfx", credentials: resource.config['credentials'])