foreman-tasks-core 0.3.0 → 0.3.5

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: cf0691634b81dc717a0678d8dbbf78da4489fe4a4ad8e141815c0715de637192
4
- data.tar.gz: 49f3a9a18cd5cd1bee5405b9272ef9cba77476bc57973ac1dc87e65a98eebf4e
3
+ metadata.gz: 9eeba72428b030c0bcec9f51c7b58cbfb7e046eb7279b68b6030b46aaa72a434
4
+ data.tar.gz: 9a40808da08504914c856d9407a7d454a5c5045125a768ee5d6b54424444bd93
5
5
  SHA512:
6
- metadata.gz: 519b03fc48675250a25bb0c75d49fa6f335c1e8c904acc7fe57d7f5b6b143d25cf3b6effd7ae4554fd69796f9648eb13ef1e9e853366a22c17bbb8dae75e4978
7
- data.tar.gz: f7009108c1a9c5e515e37213e435e91cb35a704d72c650576a1331d6395cacf2c7fc2d8cedda1363de33384c59b3dbe55f38d871143e8c7b405bed00d1a76ec4
6
+ metadata.gz: c9cd9a1e5c8f247bd5b3f335998d2cba76d2a17ba6edfae529713f6eaaa60de6133d61125e76175544a8248f259f48bfa715de46cd4f1ff5132844d1c5c0250d
7
+ data.tar.gz: 2ddb3a83487315cdbc6ecf32886d67f599badb47f61f02019122fed0103602af72f0c8e5f999016dfec36a3caa56c17202fb3ce0426f5814084d5703bd702991
@@ -4,6 +4,12 @@
4
4
  require 'foreman_tasks_core/settings_loader'
5
5
  require 'foreman_tasks_core/otp_manager'
6
6
  require 'foreman_tasks_core/ticker'
7
+ require 'foreman_tasks_core/batch_action'
8
+ require 'foreman_tasks_core/batch_callback_action'
9
+ require 'foreman_tasks_core/batch_runner_action'
10
+ require 'foreman_tasks_core/output_collector_action'
11
+ require 'foreman_tasks_core/single_runner_batch_action'
12
+ require 'foreman_tasks_core/task_launcher'
7
13
 
8
14
  module ForemanTasksCore
9
15
  def self.dynflow_world
@@ -0,0 +1,21 @@
1
+ module ForemanTasksCore
2
+ class BatchAction < ::Dynflow::Action
3
+ include Dynflow::Action::WithSubPlans
4
+ include Dynflow::Action::WithPollingSubPlans
5
+
6
+ # { task_id => { :action_class => Klass, :input => input } }
7
+ def plan(launcher, input_hash)
8
+ launcher.launch_children(self, input_hash)
9
+ plan_self
10
+ end
11
+
12
+ def initiate
13
+ ping suspended_action
14
+ wait_for_sub_plans sub_plans
15
+ end
16
+
17
+ def rescue_strategy
18
+ Dynflow::Action::Rescue::Fail
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ module ForemanTasksCore
2
+ class BatchCallback < ::Dynflow::Action
3
+ def plan(input_hash, results)
4
+ plan_self :targets => input_hash, :results => results
5
+ end
6
+
7
+ def run
8
+ payload = format_payload(input['targets'], input['results'])
9
+ SmartProxyDynflowCore::Callback::Request.new.callback({ :callbacks => payload }.to_json)
10
+ end
11
+
12
+ private
13
+
14
+ def format_payload(input_hash, results)
15
+ input_hash.map do |task_id, callback|
16
+ { :callback => callback, :data => results[task_id] }
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ require 'foreman_tasks_core/runner/action'
2
+
3
+ module ForemanTasksCore
4
+ class BatchRunnerAction < ::ForemanTasksCore::Runner::Action
5
+ def plan(launcher, input)
6
+ plan_self :targets => launcher.runner_input(input), :operation => launcher.operation
7
+ end
8
+
9
+ def initiate_runner
10
+ launcher = SmartProxyDynflowCore::TaskLauncherRegistry.fetch(input[:operation])
11
+ launcher.runner_class.new(input[:targets], suspended_action: suspended_action)
12
+ end
13
+ end
14
+ end
@@ -17,10 +17,15 @@ module ForemanTasksCore
17
17
  @password ||= {}
