choria-colt 0.3.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17cd0f4a8fd7bc14aed8bd1f702405d257c8ab18b31406eb13eb3b3b3d6623cd
4
- data.tar.gz: 9ad55b6d635820f4486476ed9722e23f68f85037f0b94c0ed93d500a64e10e29
3
+ metadata.gz: e5a3d94cfa899f41ced9fc0405ed5f4fb41924267d4b56f6d31ba28420c9b0e7
4
+ data.tar.gz: df5bef6793badb31de0ee0185d0f8d3ca44288fedcf64b34084dbb60d1a6de30
5
5
  SHA512:
6
- metadata.gz: cac0c586629af294b520c29e4967824cd832b257405be6a95ba4e2a552f1a92cba936b22e219ed0342b8b1cfff34b3257a5c3cf5ab6607f66450d864b636ba12
7
- data.tar.gz: 6d6cf405dd1973a4e7d813a58de872a8b37514e821ea90c216a42b3242240895ed1fb4adda8dd24d065fbbf926b7ae186fea610b9e54f5c2e5df3a7fa75b94ef
6
+ metadata.gz: bba0206e6f84679cd6c7ed5fd1831dc8e2beba052b096b265ac272baadeaf20a69585d6165a37ca1f7db2ca48a6fe532eeb77171c75f656bb0aa9f2c50796ccb
7
+ data.tar.gz: 02d6f79e80a664445793596ea9d96f106a14523ba9824893e7c1d43cc2c3484f63e27a1a20173d30e608e48f4d59872db9878385da2b197021d56374c502defa
data/.rubocop.yml CHANGED
@@ -10,6 +10,11 @@ AllCops:
10
10
  Metrics/AbcSize:
11
11
  Max: 20
12
12
 
13
+ Metrics/ClassLength:
14
+ Max: 120
15
+ Exclude:
16
+ - 'lib/choria/colt/cli.rb'
17
+
13
18
  Metrics/MethodLength:
14
19
  Max: 20
15
20
 
data/.rubocop_todo.yml CHANGED
@@ -1,22 +1,17 @@
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-04-28 09:34:37 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
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
9
  # Offense count: 1
10
- # Configuration parameters: CountComments, CountAsOne.
11
- Metrics/ClassLength:
12
- Max: 109
10
+ # Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
11
+ Metrics/AbcSize:
12
+ Max: 22
13
13
 
14
14
  # Offense count: 1
15
15
  # Configuration parameters: IgnoredMethods.
16
16
  Metrics/CyclomaticComplexity:
