Class: MCollective::Application::Tasks
- Inherits:
-
Application
- Object
- Application
- MCollective::Application::Tasks
- Defined in:
- lib/mcollective/application/tasks.rb
Instance Method Summary collapse
- #bolt_tasks ⇒ Object
- #choria ⇒ Object
- #cli ⇒ Object
- #download_files(task, files) ⇒ Object
- #extract_environment_from_argv ⇒ Object
- #list_command ⇒ Object
- #list_options ⇒ Object
- #main ⇒ Object
- #post_option_parser(configuration) ⇒ Object
-
#request_and_report(action, arguments, taskid = nil) ⇒ Object
rubocop:disable Metrics/MethodLength.
- #reset_client! ⇒ Object
- #run ⇒ Object
- #run_command ⇒ Object
-
#run_options ⇒ Object
rubocop:disable Metrics/MethodLength.
- #say(msg = "") ⇒ Object
- #show_task_help(task) ⇒ Object
- #status_command ⇒ Object
- #status_options ⇒ Object
- #tasks_support ⇒ Object
- #valid_commands ⇒ Object
Instance Method Details
#bolt_tasks ⇒ Object
391 392 393 |
# File 'lib/mcollective/application/tasks.rb', line 391 def bolt_tasks @_bolt_tasks ||= rpcclient("bolt_tasks") end |
#choria ⇒ Object
412 413 414 415 416 |
# File 'lib/mcollective/application/tasks.rb', line 412 def choria Util.loadclass("MCollective::Util::Choria") @_choria ||= Util::Choria.new end |
#cli ⇒ Object
422 423 424 425 426 427 428 429 430 |
# File 'lib/mcollective/application/tasks.rb', line 422 def cli format = configuration[:__json_format] ? :json : :default if @_cli ||= tasks_support.cli(format, [:verbose]) else tasks_support.cli(format, false) end end |
#download_files(task, files) ⇒ Object
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/mcollective/application/tasks.rb', line 224 def download_files(task, files) bolt_tasks.batch_size = 50 bolt_tasks.batch_sleep_time = 1 failed = false downloads = [] cnt = bolt_tasks.discover.size idx = 0 bolt_tasks.download(:environment => "production", :task => task, :files => files.to_json) do |_, s| unless configuration[:__json_format] print(cli.twirl("Downloading and verifying %d file(s) from the Puppet Server to all nodes:" % [files.size], cnt, idx + 1)) puts if cnt == idx + 1 end idx += 1 downloads << s end downloads.select {|d| d[:statuscode] > 0}.each_with_index do |download, i| failed = true puts if i == 0 puts(" %s: %s" % [Util.colorize(:red, "Could not download files onto %s" % download[:sender]), download[:statusmsg]]) end unless bolt_tasks.stats.noresponsefrom.empty? puts puts bolt_tasks.stats.no_response_report failed = true end if failed puts abort("Could not download the task %s onto all nodes" % task) end end |
#extract_environment_from_argv ⇒ Object
400 401 402 403 404 405 406 |
# File 'lib/mcollective/application/tasks.rb', line 400 def extract_environment_from_argv idx = ARGV.index("--environment") return "production" unless idx ARGV[idx + 1] end |
#list_command ⇒ Object
374 375 376 |
# File 'lib/mcollective/application/tasks.rb', line 374 def list_command cli.show_task_list("production", configuration[:__detail]) end |
#list_options ⇒ Object
31 32 33 34 35 36 37 |
# File 'lib/mcollective/application/tasks.rb', line 31 def self.class.option :__detail, :arguments => ["--detail"], :description => "Show command descriptions", :default => false, :type => :boolean end |
#main ⇒ Object
432 433 434 435 436 437 438 |
# File 'lib/mcollective/application/tasks.rb', line 432 def main if valid_commands.include?(configuration[:__command]) send("%s_command" % configuration[:__command]) else show_task_help(configuration[:__command]) end end |
#post_option_parser(configuration) ⇒ Object
27 28 29 |
# File 'lib/mcollective/application/tasks.rb', line 27 def post_option_parser(configuration) configuration[:__command] = ARGV.shift || "list" end |
#request_and_report(action, arguments, taskid = nil) ⇒ Object
rubocop:disable Metrics/MethodLength
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
# File 'lib/mcollective/application/tasks.rb', line 284 def request_and_report(action, arguments, taskid=nil) # rubocop:disable Metrics/MethodLength res = true task_not_known_nodes = 0 wrapper_failure = 0 completed_nodes = 0 running_nodes = 0 runtime = 0.0 success_nodes = 0 fail_nodes = 0 progress = configuration[:__summary] || configuration[:__batch_size] ? RPC::Progress.new : nil cnt = 0 expected = bolt_tasks.discover.size task_names = [] callers = [] if configuration[:__batch_size] bolt_tasks.batch_size = configuration[:__batch_size] bolt_tasks.batch_sleep_time = configuration[:__batch_sleep] end say bolt_tasks.send(action, arguments) do |_, reply| status = reply[:data] if reply[:statuscode] == 3 res = false fail_nodes += 1 task_not_known_nodes += 1 elsif [-1, 0].include?(status[:exitcode]) status[:completed] ? completed_nodes += 1 : running_nodes += 1 runtime += status[:runtime] if reply[:statuscode] == 0 success_nodes += 1 else res = false fail_nodes += 1 end elsif reply[:statuscode] == 5 res = false wrapper_failure += 1 fail_nodes += 1 else res = false fail_nodes += 1 end task_names << status[:task] if status[:task] callers << status[:callerid] if status[:callerid] if progress print(progress.twirl(cnt + 1, expected)) say if cnt + 1 == expected else cli.print_result(reply) end cnt += 1 end taskid ||= bolt_tasks.stats.requestid callers.compact! callers.uniq! task_names.compact! task_names.uniq! say cli.print_task_summary( taskid, task_names, callers, completed_nodes, running_nodes, task_not_known_nodes, wrapper_failure, success_nodes, fail_nodes, runtime, bolt_tasks.stats ) res ensure reset_client! end |
#reset_client! ⇒ Object
395 396 397 398 |
# File 'lib/mcollective/application/tasks.rb', line 395 def reset_client! bolt_tasks.batch_size = 0 bolt_tasks.progress = [:verbose] end |
#run ⇒ Object
378 379 380 381 382 383 384 385 |
# File 'lib/mcollective/application/tasks.rb', line 378 def run command = ARGV[0] command = "list" unless valid_commands.include?(command) send("%s_options" % command) super end |
#run_command ⇒ Object
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 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/mcollective/application/tasks.rb', line 164 def run_command task = ARGV.shift input = cli.task_input(configuration) say("Retrieving task metadata for task %s from the Puppet Server" % task) begin = cli.(task, "production") rescue abort($!.to_s) end cli.transform_hash_strings(, input) cli.validate_task_input(task, , input) say("Attempting to download and run task %s on %d nodes" % [Util.colorize(:bold, task), bolt_tasks.discover.size]) say download_files(task, ["files"]) request = { :task => task, :files => ["files"].to_json } request[:run_as] = configuration[:__run_as] if configuration[:__run_as] request[:input] = input.to_json if input if configuration[:__background] puts("Starting task %s in the background" % [Util.colorize(:bold, task)]) if configuration[:__batch_size] bolt_tasks.batch_size = configuration[:__batch_size] bolt_tasks.batch_sleep_time = configuration[:__batch_sleep] bolt_tasks.progress = true end printrpc bolt_tasks.run_no_wait(request) printrpcstats if bolt_tasks.stats.okcount > 0 puts puts("Request detailed status for the task using 'mco tasks status %s'" % [Util.colorize(:bold, bolt_tasks.stats.requestid)]) end else say("Running task %s and waiting up to %s seconds for it to complete" % [ Util.colorize(:bold, task), Util.colorize(:bold, bolt_tasks.ddl.[:timeout]) ]) success = request_and_report(:run_and_wait, request) exit(success ? 0 : 1) end ensure reset_client! end |
#run_options ⇒ Object
rubocop:disable Metrics/MethodLength
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 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 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/mcollective/application/tasks.rb', line 71 def # rubocop:disable Metrics/MethodLength [:usage].clear self.class.usage <<-USAGE mco tasks run <TASK NAME> [OPTIONS] Runs a task in the background and wait up to 50 seconds for it to complete. Task inputs are handled using --argument=value for basic String, Numeric and Boolean types, others can be passed using --input Input can also be read from a file using "--input @file.json" or "--input @file.yaml". For complex data types like Hashes, Arrays or Variants you have to supply input as YAML or JSON. Once a task is run the task ID will be displayed which can later be used with the "mco tasks status" command to extract results. Examples: Run myapp::upgrade task in the background and wait for it to complete: mco tasks run myapp::upgrade --version 1.0.0 Run myapp::upgrade task in the background and return immediately: mco tasks run myapp::upgrade --version 1.0.0 --background Supply complex data input to the task: Should input be given on both the CLI arguments and a file the CLI arguments will override the file mco tasks run myapp::upgrade --input @input.json mco tasks run myapp::upgrade --input @input.yaml mco tasks run myapp::upgrade --version 1.0.0 --input \\ '{"source": { "url": "http://repo/archive-1.0.0.tgz", "hash": "68b329da9893e34099c7d8ad5cb9c940"}}' USAGE task = ARGV[1] abort("Please specify a task to run") unless task cli.(task, "production", self) self.class.option :__summary, :arguments => ["--summary"], :description => "Only show a overall summary of the task", :default => false, :type => :boolean self.class.option :__background, :arguments => ["--background"], :description => "Do not wait for the task to complete", :default => false, :type => :boolean self.class.option :__json_input, :arguments => ["--input INPUT"], :description => "JSON input to pass to the task", :required => false, :type => String self.class.option :__batch_size, :arguments => ["--batch SIZE"], :description => "Run tasks on nodes in batches", :required => false, :type => String self.class.option :__batch_sleep, :arguments => ["--batch-sleep SECONDS"], :description => "Time to sleep between invocations of batches of nodes", :required => false, :default => 1, :type => Integer self.class.option :__run_as, :arguments => ["--run-as USERNAME"], :description => "Run task as user USERNAME", :required => false, :default => nil, :type => String end |
#say(msg = "") ⇒ Object
160 161 162 |
# File 'lib/mcollective/application/tasks.rb', line 160 def say(msg="") puts(msg) unless configuration[:__json_format] end |
#show_task_help(task) ⇒ Object
387 388 389 |
# File 'lib/mcollective/application/tasks.rb', line 387 def show_task_help(task) cli.show_task_help(task, "production") end |
#status_command ⇒ Object
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/mcollective/application/tasks.rb', line 262 def status_command taskid = ARGV.shift abort("Please specify a task id to display") unless taskid if configuration[:__metadata] say("Requesting task metadata for request %s" % Util.colorize(:bold, taskid)) unless [:verbose] bolt_tasks.task_status(:task_id => taskid).each do |status| cli.(status) end cli.print_rpc_stats(bolt_tasks.stats) else say("Requesting task status for request %s, showing failures only pass --verbose for all output" % Util.colorize(:bold, taskid)) unless [:verbose] success = request_and_report(:task_status, {:task_id => taskid}, taskid) exit(success ? 0 : 1) end end |
#status_options ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/mcollective/application/tasks.rb', line 39 def [:usage].clear self.class.usage <<-USAGE mco tasks status <REQUEST> [FLAGS] Retrieves the status for a task you previously requested. It can be running or completed. By default only failed exuecutions are shown, use --verbose to see them all. USAGE self.class.option :__summary, :arguments => ["--summary"], :description => "Only show a overall summary of the task", :default => false, :type => :boolean self.class.option :__metadata, :arguments => ["--metadata"], :description => "Only show task metadata for each node", :default => false, :type => :boolean self.class.option :__json_format, :arguments => ["--json"], :description => "Display results in JSON format", :default => false, :type => :boolean end |
#tasks_support ⇒ Object
418 419 420 |
# File 'lib/mcollective/application/tasks.rb', line 418 def tasks_support @_tasks_support ||= choria.tasks_support end |
#valid_commands ⇒ Object
408 409 410 |
# File 'lib/mcollective/application/tasks.rb', line 408 def valid_commands methods.grep(/_command$/).map {|c| c.to_s.gsub("_command", "")} end |