18
18
  end
19
19
 
20
- def authenticate(hash)
20
+ def authenticate(hash, expected_user: nil, clear: true)
21
21
  plain = Base64.decode64(hash)
22
22
  username, otp = plain.split(':', 2)
23
- drop_otp(username, otp)
23
+ if expected_user
24
+ return false unless expected_user == username
25
+ end
26
+ password_matches = passwords[username] == otp
27
+ passwords.delete(username) if clear && password_matches
28
+ password_matches
24
29
  end
25
30
 
26
31
  def tokenize(username, password)
@@ -0,0 +1,8 @@
1
+ module ForemanTasksCore
2
+ class OutputCollectorAction < ::ForemanTasksCore::Runner::Action
3
+ def init_run
4
+ output[:result] = []
5
+ suspend
6
+ end
7
+ end
8
+ end
@@ -7,3 +7,4 @@ require 'foreman_tasks_core/runner/update'
7
7
  require 'foreman_tasks_core/runner/base'
8
8
  require 'foreman_tasks_core/runner/dispatcher'
9
9
  require 'foreman_tasks_core/runner/action'
10
+ require 'foreman_tasks_core/runner/parent'
@@ -6,9 +6,10 @@ module ForemanTasksCore
6
6
  attr_reader :id
7
7
  attr_writer :logger
8
8
 
9
- def initialize(*_args)
9
+ def initialize(*_args, suspended_action: nil)
10
+ @suspended_action = suspended_action
10
11
  @id = SecureRandom.uuid
11
- @continuous_output = ::ForemanTasksCore::ContinuousOutput.new
12
+ initialize_continuous_outputs
12
13
  end
13
14
 
14
15
  def logger
@@ -18,11 +19,14 @@ module ForemanTasksCore
18
19
  def run_refresh
19
20
  logger.debug('refreshing runner')
20
21
  refresh
21
- new_data = @continuous_output
22
- @continuous_output = ForemanTasksCore::ContinuousOutput.new
23
- if !new_data.empty? || @exit_status
24
- return Runner::Update.new(new_data, @exit_status)
25
- end
22
+ generate_updates
23
+ end
24
+
25
+ # by default, external event just causes the refresh to be triggered: this allows the descendants
26
+ # of the Base to add custom logic to process the external events.
27
+ # Similarly as `run_refresh`, it's expected to return updates to be dispatched.
28
+ def external_event(_event)
29
+ run_refresh
26
30
  end
27
31
 
28
32
  def start
@@ -59,13 +63,36 @@ module ForemanTasksCore
59
63
  def publish_exception(context, exception, fatal = true)
60
64
  logger.error("#{context} - #{exception.class} #{exception.message}:\n" + \
61
65
  exception.backtrace.join("\n"))
62
- @continuous_output.add_exception(context, exception)
66
+ dispatch_exception context, exception
63
67
  publish_exit_status('EXCEPTION') if fatal
64
68
  end
65
69
 
66
70
  def publish_exit_status(status)
67
71
  @exit_status = status
68
72
  end
73
+
74
+ def dispatch_exception(context, exception)
75
+ @continuous_output.add_exception(context, exception)
76
+ end
77
+
78
+ def generate_updates
79
+ return no_update if @continuous_output.empty? && @exit_status.nil?
80
+ new_data = @continuous_output
81
+ @continuous_output = ForemanTasksCore::ContinuousOutput.new
82
+ new_update(new_data, @exit_status)
83
+ end
84
+
85
+ def no_update
86
+ {}
87
+ end
88
+
89
+ def new_update(data, exit_status)
90
+ { @suspended_action => Runner::Update.new(data, exit_status) }
91
+ end
92
+
93
+ def initialize_continuous_outputs
94
+ @continuous_output = ::ForemanTasksCore::ContinuousOutput.new
95
+ end
69
96
  end
70
97
  end
71
98
  end
