foreman-tasks-core 0.3.1 → 0.3.2
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 +4 -4
- data/lib/foreman_tasks_core.rb +5 -0
- data/lib/foreman_tasks_core/batch_action.rb +21 -0
- data/lib/foreman_tasks_core/batch_callback_action.rb +20 -0
- data/lib/foreman_tasks_core/batch_runner_action.rb +14 -0
- data/lib/foreman_tasks_core/output_collector_action.rb +8 -0
- data/lib/foreman_tasks_core/runner/command.rb +40 -0
- data/lib/foreman_tasks_core/runner/command_runner.rb +3 -33
- data/lib/foreman_tasks_core/runner/parent.rb +20 -9
- data/lib/foreman_tasks_core/single_runner_batch_action.rb +39 -0
- data/lib/foreman_tasks_core/task_launcher.rb +1 -0
- data/lib/foreman_tasks_core/task_launcher/abstract.rb +3 -1
- data/lib/foreman_tasks_core/task_launcher/batch.rb +23 -23
- data/lib/foreman_tasks_core/task_launcher/group.rb +47 -0
- data/lib/foreman_tasks_core/task_launcher/single.rb +4 -1
- data/lib/foreman_tasks_core/version.rb +1 -1
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c036a816a81a10ce427600ce920c1aa98c59bb2c317dcba1662f906941d00e0
|
4
|
+
data.tar.gz: 3e74db375442e42f0ad7e7f5887d1cd5ab79b311d86c1389f24fb5d168146a70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c68ff530abb93733509feb1201d74c7588b1edc3e90c6caf2fd54fce11aedeb760595c2ce3fcf8f208fe5eafbc7bca00aecec08ee4b28d0b1e438c6b81938d1
|
7
|
+
data.tar.gz: f1e5baa029323687099e055874464d1710ddbcc8488207fcb64bdc5f5682ff90311c8db6fbf5ce6eb372a4d9eb821df51ac26a5e151bbc6d4551983a896e6f82
|
data/lib/foreman_tasks_core.rb
CHANGED
@@ -4,6 +4,11 @@
|
|
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'
|
7
12
|
require 'foreman_tasks_core/task_launcher'
|
8
13
|
|
9
14
|
module ForemanTasksCore
|
@@ -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
|
@@ -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 <
|
7
|
-
|
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
|
@@ -1,10 +1,11 @@
|
|
1
1
|
module ForemanTasksCore
|
2
2
|
module Runner
|
3
3
|
class Parent < Base
|
4
|
-
# targets = {
|
4
|
+
# targets = { identifier => { :execution_plan_id => "...", :run_step_id => id,
|
5
5
|
# :input => { ... } }
|
6
6
|
def initialize(targets = {}, suspended_action: nil)
|
7
7
|
@targets = targets
|
8
|
+
@exit_statuses = {}
|
8
9
|
super suspended_action: suspended_action
|
9
10
|
end
|
10
11
|
|
@@ -13,9 +14,11 @@ module ForemanTasksCore
|
|
13
14
|
if value.empty? && @exit_status.nil?
|
14
15
|
acc
|
15
16
|
else
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
identifier = key
|
18
|
+
@outputs[identifier] = ForemanTasksCore::ContinuousOutput.new
|
19
|
+
key = host_action(identifier) unless identifier == @suspended_action
|
20
|
+
exit_status = @exit_statuses[identifier] || @exit_status if @exit_status
|
21
|
+
acc.merge(key => Runner::Update.new(value, exit_status))
|
19
22
|
end
|
20
23
|
end
|
21
24
|
end
|
@@ -26,9 +29,9 @@ module ForemanTasksCore
|
|
26
29
|
end
|
27
30
|
end
|
28
31
|
|
29
|
-
def host_action(
|
30
|
-
options = @targets[
|
31
|
-
|
32
|
+
def host_action(identifier)
|
33
|
+
options = @targets[identifier].slice('execution_plan_id', 'run_step_id')
|
34
|
+
.merge(:world => ForemanTasksCore.dynflow_world)
|
32
35
|
Dynflow::Action::Suspended.new OpenStruct.new(options)
|
33
36
|
end
|
34
37
|
|
@@ -36,13 +39,21 @@ module ForemanTasksCore
|
|
36
39
|
@outputs.each { |_k, output| output.add_output(data, type) }
|
37
40
|
end
|
38
41
|
|
39
|
-
def
|
40
|
-
@outputs[
|
42
|
+
def publish_data(data, type)
|
43
|
+
@outputs[@suspended_action].add_output(data, type)
|
44
|
+
end
|
45
|
+
|
46
|
+
def publish_data_for(identifier, data, type)
|
47
|
+
@outputs[identifier].add_output(data, type)
|
41
48
|
end
|
42
49
|
|
43
50
|
def dispatch_exception(context, exception)
|
44
51
|
@outputs.values.each { |output| output.add_exception(context, exception) }
|
45
52
|
end
|
53
|
+
|
54
|
+
def publish_exit_status_for(identifier, exit_status)
|
55
|
+
@exit_statuses[identifier] = exit_status
|
56
|
+
end
|
46
57
|
end
|
47
58
|
end
|
48
59
|
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
|
@@ -13,6 +13,8 @@ module ForemanTasksCore
|
|
13
13
|
raise NotImplementedError
|
14
14
|
end
|
15
15
|
|
16
|
+
def self.input_format; end
|
17
|
+
|
16
18
|
private
|
17
19
|
|
18
20
|
def format_result(result)
|
@@ -25,7 +27,7 @@ module ForemanTasksCore
|
|
25
27
|
end
|
26
28
|
|
27
29
|
def action_class(input)
|
28
|
-
::Dynflow::Utils.constantize(input['action_class'])
|
30
|
+
options[:action_class_override] || ::Dynflow::Utils.constantize(input['action_class'])
|
29
31
|
end
|
30
32
|
|
31
33
|
def with_callback(input)
|
@@ -1,37 +1,37 @@
|
|
1
1
|
module ForemanTasksCore
|
2
2
|
module TaskLauncher
|
3
|
-
class ParentAction < ::Dynflow::Action
|
4
|
-
include Dynflow::Action::WithSubPlans
|
5
|
-
include Dynflow::Action::WithPollingSubPlans
|
6
|
-
|
7
|
-
# { task_id => { :action_class => Klass, :input => input } }
|
8
|
-
def plan(launcher, input_hash)
|
9
|
-
launcher.launch_children(self, input_hash)
|
10
|
-
plan_self
|
11
|
-
end
|
12
|
-
|
13
|
-
def initiate
|
14
|
-
ping suspended_action
|
15
|
-
wait_for_sub_plans sub_plans
|
16
|
-
end
|
17
|
-
|
18
|
-
def rescue_strategy
|
19
|
-
Dynflow::Action::Rescue::Fail
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
3
|
class Batch < Abstract
|
24
4
|
def launch!(input)
|
25
|
-
trigger(nil,
|
5
|
+
trigger(nil, BatchAction, self, input)
|
26
6
|
end
|
27
7
|
|
28
8
|
def launch_children(parent, input_hash)
|
29
9
|
input_hash.each do |task_id, input|
|
30
|
-
launcher =
|
31
|
-
launcher.launch!(input)
|
10
|
+
launcher = child_launcher(parent)
|
11
|
+
launcher.launch!(transform_input(input))
|
32
12
|
results[task_id] = launcher.results
|
33
13
|
end
|
34
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
35
|
end
|
36
36
|
end
|
37
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
|
@@ -1,7 +1,10 @@
|
|
1
1
|
module ForemanTasksCore
|
2
2
|
module TaskLauncher
|
3
3
|
class Single < Abstract
|
4
|
-
|
4
|
+
def self.input_format
|
5
|
+
{ :action_class => "MyActionClass", :action_input => {} }
|
6
|
+
end
|
7
|
+
|
5
8
|
def launch!(input)
|
6
9
|
triggered = trigger(options[:parent],
|
7
10
|
action_class(input),
|
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.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Nečas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-04-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dynflow
|
@@ -35,20 +35,27 @@ 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
|
45
50
|
- lib/foreman_tasks_core/runner/parent.rb
|
46
51
|
- lib/foreman_tasks_core/runner/update.rb
|
47
52
|
- lib/foreman_tasks_core/settings_loader.rb
|
48
53
|
- lib/foreman_tasks_core/shareable_action.rb
|
54
|
+
- lib/foreman_tasks_core/single_runner_batch_action.rb
|
49
55
|
- lib/foreman_tasks_core/task_launcher.rb
|
50
56
|
- lib/foreman_tasks_core/task_launcher/abstract.rb
|
51
57
|
- lib/foreman_tasks_core/task_launcher/batch.rb
|
58
|
+
- lib/foreman_tasks_core/task_launcher/group.rb
|
52
59
|
- lib/foreman_tasks_core/task_launcher/single.rb
|
53
60
|
- lib/foreman_tasks_core/ticker.rb
|
54
61
|
- lib/foreman_tasks_core/version.rb
|