Class: MCollective::Util::Playbook::Tasks::McollectiveTask
- Defined in:
- lib/mcollective/util/playbook/tasks/mcollective_task.rb
Instance Attribute Summary
Attributes inherited from Base
Instance Method Summary collapse
-
#assert_replies(replies) ⇒ Boolean, Integer
Runs the reply data through the assertion, true when all replies match.
-
#client(from_cache = true) ⇒ RPC::Client
Creates and cache an RPC::Client for the configured agent.
-
#create_and_configure_client ⇒ RPC::Client
Creates a new RPC::Client and configures it with the configured settings.
-
#from_hash(data) ⇒ McollectiveTask
Initialize the task from a hash.
-
#jgrep? ⇒ Boolean
Determines if jgrep is available and loads it.
-
#log_failure(stats, replies) ⇒ Object
Logs a failed request.
- #log_reply(reply) ⇒ Object
-
#log_results(stats, replies) ⇒ Object
Logs the result of a request.
-
#log_success(stats) ⇒ Object
Logs a successfull request.
-
#parse_action(action) ⇒ Array<String, String>
Parse an action in the form agent.action.
-
#parse_assertion ⇒ true, String
Validates the supplied assertion using JGrep’s parser.
-
#request_success?(stats) ⇒ Boolean
Determines if a request was succesfull.
-
#run ⇒ Array<Boolean, String, Array<RPC::Result>>
Logs a single RPC reply Performs a single attempt at calling the agent.
-
#run_result(stats, replies) ⇒ Array<Boolean, String, Array<Hash>>
Determines the run result.
-
#should_summarize? ⇒ Boolean
Determines if a summary was requested.
- #startup_hook ⇒ Object
-
#success_message(stats) ⇒ String
Creates the messages logged on success.
-
#summary_message(stats) ⇒ String?
Creates the summary message.
-
#symbolize_basic_input_arguments(properties) ⇒ Hash
Converts the string keys to symbols if the DDL is based on symbols.
- #to_execution_result(results) ⇒ Object
-
#validate_configuration! ⇒ Object
Validates the internal configuration of the task.
Methods inherited from Base
Methods included from MCollective::Util::Playbook::TemplateUtil
#__template_process_string, #__template_resolve, #t
Constructor Details
This class inherits a constructor from MCollective::Util::Playbook::Tasks::Base
Instance Method Details
#assert_replies(replies) ⇒ Boolean, Integer
Runs the reply data through the assertion, true when all replies match
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 279 def assert_replies(replies) return [false, replies.size] unless @assertion return [false, replies.size] unless jgrep? result = [] expected = replies.size jdata = replies.map {|reply| reply.results[:data]}.to_json begin Log.debug("Asserting '%s' over %d replies" % [@assertion, replies.size]) result = JGrep.jgrep(jdata, @assertion) rescue Log.error("Assertion '%s' could not be matched: %s" % [@asssertion, expected]) end [result.size == expected, expected - result.size] end |
#client(from_cache = true) ⇒ RPC::Client
Creates and cache an RPC::Client for the configured agent
35 36 37 38 39 40 41 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 35 def client(from_cache=true) if from_cache @_rpc_client ||= create_and_configure_client else create_and_configure_client end end |
#create_and_configure_client ⇒ RPC::Client
discovery
Creates a new RPC::Client and configures it with the configured settings
47 48 49 50 51 52 53 54 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 47 def create_and_configure_client client = RPC::Client.new(@agent, :configfile => Util.config_file_for_user, :options => Util.) client.batch_size = @batch_size if @batch_size client.batch_sleep_time = @batch_sleep_time if @batch_sleep_time client.discover(:nodes => @nodes) client.progress = false client end |
#from_hash(data) ⇒ McollectiveTask
Initialize the task from a hash
88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 88 def from_hash(data) @nodes = data.fetch("nodes", []) @agent, @action = parse_action(data["action"]) @batch_size = data["batch_size"] @batch_sleep_time = data["batch_sleep_time"] @properties = data.fetch("properties", {}) @post = data.fetch("post", []) @log_replies = !data.fetch("silent", false) @assertion = data["assert"] @_rpc_client = nil self end |
#jgrep? ⇒ Boolean
Determines if jgrep is available and loads it
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 15 def jgrep? @_jgrep = false require "jgrep" if JGrep.respond_to?("validate_expression") @_jgrep = true else Log.warn("Please install a version of JGrep greater than or equal to 1.5.0") end @_jgrep rescue LoadError @_jgrep = false end |
#log_failure(stats, replies) ⇒ Object
Logs a failed request
243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 243 def log_failure(stats, replies) stats ||= client.stats Log.warn("Failed request %s for %s#%s in %0.2fs" % [stats.requestid, @agent, @action, stats.totaltime]) Log.warn("No responses from: %s" % stats.noresponsefrom.join(", ")) unless stats.noresponsefrom.empty? if stats.failcount > 0 replies.each do |reply| Log.warn("Failed result from %s: %s" % [reply.results[:sender], reply.results[:statusmsg]]) if reply.results[:statuscode] > 0 end end end |
#log_reply(reply) ⇒ Object
257 258 259 260 261 262 263 264 265 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 257 def log_reply(reply) if reply.results[:statuscode] == 0 return unless @log_replies Log.info("%s %s#%s success: %s" % [reply.results[:sender], @agent, @action, reply.results[:data].inspect]) else Log.warn("%s %s#%s failure: %s" % [reply.results[:sender], @agent, @action, reply.results[:data].inspect]) end end |
#log_results(stats, replies) ⇒ Object
Logs the result of a request
199 200 201 202 203 204 205 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 199 def log_results(stats, replies) if request_success?(stats) log_success(stats) else log_failure(stats, replies) end end |
#log_success(stats) ⇒ Object
Logs a successfull request
210 211 212 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 210 def log_success(stats) Log.debug((stats)) end |
#parse_action(action) ⇒ Array<String, String>
check it complies to format
Parse an action in the form agent.action
80 81 82 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 80 def parse_action(action) action.split(".") end |
#parse_assertion ⇒ true, String
Validates the supplied assertion using JGrep’s parser
270 271 272 273 274 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 270 def parse_assertion return "JGrep not installed" unless jgrep? JGrep.validate_expression(@assertion) end |
#request_success?(stats) ⇒ Boolean
Determines if a request was succesfull
301 302 303 304 305 306 307 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 301 def request_success?(stats) return false if stats.failcount > 0 return false if stats.okcount == 0 return false unless stats.noresponsefrom.empty? true end |
#run ⇒ Array<Boolean, String, Array<RPC::Result>>
should return some kind of task status object
Logs a single RPC reply Performs a single attempt at calling the agent
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 331 def run Log.info("Starting request for %s#%s against %d nodes" % [@agent, @action, @nodes.size]) begin replies = [] client.send(@action, symbolize_basic_input_arguments(@properties)) do |_, s| replies << s log_reply(s) end log_results(client.stats, replies) run_result(client.stats, replies) rescue msg = "Could not create request for %s#%s: %s: %s" % [@agent, @action, $!.class, $!.to_s] Log.debug(msg) Log.debug($!.backtrace.join("\t\n")) [false, msg, []] end end |
#run_result(stats, replies) ⇒ Array<Boolean, String, Array<Hash>>
Determines the run result
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 108 def run_result(stats, replies) reply_data = replies.map do |reply| { "agent" => reply.agent, "action" => reply.action, "sender" => reply.results[:sender], "statuscode" => reply.results[:statuscode], "statusmsg" => reply.results[:statusmsg], "data" => reply.results[:data], "requestid" => stats.requestid } end success = request_success?(stats) assert_failed = -1 if @assertion && success passed, assert_failed = assert_replies(replies) if passed Log.info("Assertion '%s' passed on all %d nodes" % [@assertion, replies.size]) else Log.warn("Assertion '%s' failed on %d/%d nodes" % [@assertion, assert_failed, replies.size]) success = false end end if success msg = nil msg = (stats) if should_summarize? msg ||= (stats) [true, msg, reply_data] elsif assert_failed > -1 [false, "Failed request %s for %s#%s assertion failed on %d node(s)" % [stats.requestid, @agent, @action, assert_failed], reply_data] else failed = stats.failcount + stats.noresponsefrom.size [false, "Failed request %s for %s#%s on %d failed node(s)" % [stats.requestid, @agent, @action, failed], reply_data] end end |
#should_summarize? ⇒ Boolean
Determines if a summary was requested
312 313 314 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 312 def should_summarize? @post.include?("summarize") end |
#startup_hook ⇒ Object
6 7 8 9 10 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 6 def startup_hook @properties = {} @post = [] @nodes = [] end |
#success_message(stats) ⇒ String
Creates the messages logged on success
217 218 219 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 217 def (stats) "Successful request %s for %s#%s in %0.2fs against %d node(s)" % [stats.requestid, @agent, @action, stats.totaltime, stats.okcount] end |
#summary_message(stats) ⇒ String?
Creates the summary message
225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 225 def (stats) summary = {} if stats.aggregate_summary.size + stats.aggregate_failures.size > 0 stats.aggregate_summary.each do |aggregate| summary.merge!(aggregate.result[:value]) end end return nil if summary.empty? "Summary for %s: %s" % [@description, summary.to_json] end |
#symbolize_basic_input_arguments(properties) ⇒ Hash
Converts the string keys to symbols if the DDL is based on symbols
This is to be compatible with either JSON or non JSON mcollectives
322 323 324 325 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 322 def symbolize_basic_input_arguments(properties) input = client.ddl.action_interface(@action)[:input] || {} client.ddl.symbolize_basic_input_arguments(input, properties) end |
#to_execution_result(results) ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 149 def to_execution_result(results) e_result = {} results[2].each do |data| result = { "value" => JSON.parse(JSON.dump(data)), "type" => "mcollective", "fail_ok" => @fail_ok } unless data["statuscode"] == 0 result["error"] = { "msg" => data["statusmsg"], "kind" => "choria.playbook/taskerror", "details" => { "agent" => @agent, "action" => @action, "issue_code" => data["statuscode"] } } end e_result[data["sender"]] = result end if client.stats client.stats.noresponsefrom.each do |nr| e_result[nr] = { "value" => {}, "type" => "mcollective", "fail_ok" => @fail_ok, "error" => { "msg" => "No response from node %s" % nr, "kind" => "choria.playbook/taskerror", "details" => { "agent" => @agent, "action" => @action } } } end end e_result end |
#validate_configuration! ⇒ Object
Validates the internal configuration of the task
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/mcollective/util/playbook/tasks/mcollective_task.rb', line 59 def validate_configuration! raise("Nodes have to be an array") unless @nodes.is_a?(Array) raise("Nodes need to be supplied, refusing to run against empty node list") if @nodes.empty? if @assertion raise("jgrep is required for tasks with an assertion") unless jgrep? parse_result = parse_assertion unless parse_result == true parse_result.tr!("\n", " ") raise("Could not parse the assertion %s: %s" % [@assertion, parse_result]) end end end |