@@ -0,0 +1,40 @@
1
+ module ForemanTasksCore
2
+ module Runner
3
+ module Command
4
+ def initialize_command(*command)
5
+ @command_out, @command_in, @command_pid = PTY.spawn(*command)
6
+ rescue Errno::ENOENT => e
7
+ publish_exception("Error running command '#{command.join(' ')}'", e)
8
+ end
9
+
10
+ def refresh
11
+ return if @command_out.nil?
12
+ ready_outputs, * = IO.select([@command_out], nil, nil, 0.1)
13
+ if ready_outputs
14
+ if @command_out.nread > 0
15
+ lines = @command_out.read_nonblock(@command_out.nread)
16
+ else
17
+ close_io
18
+ Process.wait(@command_pid)
19
+ publish_exit_status($CHILD_STATUS.exitstatus)
20
+ end
21
+ publish_data(lines, 'stdout') if lines && !lines.empty?
22
+ end
23
+ end
24
+
25
+ def close
26
+ close_io
27
+ end
28
+
29
+ private
30
+
31
+ def close_io
32
+ @command_out.close if @command_out && !@command_out.closed?
33
+ @command_out = nil
34
+
35
+ @command_in.close if @command_in && !@command_in.closed?
36
+ @command_in = nil
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,41 +1,11 @@
1
1
  require 'io/wait'
2
2
  require 'pty'
3
+ require 'foreman_tasks_core/runner/command'
3
4
 
4
5
  module ForemanTasksCore
5
6
  module Runner
6
- class CommandRunner < Runner::Base
7
- def initialize_command(*command)
8
- @command_out, @command_in, @command_pid = PTY.spawn(*command)
9
- end
10
-
11
- def refresh
12
- return if @command_out.nil?
13
- ready_outputs, * = IO.select([@command_out], nil, nil, 0.1)
14
- if ready_outputs
15
- if @command_out.nread > 0
16
- lines = @command_out.read_nonblock(@command_out.nread)
17
- else
18
- close_io
19
- Process.wait(@command_pid)
20
- publish_exit_status($CHILD_STATUS.exitstatus)
21
- end
22
- publish_data(lines, 'stdout') if lines && !lines.empty?
23
- end
24
- end
25
-
26
- def close
27
- close_io
28
- end
29
-
30
- private
31
-
32
- def close_io
33
- @command_out.close if @command_out && !@command_out.closed?
34
- @command_out = nil
35
-
36
- @command_in.close if @command_in && !@command_in.closed?
37
- @command_in = nil
38
- end
7
+ class CommandRunner < Base
8
+ include Command
39
9
  end
40
10
  end
41
11
  end
@@ -37,15 +37,21 @@ module ForemanTasksCore
37
37
 
38
38
  def refresh_runner
39
39
  @logger.debug("refresh runner #{@runner.id}")
40
- if (update = @runner.run_refresh)
41
- @suspended_action << update
42
- finish if update.exit_status
43
- end
40
+ dispatch_updates(@runner.run_refresh)
44
41
  ensure
45
42
  @refresh_planned = false
46
43
  plan_next_refresh
47
44
  end
48
45
 
46
+ def dispatch_updates(updates)
47
+ updates.each { |receiver, update| (receiver || @suspended_action) << update }
48
+
49
+ # This is a workaround when the runner does not accept the suspended action
50
+ main_key = updates.keys.any?(&:nil?) ? nil : @suspended_action
51
+ main_process = updates[main_key]
52
+ finish if main_process && main_process.exit_status
53
+ end
54
+
49
55
  def timeout_runner
50
56
  @logger.debug("timeout runner #{@runner.id}")
51
57
  @runner.timeout
@@ -73,8 +79,8 @@ module ForemanTasksCore
73
79
  finish_termination
74
80
  end
75
81
 
76
- def external_event(_event)
77
- refresh_runner
82
+ def external_event(event)
83
+ dispatch_updates(@runner.external_event(event))
78
84
  end
79
85
 
80
86
  private
@@ -114,39 +120,33 @@ module ForemanTasksCore
114
120
 
115
121
  def start(suspended_action, runner)
116
122
  synchronize do
117
- begin
118
- raise "Actor with runner id #{runner.id} already exists" if @runner_actors[runner.id]
119
- runner.logger = @logger
120
- runner_actor = RunnerActor.spawn("runner-actor-#{runner.id}", self, suspended_action, runner, @clock, @logger)
121
- @runner_actors[runner.id] = runner_actor
122
- @runner_suspended_actions[runner.id] = suspended_action
123
- runner_actor.tell(:start_runner)
124
- return runner.id
125
- rescue => exception
126
- _handle_command_exception(runner.id, exception)
127
- return nil
128
- end
123
+ raise "Actor with runner id #{runner.id} already exists" if @runner_actors[runner.id]
124
+ runner.logger = @logger
125
+ runner_actor = RunnerActor.spawn("runner-actor-#{runner.id}", self, suspended_action, runner, @clock, @logger)
126
+ @runner_actors[runner.id] = runner_actor
127
+ @runner_suspended_actions[runner.id] = suspended_action
128
+ runner_actor.tell(:start_runner)
129
+ return runner.id
130
+ rescue => exception
131
+ _handle_command_exception(runner.id, exception)
132
+ return nil
129
133
  end
