foreman-tasks-core 0.3.0 → 0.3.1
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 +1 -0
- data/lib/foreman_tasks_core/runner.rb +1 -0
- data/lib/foreman_tasks_core/runner/base.rb +20 -8
- data/lib/foreman_tasks_core/runner/dispatcher.rb +8 -4
- data/lib/foreman_tasks_core/runner/parent.rb +48 -0
- data/lib/foreman_tasks_core/task_launcher.rb +8 -0
- data/lib/foreman_tasks_core/task_launcher/abstract.rb +42 -0
- data/lib/foreman_tasks_core/task_launcher/batch.rb +37 -0
- data/lib/foreman_tasks_core/task_launcher/single.rb +14 -0
- data/lib/foreman_tasks_core/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c46d9f3def1bf8405c45eb6a32331437dede8c68071d0c0c8a0159a2e489f007
|
4
|
+
data.tar.gz: 24e606e5743d4694c607514b25bbff6492153290d9d3c99546a91b6ce75967d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a3c8a38e39d80a3f5f9bc1deebdcf7e4b082838e687ae78846a17448302dddff4c00c24e81235ad455133c12bfd7112d657b7ca630210ce79bddd1f4d04e13f
|
7
|
+
data.tar.gz: c4777a0ca2d8d7562e3b2f0ab02293e7af5039753adcd9c7d0fabe1955726b60cf15e2c9664376410aff9e08de45054459ce9e2ac7a0d4a94ce49e02b3a61936
|
data/lib/foreman_tasks_core.rb
CHANGED
@@ -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
|
-
|
12
|
+
initialize_continuous_outputs
|
12
13
|
end
|
13
14
|
|
14
15
|
def logger
|
@@ -18,11 +19,7 @@ module ForemanTasksCore
|
|
18
19
|
def run_refresh
|
19
20
|
logger.debug('refreshing runner')
|
20
21
|
refresh
|
21
|
-
|
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
|
26
23
|
end
|
27
24
|
|
28
25
|
def start
|
@@ -59,13 +56,28 @@ module ForemanTasksCore
|
|
59
56
|
def publish_exception(context, exception, fatal = true)
|
60
57
|
logger.error("#{context} - #{exception.class} #{exception.message}:\n" + \
|
61
58
|
exception.backtrace.join("\n"))
|
62
|
-
|
59
|
+
dispatch_exception context, exception
|
63
60
|
publish_exit_status('EXCEPTION') if fatal
|
64
61
|
end
|
65
62
|
|
66
63
|
def publish_exit_status(status)
|
67
64
|
@exit_status = status
|
68
65
|
end
|
66
|
+
|
67
|
+
def dispatch_exception(context, exception)
|
68
|
+
@continuous_output.add_exception(context, exception)
|
69
|
+
end
|
70
|
+
|
71
|
+
def generate_updates
|
72
|
+
return {} if @continuous_output.empty? && @exit_status.nil?
|
73
|
+
new_data = @continuous_output
|
74
|
+
@continuous_output = ForemanTasksCore::ContinuousOutput.new
|
75
|
+
{ @suspended_action => Runner::Update.new(new_data, @exit_status) }
|
76
|
+
end
|
77
|
+
|
78
|
+
def initialize_continuous_outputs
|
79
|
+
@continuous_output = ::ForemanTasksCore::ContinuousOutput.new
|
80
|
+
end
|
69
81
|
end
|
70
82
|
end
|
71
83
|
end
|
@@ -37,10 +37,14 @@ module ForemanTasksCore
|
|
37
37
|
|
38
38
|
def refresh_runner
|
39
39
|
@logger.debug("refresh runner #{@runner.id}")
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
updates = @runner.run_refresh
|
41
|
+
|
42
|
+
updates.each { |receiver, update| (receiver || @suspended_action) << update }
|
43
|
+
|
44
|
+
# This is a workaround when the runner does not accept the suspended action
|
45
|
+
main_key = updates.keys.any?(&:nil?) ? nil : @suspended_action
|
46
|
+
main_process = updates[main_key]
|
47
|
+
finish if main_process && main_process.exit_status
|
44
48
|
ensure
|
45
49
|
@refresh_planned = false
|
46
50
|
plan_next_refresh
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module ForemanTasksCore
|
2
|
+
module Runner
|
3
|
+
class Parent < Base
|
4
|
+
# targets = { hostname => { :execution_plan_id => "...", :run_step_id => id,
|
5
|
+
# :input => { ... } }
|
6
|
+
def initialize(targets = {}, suspended_action: nil)
|
7
|
+
@targets = targets
|
8
|
+
super suspended_action: suspended_action
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate_updates
|
12
|
+
@outputs.reduce({}) do |acc, (key, value)|
|
13
|
+
if value.empty? && @exit_status.nil?
|
14
|
+
acc
|
15
|
+
else
|
16
|
+
@outputs[key] = ForemanTasksCore::ContinuousOutput.new
|
17
|
+
key = host_action(key) unless key == @suspended_action
|
18
|
+
acc.merge(key => Runner::Update.new(value, @exit_status))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize_continuous_outputs
|
24
|
+
@outputs = ([@suspended_action] + @targets.keys).reduce({}) do |acc, target|
|
25
|
+
acc.merge(target => ForemanTasksCore::ContinuousOutput.new)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def host_action(hostname)
|
30
|
+
options = @targets[hostname].slice('execution_plan_id', 'run_step_id')
|
31
|
+
.merge(:world => ForemanTasksCore.dynflow_world)
|
32
|
+
Dynflow::Action::Suspended.new OpenStruct.new(options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def broadcast_data(data, type)
|
36
|
+
@outputs.each { |_k, output| output.add_output(data, type) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def publish_data_for(hostname, data, type)
|
40
|
+
@outputs[hostname].add_output(data, type)
|
41
|
+
end
|
42
|
+
|
43
|
+
def dispatch_exception(context, exception)
|
44
|
+
@outputs.values.each { |output| output.add_exception(context, exception) }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,42 @@
|
|
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
|
+
private
|
17
|
+
|
18
|
+
def format_result(result)
|
19
|
+
if result.triggered?
|
20
|
+
{ :result => 'success', :task_id => result.execution_plan_id }
|
21
|
+
else
|
22
|
+
plan = world.persistence.load_execution_plan(result.id)
|
23
|
+
{ :result => 'error', :errors => plan.errors }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def action_class(input)
|
28
|
+
::Dynflow::Utils.constantize(input['action_class'])
|
29
|
+
end
|
30
|
+
|
31
|
+
def with_callback(input)
|
32
|
+
input.merge(:callback_host => callback)
|
33
|
+
end
|
34
|
+
|
35
|
+
def trigger(parent, klass, *input)
|
36
|
+
world.trigger do
|
37
|
+
world.plan_with_options(caller_action: parent, action_class: klass, args: input)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module ForemanTasksCore
|
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
|
+
class Batch < Abstract
|
24
|
+
def launch!(input)
|
25
|
+
trigger(nil, ParentAction, self, input)
|
26
|
+
end
|
27
|
+
|
28
|
+
def launch_children(parent, input_hash)
|
29
|
+
input_hash.each do |task_id, input|
|
30
|
+
launcher = Single.new(world, callback, :parent => parent)
|
31
|
+
launcher.launch!(input)
|
32
|
+
results[task_id] = launcher.results
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module ForemanTasksCore
|
2
|
+
module TaskLauncher
|
3
|
+
class Single < Abstract
|
4
|
+
# { :action_class => "MyActionClass", :action_input => {} }
|
5
|
+
def launch!(input)
|
6
|
+
triggered = trigger(options[:parent],
|
7
|
+
action_class(input),
|
8
|
+
with_callback(input.fetch('action_input', {})))
|
9
|
+
@results = format_result(triggered)
|
10
|
+
triggered
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
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.
|
4
|
+
version: 0.3.1
|
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-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dynflow
|
@@ -42,9 +42,14 @@ files:
|
|
42
42
|
- lib/foreman_tasks_core/runner/base.rb
|
43
43
|
- lib/foreman_tasks_core/runner/command_runner.rb
|
44
44
|
- lib/foreman_tasks_core/runner/dispatcher.rb
|
45
|
+
- lib/foreman_tasks_core/runner/parent.rb
|
45
46
|
- lib/foreman_tasks_core/runner/update.rb
|
46
47
|
- lib/foreman_tasks_core/settings_loader.rb
|
47
48
|
- lib/foreman_tasks_core/shareable_action.rb
|
49
|
+
- lib/foreman_tasks_core/task_launcher.rb
|
50
|
+
- lib/foreman_tasks_core/task_launcher/abstract.rb
|
51
|
+
- lib/foreman_tasks_core/task_launcher/batch.rb
|
52
|
+
- lib/foreman_tasks_core/task_launcher/single.rb
|
48
53
|
- lib/foreman_tasks_core/ticker.rb
|
49
54
|
- lib/foreman_tasks_core/version.rb
|
50
55
|
homepage: https://github.com/theforeman/foreman-tasks
|