17
- Max: 9
18
-
19
- # Offense count: 1
20
- # Configuration parameters: IgnoredMethods.
21
- Metrics/PerceivedComplexity:
22
- Max: 9
17
+ Max: 8
data/CHANGELOG.md ADDED
@@ -0,0 +1,58 @@
1
+ # Changelog
2
+
3
+ ## [v0.5.0](https://github.com/opus-codium/choria-colt/tree/v0.5.0) (2022-05-02)
4
+
5
+ [Full Changelog](https://github.com/opus-codium/choria-colt/compare/v0.4.0...v0.5.0)
6
+
7
+ **Merged pull requests:**
8
+
9
+ - Process and display RPC errors like execution errors [\#24](https://github.com/opus-codium/choria-colt/pull/24) ([neomilium](https://github.com/neomilium))
10
+ - CLI: Be more green\(washing\) [\#23](https://github.com/opus-codium/choria-colt/pull/23) ([neomilium](https://github.com/neomilium))
11
+ - CLI: Support @file notation on --targets option [\#22](https://github.com/opus-codium/choria-colt/pull/22) ([neomilium](https://github.com/neomilium))
12
+ - Do not pass explicit options to rpcclient [\#21](https://github.com/opus-codium/choria-colt/pull/21) ([smortex](https://github.com/smortex))
13
+
14
+ ## [v0.4.0](https://github.com/opus-codium/choria-colt/tree/v0.4.0) (2022-04-25)
15
+
16
+ [Full Changelog](https://github.com/opus-codium/choria-colt/compare/v0.3.0...v0.4.0)
17
+
18
+ **Merged pull requests:**
19
+
20
+ - Spec: Fix tests after duration introduction [\#20](https://github.com/opus-codium/choria-colt/pull/20) ([neomilium](https://github.com/neomilium))
21
+ - CLI: Add `colt task status` subcommand [\#19](https://github.com/opus-codium/choria-colt/pull/19) ([neomilium](https://github.com/neomilium))
22
+
23
+ ## [v0.3.0](https://github.com/opus-codium/choria-colt/tree/v0.3.0) (2022-04-12)
24
+
25
+ [Full Changelog](https://github.com/opus-codium/choria-colt/compare/v0.2.0...v0.3.0)
26
+
27
+ **Merged pull requests:**
28
+
29
+ - Improve CLI output [\#18](https://github.com/opus-codium/choria-colt/pull/18) ([neomilium](https://github.com/neomilium))
30
+ - CLI: Add an option to choose log level [\#17](https://github.com/opus-codium/choria-colt/pull/17) ([neomilium](https://github.com/neomilium))
31
+ - Improve stability, fix results retrieving [\#16](https://github.com/opus-codium/choria-colt/pull/16) ([neomilium](https://github.com/neomilium))
32
+ - CLI: Add an option to set log level [\#15](https://github.com/opus-codium/choria-colt/pull/15) ([neomilium](https://github.com/neomilium))
33
+ - Setup CI [\#14](https://github.com/opus-codium/choria-colt/pull/14) ([neomilium](https://github.com/neomilium))
34
+ - CLI: Format error [\#13](https://github.com/opus-codium/choria-colt/pull/13) ([neomilium](https://github.com/neomilium))
35
+ - CLI: Display default value if available for parameters [\#12](https://github.com/opus-codium/choria-colt/pull/12) ([neomilium](https://github.com/neomilium))
36
+ - Test CLI formatter using RSpec [\#11](https://github.com/opus-codium/choria-colt/pull/11) ([neomilium](https://github.com/neomilium))
37
+ - Colorize outputs [\#10](https://github.com/opus-codium/choria-colt/pull/10) ([neomilium](https://github.com/neomilium))
38
+ - Fix task input option parsing and task output display [\#9](https://github.com/opus-codium/choria-colt/pull/9) ([neomilium](https://github.com/neomilium))
39
+ - Implement continous result display [\#8](https://github.com/opus-codium/choria-colt/pull/8) ([neomilium](https://github.com/neomilium))
40
+ - Improve robustness on errors [\#7](https://github.com/opus-codium/choria-colt/pull/7) ([neomilium](https://github.com/neomilium))
41
+ - Minor code readability improvements [\#6](https://github.com/opus-codium/choria-colt/pull/6) ([neomilium](https://github.com/neomilium))
42
+ - Improve logging [\#5](https://github.com/opus-codium/choria-colt/pull/5) ([neomilium](https://github.com/neomilium))
43
+ - Force convertion to boolean if parameter is true/false [\#4](https://github.com/opus-codium/choria-colt/pull/4) ([neomilium](https://github.com/neomilium))
44
+ - Tasks: Autofill default values [\#3](https://github.com/opus-codium/choria-colt/pull/3) ([neomilium](https://github.com/neomilium))
45
+ - CLI: Support filter on Puppet classes [\#2](https://github.com/opus-codium/choria-colt/pull/2) ([neomilium](https://github.com/neomilium))
46
+ - Tasks: Structure data before return results [\#1](https://github.com/opus-codium/choria-colt/pull/1) ([neomilium](https://github.com/neomilium))
47
+
48
+ ## [v0.2.0](https://github.com/opus-codium/choria-colt/tree/v0.2.0) (2022-03-03)
49
+
50
+ [Full Changelog](https://github.com/opus-codium/choria-colt/compare/v0.1.1...v0.2.0)
51
+
52
+ ## [v0.1.1](https://github.com/opus-codium/choria-colt/tree/v0.1.1) (2022-03-03)
53
+
54
+ [Full Changelog](https://github.com/opus-codium/choria-colt/compare/v0.1.0...v0.1.1)
55
+
56
+
57
+
58
+ \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
data/README.md CHANGED
@@ -47,7 +47,14 @@ Or install it yourself as:
47
47
 
48
48
  After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
49
49
 
50
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then 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).
50
+ To install this gem onto your local machine, run `bundle exec rake install`.
51
+
52
+
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`
56
+ 1. commit changes
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).
51
58
 
52
59
  ## Contributing
53
60
 
data/Rakefile CHANGED
@@ -3,6 +3,17 @@
3
3
  require 'bundler/gem_tasks'
4
4
  require 'rubocop/rake_task'
5
5
 
6
+ require 'choria/colt/version'
7
+
6
8
  RuboCop::RakeTask.new
7
9
 
10
+ require 'github_changelog_generator/task'
11
+
12
+ GitHubChangelogGenerator::RakeTask.new :changelog do |config|
13
+ config.user = 'opus-codium'
14
+ config.project = 'choria-colt'
15
+ config.since_tag = 'v0.1.0'
16
+ config.future_release = "v#{Choria::Colt::VERSION}"
17
+ end
18
+
8
19
  task default: :rubocop
data/choria-colt.gemspec CHANGED
@@ -37,6 +37,7 @@ Gem::Specification.new do |spec|
37
37
  spec.add_dependency 'tty-logger'
38
38
 
39
39
  # spec.add_development_dependency 'byebug'
40
+ spec.add_development_dependency 'github_changelog_generator'
40
41
  spec.add_development_dependency 'rake'
41
42
  spec.add_development_dependency 'rspec'
42
43
  spec.add_development_dependency 'rubocop'
@@ -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 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
- def process_error(result) # rubocop:disable Metrics/AbcSize
36
- host = "#{pastel.bright_red '⨯'} #{pastel.host(result[:sender]).ljust(60, ' ')}duration: #{pastel.bright_white result[:data][:runtime]}"
71
+ def process_error(result) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
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
@@ -27,6 +27,7 @@ module Choria
27
27
  desc: 'Select the targets which have the specified Puppet classes.'
28
28
  def run(*args) # rubocop:disable Metrics/AbcSize
29
29
  input = extract_task_parameters_from_args(args)
30
+ targets = extract_targets_from_options
30
31
 
31
32
  raise Thor::Error, 'Task name is required' if args.empty?
32
33
  raise Thor::Error, "Too many arguments: #{args}" unless args.count == 1
@@ -35,8 +36,7 @@ module Choria
35
36
 
36
37
  task_name = args.shift
37
38
 
38
- targets = options['targets']&.split(',')
39
- targets = nil if options['targets'] == 'all'
39
+ logger.debug "Targets: #{targets}"
40
40
 
41
41
  targets_with_classes = options['targets_with_classes']&.split(',')
42
42
 
@@ -45,8 +45,8 @@ module Choria
45
45
  end
46
46
 
47
47
  File.write 'last_run.json', JSON.pretty_generate(results)
48
- rescue Choria::Orchestrator::Error => e
49
- raise Thor::Error, "#{e.class}: #{e}"
48
+ rescue Choria::Orchestrator::Error
49
+ # This error is already logged and displayed.
50
50
  end
51
51
 
52
52
  desc 'show [task name] [options]', 'Show available tasks and task documentation'
@@ -78,6 +78,22 @@ module Choria
78
78
  end
79
79
  end
80
80
 
81
+ desc 'status <task id>', 'Show task results'
82
+ long_desc <<~DESC
83
+ Show results from a previously ran task.
84
+
85
+ A task ID is required to request Choria services and retrieve results.
86
+ DESC
87
+ def status(task_id)
88
+ results = colt.wait_bolt_task task_id do |result|
89
+ $stdout.puts formatter.process_result(result)
90
+ end
91
+
92
+ File.write 'last_run.json', JSON.pretty_generate(results)
93
+ rescue Choria::Orchestrator::Error
94
+ # This error is already logged and displayed.
95
+ end
96
+
81
97
  no_commands do # rubocop:disable Metrics/BlockLength
82
98
  def colt
83
99
  @colt ||= Choria::Colt.new logger: logger
@@ -114,6 +130,16 @@ module Choria
114
130
  end.to_h
115
131
  end
116
132
 
133
+ def extract_targets_from_options
134
+ return nil if options['targets'] == 'all'
135
+
136
+ targets = options['targets']&.split(',')
137
+ targets&.map do |t|
138
+ t = File.read(t.sub(/^@/, '')).lines.map(&:strip) if t.start_with? '@'
139
+ t
140
+ end&.flatten
141
+ end
142
+
117
143
  def show_tasks_summary(tasks)
118
144
  tasks.reject! { |_task, metadata| metadata['metadata']['private'] }
119
145
 
@@ -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.3.0'
5
+ VERSION = '0.5.1'
6
6
  end
7
7
  end
data/lib/choria/colt.rb CHANGED
@@ -21,7 +21,7 @@ module Choria
21
21
 
22
22
  def run_bolt_task(task_name, input: {}, targets: nil, targets_with_classes: nil, &block)
23
23
  logger.debug "Instantiate task '#{task_name}' and validate input"
24
- task = Choria::Orchestrator::Task.new(task_name, input: input, orchestrator: orchestrator)
24
+ task = Choria::Orchestrator::Task.new(name: task_name, input: input, orchestrator: orchestrator)
25
25
 
26
26
  task.on_result(&block) if block_given?
27
27
 
@@ -33,6 +33,18 @@ 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)
38
+
39
+ task.on_result(&block) if block_given?
40
+
41
+ task.wait
42
+ task.results
43
+ rescue Choria::Orchestrator::Error => e
44
+ logger.error e.message
45
+ raise
46
+ end
47
+
36
48
  def tasks(environment:, cache: nil)
37
49
  tasks_names = orchestrator.tasks_support.tasks(environment).map do |task|
38
50
  task['name']
@@ -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,18 +7,18 @@ 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 :name, :input, :environment, :rpc_results, :results
12
- attr_accessor :rpc_responses
12
+ attr_reader :id, :name, :input, :environment
13
13
 
14
- def initialize(name, orchestrator:, input: {}, environment: 'production')
14
+ def initialize(orchestrator:, id: nil, name: nil, input: {}, environment: 'production')
15
+ @id = id
15
16
  @name = name
16
17
  @environment = environment
17
18
  @orchestrator = orchestrator
18
- @input = default_input.merge input
19
-
20
- @results = []
19
+ return if @name.nil?
21
20
 
21
+ @input = default_input.merge input
22
22
  logger.debug "Task inputs: #{input}"
23
23
  validate_inputs
24
24
  end
@@ -31,69 +31,82 @@ module Choria
31
31
  metadata['files'].to_json
32
32
  end
33
33
 
34
- def wait # rubocop:disable Metrics/AbcSize
35
- rpc_responses_ok, rpc_responses_error = rpc_responses.partition { |res| (res[:body][:statuscode]).zero? }
36
- rpc_responses_error.each do |res|
37
- logger.error "Task request failed on '#{res[:senderid]}':\n#{pp res}"
38
- end
34
+ def results
35
+ result_set.results
36
+ end
39
37
 
40
- 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?
41
40
 
42
- 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
43
45
 
44
- @id = task_ids.first
46
+ def wait
47
+ raise Error, 'Task ID is required!' if @id.nil?
45
48
 
46
- 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
47
55
  end
48
56
 
49
57
  def on_result(&block)
50
- @on_result = lambda { |result|
51
- block.call(result)
52
- }
58
+ @on_result = ->(result) { block.call(result) }
53
59
  end
54
60
 
55
61
  private
56
62
 
57
- def rpc_results=(results)
58
- new_result_hosts = (results.map { |res| res[:sender] }) - (@results.map { |res| res[:sender] })
59
-
60
- new_result_hosts.each do |host|
61
- result = results.find { |res| res[:sender] == host }
62
-
63
- next unless result[:data][:exitcode] != -1
64
-
65
- logger.debug "New result for task ##{@id}: #{result}"
66
- structured_result = Choria::Colt::DataStructurer.structure(result).with_indifferent_access
67
-
68
- @on_result&.call(structured_result)
63
+ def result_set
64
+ @result_set ||= ResultSet.new(on_result: @on_result)
65
+ end
69
66
 
70
- @results << structured_result
67
+ def rpc_results=(results)
68
+ pending_results, completed_results = results.partition { |res| res[:data][:exitcode] == -1 }
69
+ @pending_targets ||= pending_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]
71
76
  end
72
-
73
- @rpc_results = results
74
77
  end
75
78
 
76
- def wait_results
77
- raise 'Task ID is required!' if @id.nil?
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?
78
83
 
79
- logger.info 'Waiting task results…'
80
-
81
- @results = []
82
- @rpc_results = []
83
-
84
- loop do
85
- 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
86
87
 
87
- 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)
88
92
  end
93
+
94
+ raise NoNodesLeftError, "No nodes left to continue after 'download' action" if @pending_targets.empty?
89
95
  end
90
96
 
91
- def terminated?
92
- @rpc_results.each do |result|
93
- 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
94
103
  end
104
+ raise NoNodesLeftError, "No nodes left to continue after 'run_no_wait' action" if @pending_targets.empty?
105
+
106
+ task_ids.uniq!
107
+ raise NotImplementedError, "Multiple task IDs: #{task_ids}" unless task_ids.count == 1
95
108
 
96
- true
109
+ @id = task_ids.first
97
110
  end
98
111
 
99
112
  def _metadata
@@ -118,6 +131,10 @@ module Choria
118
131
  def logger
119
132
  @orchestrator.logger
120
133
  end
134
+
135
+ def rpc_client
136
+ @orchestrator.rpc_client
137
+ end
121
138
  end
122
139
  end
123
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
@@ -33,51 +51,13 @@ module Choria
33
51
  end
34
52
 
35
53
  logger.info 'Discovering targets…'
36
- raise DiscoverError, 'No request sent, no node discovered' if rpc_client.discover.size.zero?
54
+ raise DiscoverError, 'No requests sent, no nodes discovered' if rpc_client.discover.size.zero?
37
55
 
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?
56
+ task.run
55
57
  end
56
58
 
57
59
  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
- }
60
+ @rpc_client ||= rpcclient('bolt_tasks', options: {})
81
61
  end
82
62
  end
83
63
  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.3.0
4
+ version: 0.5.1
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-12 00:00:00.000000000 Z
11
+ date: 2022-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: github_changelog_generator
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: rake
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -189,6 +203,7 @@ files:
189
203
  - ".rspec"
190
204
  - ".rubocop.yml"
191
205
  - ".rubocop_todo.yml"
206
+ - CHANGELOG.md
192
207
  - Gemfile
193
208
  - README.md
194
209
  - Rakefile
@@ -203,6 +218,7 @@ files:
203
218
  - lib/choria/colt/version.rb
204
219
  - lib/choria/orchestrator.rb
205
220
  - lib/choria/orchestrator/task.rb
221
+ - lib/choria/orchestrator/task/result_set.rb
206
222
  - sig/choria/colt.rbs
207
223
  homepage: https://github.com/opus-codium/choria-colt
208
224
  licenses: []