130
134
  end
131
135
 
132
136
  def kill(runner_id)
133
137
  synchronize do
134
- begin
135
- runner_actor = @runner_actors[runner_id]
136
- runner_actor.tell(:kill) if runner_actor
137
- rescue => exception
138
- _handle_command_exception(runner_id, exception, false)
139
- end
138
+ runner_actor = @runner_actors[runner_id]
139
+ runner_actor.tell(:kill) if runner_actor
140
+ rescue => exception
141
+ _handle_command_exception(runner_id, exception, false)
140
142
  end
141
143
  end
142
144
 
143
145
  def finish(runner_id)
144
146
  synchronize do
145
- begin
146
- _finish(runner_id)
147
- rescue => exception
148
- _handle_command_exception(runner_id, exception, false)
149
- end
147
+ _finish(runner_id)
148
+ rescue => exception
149
+ _handle_command_exception(runner_id, exception, false)
150
150
  end
151
151
  end
152
152
 
@@ -0,0 +1,57 @@
1
+ module ForemanTasksCore
2
+ module Runner
3
+ class Parent < Base
4
+ # targets = { identifier => { :execution_plan_id => "...", :run_step_id => id,
5
+ # :input => { ... } }
6
+ def initialize(targets = {}, suspended_action: nil)
7
+ @targets = targets
8
+ @exit_statuses = {}
9
+ super suspended_action: suspended_action
10
+ end
11
+
12
+ def generate_updates
13
+ base = {}
14
+ base[@suspended_action] = Runner::Update.new(ForemanTasksCore::ContinuousOutput.new, @exit_status) if @exit_status
15
+ # Operate on all hosts if the main process ended or only on hosts for which we have updates
16
+ @outputs.reject { |_, output| @exit_status.nil? && output.empty? }
17
+ .reduce(base) do |acc, (identifier, output)|
18
+ @outputs[identifier] = ForemanTasksCore::ContinuousOutput.new # Create a new ContinuousOutput for next round of updates
19
+ exit_status = @exit_statuses[identifier] || @exit_status if @exit_status
20
+ acc.merge(host_action(identifier) => Runner::Update.new(output, exit_status))
21
+ end
22
+ end
23
+
24
+ def initialize_continuous_outputs
25
+ @outputs = @targets.keys.reduce({}) do |acc, target|
26
+ acc.merge(target => ForemanTasksCore::ContinuousOutput.new)
27
+ end
28
+ end
29
+
30
+ def host_action(identifier)
31
+ options = @targets[identifier].slice('execution_plan_id', 'run_step_id')
32
+ .merge(:world => ForemanTasksCore.dynflow_world)
33
+ Dynflow::Action::Suspended.new OpenStruct.new(options)
34
+ end
35
+
36
+ def broadcast_data(data, type)
37
+ @outputs.each { |_k, output| output.add_output(data, type) }
38
+ end
39
+
40
+ def publish_data(_data, _type)
41
+ true
42
+ end
43
+
44
+ def publish_data_for(identifier, data, type)
45
+ @outputs[identifier].add_output(data, type)
46
+ end
47
+
48
+ def dispatch_exception(context, exception)
49
+ @outputs.values.each { |output| output.add_exception(context, exception) }
50
+ end
51
+
52
+ def publish_exit_status_for(identifier, exit_status)
53
+ @exit_statuses[identifier] = exit_status
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,39 @@
1
+ module ForemanTasksCore
2
+ class SingleRunnerBatchAction < ForemanTasksCore::BatchAction
3
+ def plan(launcher, input_hash)
4
+ launcher.launch_children(self, input_hash)
5
+ sequence do
6
+ results = plan_self
7
+ plan_action BatchCallback, launcher.prepare_batch(input_hash), results.output[:results]
8
+ end
9
+ end
10
+
11
+ def run(event = nil)
12
+ super unless event == Dynflow::Action::Skip
13
+ end
14
+
15
+ def initiate
16
+ ping suspended_action
17
+ wait_for_sub_plans sub_plans
18
+ end
19
+
20
+ def check_for_errors!(optional = true)
21
+ super unless optional
22
+ end
23
+
24
+ def on_finish
25
+ output[:results] = sub_plans.map(&:entry_action).reduce({}) do |acc, cur|
26
+ acc.merge(cur.execution_plan_id => cur.output)
27
+ end
28
+ end
29
+
30
+ def finalize
31
+ output.delete(:results)
32
+ check_for_errors!
33
+ end
34
+
35
+ def rescue_strategy_for_self
36
+ Dynflow::Action::Rescue::Skip
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,9 @@
1
+ module ForemanTasksCore
2
+ module TaskLauncher
3
+ end
4
+ end
5
+
6
+ require 'foreman_tasks_core/task_launcher/abstract'
7
+ require 'foreman_tasks_core/task_launcher/single'
8
+ require 'foreman_tasks_core/task_launcher/batch'
9
+ require 'foreman_tasks_core/task_launcher/group'
@@ -0,0 +1,44 @@
1
+ module ForemanTasksCore
2
+ module TaskLauncher
3
+ class Abstract
4
+ attr_reader :callback, :options, :results, :world
5
+ def initialize(world, callback, options = {})
6
+ @world = world
7
+ @callback = callback
8
+ @options = options
9
+ @results = {}
10
+ end
11
+
12
+ def launch!(_input)
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def self.input_format; end
17
+
18
+ private
19
+
20
+ def format_result(result)
21
+ if result.triggered?
22
+ { :result => 'success', :task_id => result.execution_plan_id }
23
+ else
24
+ plan = world.persistence.load_execution_plan(result.id)
25
+ { :result => 'error', :errors => plan.errors }
26
+ end
27
+ end
28
+
29
+ def action_class(input)
30
+ options[:action_class_override] || ::Dynflow::Utils.constantize(input['action_class'])
31
+ end
32
+
33
+ def with_callback(input)
34
+ input.merge(:callback_host => callback)
35
+ end
36
+
37
+ def trigger(parent, klass, *input)
38
+ world.trigger do
39
+ world.plan_with_options(caller_action: parent, action_class: klass, args: input)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,37 @@
1
+ module ForemanTasksCore
2
+ module TaskLauncher
3
+ class Batch < Abstract
4
+ def launch!(input)
5
+ trigger(nil, BatchAction, self, input)
6
+ end
7
+
8
+ def launch_children(parent, input_hash)
9
+ input_hash.each do |task_id, input|
10
+ launcher = child_launcher(parent)
11
+ launcher.launch!(transform_input(input))
12
+ results[task_id] = launcher.results
13
+ end
14
+ end
15
+
16
+ def prepare_batch(input_hash)
17
+ success_tasks = input_hash.select do |task_id, _input|
18
+ results[task_id][:result] == 'success'
19
+ end
20
+ success_tasks.reduce({}) do |acc, (key, value)|
21
+ acc.merge(results[key][:task_id] => value['action_input']['callback'])
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def child_launcher(parent)
28
+ Single.new(world, callback, :parent => parent)
29
+ end
30
+
31
+ # Identity by default
32
+ def transform_input(input)
33
+ input
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,47 @@
1
+ require 'foreman_tasks_core/runner'
2
+
3
+ module ForemanTasksCore
4
+ module TaskLauncher
5
+ class AbstractGroup < Batch
6
+ def self.runner_class
7
+ raise NotImplementedError
8
+ end
9
+
10
+ def launch!(input)
11
+ trigger(nil, SingleRunnerBatchAction, self, input)
12
+ end
13
+
14
+ def launch_children(parent, input_hash)
15
+ super(parent, input_hash)
16
+ trigger(parent, BatchRunnerAction, self, input_hash)
17
+ end
18
+
19
+ def operation
20
+ raise NotImplementedError
21
+ end
22
+
23
+ def runner_input(input)
24
+ input.reduce({}) do |acc, (id, input)|
25
+ input = { :execution_plan_id => results[id][:task_id],
26
+ :run_step_id => 2,
27
+ :input => input }
28
+ acc.merge(id => input)
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def child_launcher(parent)
35
+ Single.new(world, callback, :parent => parent, :action_class_override => OutputCollectorAction)
36
+ end
37
+
38
+ def transform_input(input)
39
+ wipe_callback(input)
40
+ end
41
+
42
+ def wipe_callback(input)
43
+ input.merge('action_input' => input['action_input'].merge('callback' => nil))
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,17 @@
1
+ module ForemanTasksCore
2
+ module TaskLauncher
3
+ class Single < Abstract
4
+ def self.input_format
5
+ { :action_class => "MyActionClass", :action_input => {} }
6
+ end
7
+
8
+ def launch!(input)
9
+ triggered = trigger(options[:parent],
10
+ action_class(input),
11
+ with_callback(input.fetch('action_input', {})))
12
+ @results = format_result(triggered)
13
+ triggered
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,5 @@
1
+ require 'dynflow'
2
+
1
3
  module ForemanTasksCore
