choria-colt 0.4.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d2f9c64ee41ebc49a88deff71b470baab7c4e83b921102518969fe2a35b77f1
4
- data.tar.gz: 8f69562d201ff4addc3b44aa693d508ceca1a1623455d2ac57b273e59cd300f1
3
+ metadata.gz: 4e76e667917bf1958b48d45148712fa5e0d6f2c15280bbbda0d4899b0537e9f8
4
+ data.tar.gz: 17637d3bf6738bef6c28a282aabb1c4ac7680e4b2e8a6f0fe873a27b59079cc1
5
5
  SHA512:
6
- metadata.gz: 8fd9cc5e888843d6c8954fe7d2543b4496fe861354162f499831f4ebe7cc8ccd3def73604c6d44e6f83273f71eb8364fc1b01c99581c16e8b2635adbee071aea
7
- data.tar.gz: 5a912066de4c960ffc85debf3cc53a678ac3312f2e75daec0d999f50af7f24215f1347b6c4984de55db9f3bb357075486310ab11db685e8f866c61a06049940f
6
+ metadata.gz: bacccbdfd46669936f1271d05e4fdceae1864e07ae7f14b260f6de3ec2ed1e90d0c3270f57ea3faaa424b267eab59e1460abcdf4262feec421c6ea510bc811d5
7
+ data.tar.gz: ad8aaf32f6f71f349d04955cb795c0439c4ecd30103f290da82b3ce7037c6dce330b7e89123a416c120b61bc194c754debfb97412e6e200af8d53264aaba169c
data/.rubocop.yml CHANGED
@@ -11,6 +11,7 @@ Metrics/AbcSize:
11
11
  Max: 20
12
12
 
13
13
  Metrics/ClassLength:
14
+ Max: 120
14
15
  Exclude:
15
16
  - 'lib/choria/colt/cli.rb'
16
17
 
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2022-04-07 15:43:34 UTC using RuboCop version 1.26.0.
3
+ # on 2022-05-03 07:08:32 UTC using RuboCop version 1.26.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -9,9 +9,4 @@
9
9
  # Offense count: 1
10
10
  # Configuration parameters: IgnoredMethods.
11
11
  Metrics/CyclomaticComplexity:
12
- Max: 9
13
-
14
- # Offense count: 1
15
- # Configuration parameters: IgnoredMethods.
16
- Metrics/PerceivedComplexity:
17
- Max: 9
12
+ Max: 8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.6.0](https://github.com/opus-codium/choria-colt/tree/v0.6.0) (2022-05-16)
4
+
5
+ [Full Changelog](https://github.com/opus-codium/choria-colt/compare/v0.5.1...v0.6.0)
6
+
7
+ **Merged pull requests:**
8
+
9
+ - Allow to run a task from any puppet environment [\#28](https://github.com/opus-codium/choria-colt/pull/28) ([neomilium](https://github.com/neomilium))
10
+ - CLI: Use symbol notation to target `:all` nodes [\#27](https://github.com/opus-codium/choria-colt/pull/27) ([neomilium](https://github.com/neomilium))
11
+ - CLI: Allow targeting on task status requests [\#26](https://github.com/opus-codium/choria-colt/pull/26) ([neomilium](https://github.com/neomilium))
12
+ - Fix `task status` command [\#25](https://github.com/opus-codium/choria-colt/pull/25) ([neomilium](https://github.com/neomilium))
13
+
14
+ ## [v0.5.1](https://github.com/opus-codium/choria-colt/tree/v0.5.1) (2022-05-02)
15
+
16
+ [Full Changelog](https://github.com/opus-codium/choria-colt/compare/v0.5.0...v0.5.1)
17
+
18
+ ## [v0.5.0](https://github.com/opus-codium/choria-colt/tree/v0.5.0) (2022-05-02)
19
+
20
+ [Full Changelog](https://github.com/opus-codium/choria-colt/compare/v0.4.0...v0.5.0)
21
+
22
+ **Merged pull requests:**
23
+
24
+ - Process and display RPC errors like execution errors [\#24](https://github.com/opus-codium/choria-colt/pull/24) ([neomilium](https://github.com/neomilium))
25
+ - CLI: Be more green\(washing\) [\#23](https://github.com/opus-codium/choria-colt/pull/23) ([neomilium](https://github.com/neomilium))
26
+ - CLI: Support @file notation on --targets option [\#22](https://github.com/opus-codium/choria-colt/pull/22) ([neomilium](https://github.com/neomilium))
27
+ - Do not pass explicit options to rpcclient [\#21](https://github.com/opus-codium/choria-colt/pull/21) ([smortex](https://github.com/smortex))
28
+
3
29
  ## [v0.4.0](https://github.com/opus-codium/choria-colt/tree/v0.4.0) (2022-04-25)
4
30
 
5
31
  [Full Changelog](https://github.com/opus-codium/choria-colt/compare/v0.3.0...v0.4.0)
data/README.md CHANGED
@@ -51,8 +51,8 @@ To install this gem onto your local machine, run `bundle exec rake install`.
51
51
 
52
52
 
53
53
  To release a new version:
54
- 1. update the version number in `version.rb`
55
- 1. generate CHANGELOG.md with `bundle exec rake changelog`
54
+ 1. update the version number in `lib/choria/colt/version.rb`
55
+ 1. generate `CHANGELOG.md` with `bundle exec rake changelog`
56
56
  1. commit changes
57
57
  1. run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
58
58
 
@@ -5,6 +5,33 @@ module Choria
5
5
  class Colt
6
6
  class CLI < Thor
7
7
  class Formatter
8
+ module Result
9
+ def sender
10
+ self[:sender]
11
+ end
12
+
13
+ def exitcode
14
+ dig(:data, :exitcode)
15
+ end
16
+
17
+ def ok?
18
+ exitcode&.zero?
19
+ end
20
+
21
+ def runtime
22
+ dig(:data, :runtime)
23
+ end
24
+
25
+ # CLI
26
+ def output
27
+ if dig(:result, :_output).nil?
28
+ JSON.pretty_generate(self[:result]).split("\n")
29
+ else
30
+ dig(:result, :_output)
31
+ end
32
+ end
33
+ end
34
+
8
35
  attr_reader :pastel
9
36
 
10
37
  def initialize(colored:)
@@ -13,27 +40,36 @@ module Choria
13
40
  end
14
41
 
15
42
  def process_result(result)
16
- return process_error(result) unless result.dig(:data, :exitcode)&.zero?
43
+ result.extend Formatter::Result
17
44
 
18
- process_success(result)
45
+ case result[:statuscode]
46
+ when 0
47
+ # 0 OK
48
+ process_success(result)
49
+ when 1
50
+ # 1 OK, failed. All the data parsed ok, we have a action matching the request but the requested action could not be completed. RPCAborted
51
+ process_error(result) # unless result.ok?
52
+ else
53
+ # 2 Unknown action UnknownRPCAction
54
+ # 3 Missing data MissingRPCData
55
+ # 4 Invalid data InvalidRPCData
56
+ # 5 Other error
57
+ process_rpc_error(result)
58
+ end
19
59
  end
20
60
 
21
61
  def process_success(result)
22
- output_lines = [
23
- "#{pastel.host(result[:sender]).ljust(60, ' ')}duration: #{pastel.bright_white format('%.2fs', result[:data][:runtime])}",
24
- ]
25
-
26
- output_lines += if result.dig(:result, :_output).nil?
27
- JSON.pretty_generate(result[:result]).split("\n").map { |line| " #{line}" }
28
- else
29
- result.dig(:result, :_output).map { |line| " #{line}" }
30
- end
62
+ host = format_host(result, "#{pastel.bright_green '√'} ")
63
+ headline = "#{pastel.on_green ' '} "
31
64
 
32
- output_lines.join("\n")
65
+ [
66
+ host,
67
+ result.output.map { |line| "#{headline}#{line}" },
68
+ ].flatten.join("\n")
33
69
  end
34
70
 
35
71
  def process_error(result) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
36
- host = "#{pastel.bright_red '⨯'} #{pastel.host(result[:sender]).ljust(60, ' ')}duration: #{pastel.bright_white format('%.2fs', result[:data][:runtime])}"
72
+ host = format_host(result, "#{pastel.bright_red '⨯'} ")
37
73
  output = result.dig(:result, '_output')
38
74
  error_details = JSON.pretty_generate(result.dig(:result, :_error, :details)).split "\n"
39
75
  error_description = [
@@ -61,6 +97,26 @@ module Choria
61
97
  ].flatten.map { |line| "#{headline}#{line}" },
62
98
  ].flatten.join("\n")
63
99
  end
100
+
101
+ def process_rpc_error(result)
102
+ host = "#{pastel.bright_red '⨯'} #{pastel.host(result.sender)}"
103
+ headline = "#{pastel.on_red ' '} "
104
+
105
+ [
106
+ host,
107
+ "#{headline}#{pastel.bright_red "RPC error (#{result[:statuscode]})"}: #{pastel.bright_white result[:statusmsg]}",
108
+ ].join("\n")
109
+ end
110
+
111
+ private
112
+
113
+ def format_duration(result)
114
+ result.runtime.nil? ? '' : "duration: #{pastel.bright_white format('%.2fs', result.runtime)}"
115
+ end
116
+
117
+ def format_host(result, headline)
118
+ "#{headline}#{pastel.host(result.sender).ljust(60, ' ')}#{format_duration(result)}"
119
+ end
64
120
  end
65
121
  end
66
122
  end
@@ -9,6 +9,15 @@ module Choria
9
9
  class Colt
10
10
  class CLI < Thor
11
11
  class Tasks < Thor
12
+ def self.define_targets_and_filters_options
13
+ option :targets,
14
+ aliases: ['--target', '-t'],
15
+ desc: 'Identifies the targets of the command.'
16
+ option :targets_with_classes,
17
+ aliases: ['--targets-with-class', '-C'],
18
+ desc: 'Select the targets which have the specified Puppet classes.'
19
+ end
20
+
12
21
  class_option :log_level,
13
22
  desc: 'Set log level for CLI',
14
23
  default: 'info'
@@ -19,34 +28,28 @@ module Choria
19
28
 
20
29
  Parameters take the form parameter=value.
21
30
  DESC
22
- option :targets,
23
- aliases: ['--target', '-t'],
24
- desc: 'Identifies the targets of the command.'
25
- option :targets_with_classes,
26
- aliases: ['--targets-with-class', '-C'],
27
- desc: 'Select the targets which have the specified Puppet classes.'
28
- def run(*args) # rubocop:disable Metrics/AbcSize
29
- input = extract_task_parameters_from_args(args)
30
-
31
+ define_targets_and_filters_options
32
+ option :environment,
33
+ aliases: ['-E'],
34
+ desc: 'Puppet environment to grab tasks from',
35
+ default: 'production'
36
+ def run(*args)
31
37
  raise Thor::Error, 'Task name is required' if args.empty?
32
- raise Thor::Error, "Too many arguments: #{args}" unless args.count == 1
33
38
 
34
- raise Thor::Error, 'Flag --targets or --targets-with-class is required' if options['targets'].nil? && options['targets_with_classes'].nil?
39
+ input = extract_task_parameters_from_args(args)
40
+ raise Thor::Error, "Too many arguments: #{args}" unless args.count == 1
35
41
 
36
42
  task_name = args.shift
43
+ targets, targets_with_classes = extract_targets_and_filters_from_options
37
44
 
38
- targets = options['targets']&.split(',')
39
- targets = nil if options['targets'] == 'all'
40
-
41
- targets_with_classes = options['targets_with_classes']&.split(',')
42
-
43
- results = colt.run_bolt_task task_name, input: input, targets: targets, targets_with_classes: targets_with_classes do |result|
45
+ environment = options['environment']
46
+ results = colt.run_bolt_task task_name, input: input, targets: targets, targets_with_classes: targets_with_classes, environment: environment do |result|
44
47
  $stdout.puts formatter.process_result(result)
45
48
  end
46
49
 
47
50
  File.write 'last_run.json', JSON.pretty_generate(results)
48
- rescue Choria::Orchestrator::Error => e
49
- raise Thor::Error, "#{e.class}: #{e}"
51
+ rescue Choria::Orchestrator::Error
52
+ # This error is already logged and displayed.
50
53
  end
51
54
 
52
55
  desc 'show [task name] [options]', 'Show available tasks and task documentation'
@@ -84,14 +87,17 @@ module Choria
84
87
 
85
88
  A task ID is required to request Choria services and retrieve results.
86
89
  DESC
90
+ define_targets_and_filters_options
87
91
  def status(task_id)
88
- results = colt.wait_bolt_task task_id do |result|
92
+ targets, targets_with_classes = extract_targets_and_filters_from_options
93
+
94
+ results = colt.wait_bolt_task(task_id, targets: targets, targets_with_classes: targets_with_classes) do |result|
89
95
  $stdout.puts formatter.process_result(result)
90
96
  end
91
97
 
92
98
  File.write 'last_run.json', JSON.pretty_generate(results)
93
- rescue Choria::Orchestrator::Error => e
94
- raise Thor::Error, "#{e.class}: #{e}"
99
+ rescue Choria::Orchestrator::Error
100
+ # This error is already logged and displayed.
95
101
  end
96
102
 
97
103
  no_commands do # rubocop:disable Metrics/BlockLength
@@ -130,6 +136,25 @@ module Choria
130
136
  end.to_h
131
137
  end
132
138
 
139
+ def extract_targets_and_filters_from_options
140
+ raise Thor::Error, 'Flag --targets or --targets-with-class is required' if options['targets'].nil? && options['targets_with_classes'].nil?
141
+
142
+ targets = extract_targets_from_options
143
+ targets_with_classes = options['targets_with_classes']&.split(',')
144
+
145
+ [targets, targets_with_classes]
146
+ end
147
+
148
+ def extract_targets_from_options
149
+ return nil if options['targets'] == ':all'
150
+
151
+ targets = options['targets']&.split(',')
152
+ targets&.map do |t|
153
+ t = File.read(t.sub(/^@/, '')).lines.map(&:strip) if t.start_with? '@'
154
+ t
155
+ end&.flatten
156
+ end
157
+
133
158
  def show_tasks_summary(tasks)
134
159
  tasks.reject! { |_task, metadata| metadata['metadata']['private'] }
135
160
 
@@ -2,6 +2,8 @@ module Choria
2
2
  class Colt
3
3
  module DataStructurer
4
4
  def self.structure(res) # rubocop:disable Metrics/AbcSize
5
+ return res unless [0, 1].include? res[:statuscode]
6
+
5
7
  # data.stdout seems to always be JSON, so parse it once.
6
8
  res[:result] = JSON.parse res[:data][:stdout]
7
9
  res[:data].delete :stdout
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Choria
4
4
  class Colt
5
- VERSION = '0.4.0'
5
+ VERSION = '0.6.0'
6
6
  end
7
7
  end
data/lib/choria/colt.rb CHANGED
@@ -19,9 +19,9 @@ module Choria
19
19
  @orchestrator = Choria::Orchestrator.new logger: @logger
20
20
  end
21
21
 
22
- def run_bolt_task(task_name, input: {}, targets: nil, targets_with_classes: nil, &block)
22
+ def run_bolt_task(task_name, input: {}, targets: nil, targets_with_classes: nil, environment: 'production', &block)
23
23
  logger.debug "Instantiate task '#{task_name}' and validate input"
24
- task = Choria::Orchestrator::Task.new(name: task_name, input: input, orchestrator: orchestrator)
24
+ task = Choria::Orchestrator::Task.new(name: task_name, input: input, environment: environment, orchestrator: orchestrator)
25
25
 
26
26
  task.on_result(&block) if block_given?
27
27
 
@@ -33,11 +33,11 @@ module Choria
33
33
  raise
34
34
  end
35
35
 
36
- def wait_bolt_task(task_id, &block)
37
- task = Choria::Orchestrator::Task.new(id: task_id, orchestrator: orchestrator)
36
+ def wait_bolt_task(task_id, targets: nil, targets_with_classes: nil, &block)
37
+ orchestrator.discover(targets: targets, targets_with_classes: targets_with_classes)
38
38
 
39
+ task = Choria::Orchestrator::Task.new(id: task_id, orchestrator: orchestrator)
39
40
  task.on_result(&block) if block_given?
40
-
41
41
  task.wait
42
42
  task.results
43
43
  rescue Choria::Orchestrator::Error => e
@@ -0,0 +1,28 @@
1
+ require 'choria/colt/data_structurer'
2
+
3
+ module Choria
4
+ class Orchestrator
5
+ class Task
6
+ class ResultSet
7
+ attr_reader :results
8
+
9
+ def initialize(on_result:)
10
+ @results = []
11
+ @on_result = on_result
12
+ end
13
+
14
+ def integrate_rpc_error(rpc_error)
15
+ result = rpc_error[:body]
16
+ result[:sender] = rpc_error[:senderid]
17
+ integrate_result(result)
18
+ end
19
+
20
+ def integrate_result(result)
21
+ structured_result = Choria::Colt::DataStructurer.structure(result).with_indifferent_access
22
+ @results << structured_result
23
+ @on_result&.call(structured_result)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,4 +1,4 @@
1
- require 'choria/colt/data_structurer'
1
+ require_relative 'task/result_set'
2
2
 
3
3
  require 'active_support'
4
4
  require 'active_support/core_ext/hash/indifferent_access'
@@ -7,17 +7,15 @@ module Choria
7
7
  class Orchestrator
8
8
  class Task
9
9
  class Error < Orchestrator::Error; end
10
+ class NoNodesLeftError < Error; end
10
11
 
11
- attr_reader :id, :name, :input, :environment, :rpc_results, :results
12
- attr_accessor :rpc_responses
12
+ attr_reader :id, :name, :input, :environment
13
13
 
14
14
  def initialize(orchestrator:, id: nil, name: nil, input: {}, environment: 'production')
15
15
  @id = id
16
16
  @name = name
17
17
  @environment = environment
18
18
  @orchestrator = orchestrator
19
- @results = []
20
-
21
19
  return if @name.nil?
22
20
 
23
21
  @input = default_input.merge input
@@ -33,71 +31,82 @@ module Choria
33
31
  metadata['files'].to_json
34
32
  end
35
33
 
36
- def wait # rubocop:disable Metrics/AbcSize
37
- if @id.nil?
38
- rpc_responses_ok, rpc_responses_error = rpc_responses.partition { |res| (res[:body][:statuscode]).zero? }
39
- rpc_responses_error.each do |res|
40
- logger.error "Task request failed on '#{res[:senderid]}':\n#{pp res}"
41
- end
34
+ def results
35
+ result_set.results
36
+ end
42
37
 
43
- task_ids = rpc_responses_ok.map { |res| res[:body][:data][:task_id] }.uniq
38
+ def run
39
+ raise Error, 'Unable to run a task by ID' if name.nil?
44
40
 
45
- raise NotImplementedError, "Multiple task IDs: #{task_ids}" unless task_ids.count == 1
41
+ @pending_targets = rpc_client.discover
42
+ _download
43
+ _run_no_wait
44
+ end
46
45
 
47
- @id = task_ids.first
48
- end
46
+ def wait
47
+ raise Error, 'Task ID is required!' if @id.nil?
49
48
 
50
- wait_results
49
+ logger.info "Waiting task #{@id} results…"
50
+ @rpc_results = []
51
+ loop do
52
+ self.rpc_results = rpc_client.task_status(task_id: @id).map(&:results)
53
+ break if @pending_targets.empty?
54
+ end
51
55
  end
52
56
 
53
57
  def on_result(&block)
54
- @on_result = lambda { |result|
55
- block.call(result)
56
- }
58
+ @on_result = ->(result) { block.call(result) }
57
59
  end
58
60
 
59
61
  private
60
62
 
61
- def rpc_results=(results)
62
- new_result_hosts = (results.map { |res| res[:sender] }) - (@results.map { |res| res[:sender] })
63
-
64
- new_result_hosts.each do |host|
65
- result = results.find { |res| res[:sender] == host }
66
-
67
- next unless result[:data][:exitcode] != -1
68
-
69
- logger.debug "New result for task ##{@id}: #{result}"
70
- structured_result = Choria::Colt::DataStructurer.structure(result).with_indifferent_access
71
-
72
- @on_result&.call(structured_result)
63
+ def result_set
64
+ @result_set ||= ResultSet.new(on_result: @on_result)
65
+ end
73
66
 
74
- @results << structured_result
67
+ def rpc_results=(results)
68
+ completed_results = results.reject { |res| res[:data][:exitcode] == -1 }
69
+ @pending_targets ||= results.map { |res| res[:sender] }
70
+
71
+ new_results = completed_results.select { |res| @pending_targets.include? res[:sender] }
72
+ new_results.each do |res|
73
+ logger.debug "New result for task ##{@id}: #{res}"
74
+ result_set.integrate_result(res)
75
+ @pending_targets.delete res[:sender]
75
76
  end
76
-
77
- @rpc_results = results
78
77
  end
79
78
 
80
- def wait_results
81
- raise 'Task ID is required!' if @id.nil?
82
-
83
- logger.info "Waiting task #{@id} results…"
84
-
85
- @results = []
86
- @rpc_results = []
79
+ def process_rpc_response(rpc_response)
80
+ rpc_response.extend Orchestrator::RpcResponse
81
+ logger.debug " RPC Response: '#{rpc_response}'"
82
+ return unless rpc_response.rpc_error?
87
83
 
88
- loop do
89
- self.rpc_results = @orchestrator.rpc_client.task_status(task_id: @id).map(&:results)
84
+ @pending_targets.delete rpc_response.sender
85
+ result_set.integrate_rpc_error(rpc_response)
86
+ end
90
87
 
91
- break if terminated?
88
+ def _download
89
+ logger.info "Downloading task '#{name}' on #{rpc_client.discover.size} nodes…"
90
+ rpc_client.download(task: name, files: files, verbose: false) do |rpc_response|
91
+ process_rpc_response(rpc_response)
92
92
  end
93
+
94
+ raise NoNodesLeftError, "No nodes left to continue after 'download' action" if @pending_targets.empty?
93
95
  end
94
96
 
95
- def terminated?
96
- @rpc_results.each do |result|
97
- return false if result[:data][:exitcode] == -1
97
+ def _run_no_wait # rubocop:disable Metrics/AbcSize
98
+ logger.info "Starting task '#{name}' on #{rpc_client.discover.size} nodes…"
99
+ task_ids = []
100
+ rpc_client.run_no_wait(task: name, files: files, input: input.to_json, verbose: false) do |rpc_response|
101
+ process_rpc_response(rpc_response)
102
+ task_ids << rpc_response.task_id
98
103
  end
104
+ raise NoNodesLeftError, "No nodes left to continue after 'run_no_wait' action" if @pending_targets.empty?
99
105
 
100
- true
106
+ task_ids.uniq!
107
+ raise NotImplementedError, "Multiple task IDs: #{task_ids}" unless task_ids.count == 1
108
+
109
+ @id = task_ids.first
101
110
  end
102
111
 
103
112
  def _metadata
@@ -122,6 +131,10 @@ module Choria
122
131
  def logger
123
132
  @orchestrator.logger
124
133
  end
134
+
135
+ def rpc_client
136
+ @orchestrator.rpc_client
137
+ end
125
138
  end
126
139
  end
127
140
  end
@@ -6,6 +6,24 @@ module Choria
6
6
  class Error < StandardError; end
7
7
  class DiscoverError < Error; end
8
8
 
9
+ module RpcResponse
10
+ def sender
11
+ self[:senderid]
12
+ end
13
+
14
+ def rpc_error?
15
+ !rpc_success?
16
+ end
17
+
18
+ def rpc_success?
19
+ [0, 1].include? self[:body][:statuscode]
20
+ end
21
+
22
+ def task_id
23
+ self[:body][:data][:task_id]
24
+ end
25
+ end
26
+
9
27
  include MCollective::RPC
10
28
 
11
29
  attr_reader :logger
@@ -21,10 +39,16 @@ module Choria
21
39
  @tasks_support ||= MCollective::Util::Choria.new.tasks_support
22
40
  end
23
41
 
24
- def run(task, targets: nil, targets_with_classes: nil, verbose: false) # rubocop:disable Metrics/AbcSize
42
+ def run(task, targets: nil, targets_with_classes: nil, verbose: false)
25
43
  rpc_client.progress = verbose
44
+ discover(targets: targets, targets_with_classes: targets_with_classes)
45
+ raise DiscoverError, 'No requests sent, no nodes discovered' if rpc_client.discover.size.zero?
46
+
47
+ task.run
48
+ end
26
49
 
27
- logger.debug "Running task: '#{task.name}' (targets: #{targets.nil? ? 'all' : targets})"
50
+ def discover(targets: nil, targets_with_classes: nil)
51
+ logger.debug "Targets: #{targets.nil? ? 'all' : targets})"
28
52
  targets&.each { |target| rpc_client.identity_filter target }
29
53
 
30
54
  unless targets_with_classes.nil?
@@ -33,51 +57,11 @@ module Choria
33
57
  end
34
58
 
35
59
  logger.info 'Discovering targets…'
36
- raise DiscoverError, 'No request sent, no node discovered' if rpc_client.discover.size.zero?
37
-
38
- logger.info "Downloading task '#{task.name}' on #{rpc_client.discover.size} nodes…"
39
- rpc_client.download(task: task.name, files: task.files, verbose: verbose)
40
-
41
- responses = []
42
- logger.info "Starting task '#{task.name}' on #{rpc_client.discover.size} nodes…"
43
- rpc_client.run_no_wait(task: task.name, files: task.files, input: task.input.to_json, verbose: verbose) do |response|
44
- logger.debug " Response: '#{response}'"
45
- responses << response
46
- end
47
-
48
- # TODO: Include stats in logs when logger will be available (see MCollective::RPC#printrpcstats)
49
-
50
- task.rpc_responses = responses
51
- end
52
-
53
- def validate_rpc_result(result)
54
- raise Error, "The RPC agent returned an error: #{result[:statusmsg]}" unless (result[:statuscode]).zero?
60
+ rpc_client.discover
55
61
  end
56
62
 
57
63
  def rpc_client
58
- @rpc_client ||= rpcclient('bolt_tasks', options: rpc_options)
59
- end
60
-
61
- private
62
-
63
- def rpc_options
64
- {
65
- verbose: false,
66
- disctimeout: nil,
67
- timeout: 5,
68
- config: '/etc/choria/client.conf',
69
- collective: 'mcollective',
70
- discovery_method: nil,
71
- discovery_options: [],
72
- filter: {
73
- 'fact' => [], 'cf_class' => [], 'agent' => [], 'identity' => [], 'compound' => []
74
- },
75
- progress_bar: false,
76
- mcollective_limit_targets: false,
77
- batch_size: nil,
78
- batch_sleep_time: 1,
79
- output_format: :json,
80
- }
64
+ @rpc_client ||= rpcclient('bolt_tasks', options: {})
81
65
  end
82
66
  end
83
67
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: choria-colt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Romuald Conty
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-25 00:00:00.000000000 Z
11
+ date: 2022-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -218,6 +218,7 @@ files:
218
218
  - lib/choria/colt/version.rb
219
219
  - lib/choria/orchestrator.rb
220
220
  - lib/choria/orchestrator/task.rb
221
+ - lib/choria/orchestrator/task/result_set.rb
221
222
  - sig/choria/colt.rbs
222
223
  homepage: https://github.com/opus-codium/choria-colt
223
224
  licenses: []