2
4
  class Ticker < ::Dynflow::Actor
3
5
  attr_reader :clock
@@ -1,3 +1,3 @@
1
1
  module ForemanTasksCore
2
- VERSION = '0.3.0'.freeze
2
+ VERSION = '0.3.5'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman-tasks-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Nečas
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-08 00:00:00.000000000 Z
11
+ date: 2021-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dynflow
@@ -26,7 +26,7 @@ dependencies:
26
26
  version: 1.2.0
27
27
  description: 'Common code used both at Forman and Foreman proxy regarding tasks
28
28
 
29
- '
29
+ '
30
30
  email:
31
31
  - inecas@redhat.com
32
32
  executables: []
@@ -35,22 +35,35 @@ extra_rdoc_files: []
35
35
  files:
36
36
  - LICENSE
37
37
  - lib/foreman_tasks_core.rb
38
+ - lib/foreman_tasks_core/batch_action.rb
39
+ - lib/foreman_tasks_core/batch_callback_action.rb
40
+ - lib/foreman_tasks_core/batch_runner_action.rb
38
41
  - lib/foreman_tasks_core/continuous_output.rb
39
42
  - lib/foreman_tasks_core/otp_manager.rb
43
+ - lib/foreman_tasks_core/output_collector_action.rb
40
44
  - lib/foreman_tasks_core/runner.rb
41
45
  - lib/foreman_tasks_core/runner/action.rb
42
46
  - lib/foreman_tasks_core/runner/base.rb
47
+ - lib/foreman_tasks_core/runner/command.rb
43
48
  - lib/foreman_tasks_core/runner/command_runner.rb
44
49
  - lib/foreman_tasks_core/runner/dispatcher.rb
50
+ - lib/foreman_tasks_core/runner/parent.rb
45
51
  - lib/foreman_tasks_core/runner/update.rb
46
52
  - lib/foreman_tasks_core/settings_loader.rb
47
53
  - lib/foreman_tasks_core/shareable_action.rb
54
+ - lib/foreman_tasks_core/single_runner_batch_action.rb
55
+ - lib/foreman_tasks_core/task_launcher.rb
56
+ - lib/foreman_tasks_core/task_launcher/abstract.rb
57
+ - lib/foreman_tasks_core/task_launcher/batch.rb
58
+ - lib/foreman_tasks_core/task_launcher/group.rb
59
+ - lib/foreman_tasks_core/task_launcher/single.rb
48
60
  - lib/foreman_tasks_core/ticker.rb
49
61
  - lib/foreman_tasks_core/version.rb
50
62
  homepage: https://github.com/theforeman/foreman-tasks
51
- licenses: []
63
+ licenses:
64
+ - GPL-3.0
52
65
  metadata: {}
53
- post_install_message:
66
+ post_install_message:
54
67
  rdoc_options: []
55
68
  require_paths:
56
69
  - lib
@@ -65,9 +78,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
65
78
  - !ruby/object:Gem::Version
66
79
  version: '0'
67
80
  requirements: []
68
- rubyforge_project:
69
- rubygems_version: 2.7.6
70
- signing_key:
81
+ rubygems_version: 3.1.2
82
+ signing_key:
71
83
  specification_version: 4
72
84
  summary: Common code used both at Forman and Foreman proxy regarding tasks
73
85
  test_files: []