smart_proxy_dynflow 0.2.3 → 0.5.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/Gemfile +6 -25
- data/{bundler.plugins.d → bundler.d}/dynflow.rb +0 -0
- data/lib/smart_proxy_dynflow.rb +16 -1
- data/lib/smart_proxy_dynflow/action.rb +12 -0
- data/lib/smart_proxy_dynflow/action/batch.rb +21 -0
- data/lib/smart_proxy_dynflow/action/batch_callback.rb +20 -0
- data/lib/smart_proxy_dynflow/action/batch_runner.rb +14 -0
- data/lib/smart_proxy_dynflow/action/output_collector.rb +8 -0
- data/lib/smart_proxy_dynflow/action/runner.rb +76 -0
- data/lib/smart_proxy_dynflow/action/shareable.rb +25 -0
- data/lib/smart_proxy_dynflow/action/single_runner_batch.rb +39 -0
- data/lib/smart_proxy_dynflow/api.rb +63 -40
- data/lib/smart_proxy_dynflow/callback.rb +69 -25
- data/lib/smart_proxy_dynflow/continuous_output.rb +50 -0
- data/lib/smart_proxy_dynflow/core.rb +121 -0
- data/lib/smart_proxy_dynflow/helpers.rb +52 -6
- data/lib/smart_proxy_dynflow/http_config.ru +6 -16
- data/lib/smart_proxy_dynflow/log.rb +52 -0
- data/lib/smart_proxy_dynflow/middleware/keep_current_request_id.rb +59 -0
- data/lib/smart_proxy_dynflow/otp_manager.rb +36 -0
- data/lib/smart_proxy_dynflow/plugin.rb +9 -14
- data/lib/smart_proxy_dynflow/proxy_adapter.rb +1 -1
- data/lib/smart_proxy_dynflow/runner.rb +10 -0
- data/lib/smart_proxy_dynflow/runner/base.rb +98 -0
- data/lib/smart_proxy_dynflow/runner/command.rb +40 -0
- data/lib/smart_proxy_dynflow/runner/command_runner.rb +11 -0
- data/lib/smart_proxy_dynflow/runner/dispatcher.rb +191 -0
- data/lib/smart_proxy_dynflow/runner/parent.rb +57 -0
- data/lib/smart_proxy_dynflow/runner/update.rb +28 -0
- data/lib/smart_proxy_dynflow/settings.rb +9 -0
- data/lib/smart_proxy_dynflow/settings_loader.rb +53 -0
- data/lib/smart_proxy_dynflow/task_launcher.rb +9 -0
- data/lib/smart_proxy_dynflow/task_launcher/abstract.rb +44 -0
- data/lib/smart_proxy_dynflow/task_launcher/batch.rb +37 -0
- data/lib/smart_proxy_dynflow/task_launcher/group.rb +48 -0
- data/lib/smart_proxy_dynflow/task_launcher/single.rb +17 -0
- data/lib/smart_proxy_dynflow/task_launcher_registry.rb +31 -0
- data/lib/smart_proxy_dynflow/testing.rb +24 -0
- data/lib/smart_proxy_dynflow/ticker.rb +47 -0
- data/lib/smart_proxy_dynflow/version.rb +2 -2
- data/settings.d/dynflow.yml.example +6 -5
- metadata +83 -12
@@ -0,0 +1,53 @@
|
|
1
|
+
module Proxy::Dynflow
|
2
|
+
module SettingsLoader
|
3
|
+
def self.settings_registry
|
4
|
+
@settings_registry ||= {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.name_to_settings
|
8
|
+
@name_to_settings ||= {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.settings_keys
|
12
|
+
@settings_keys ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.settings_registered?(name)
|
16
|
+
name_to_settings.key?(name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.register_settings(names, object)
|
20
|
+
names = [names] unless names.is_a? Array
|
21
|
+
names.each do |name|
|
22
|
+
raise 'settings name has to be a symbol' unless name.is_a? Symbol
|
23
|
+
raise "settings #{name} already registered" if SettingsLoader.settings_registered?(name)
|
24
|
+
name_to_settings[name] = object
|
25
|
+
end
|
26
|
+
settings_registry[names] = object
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.setup_settings(name, settings)
|
30
|
+
raise "Settings for #{name} were not registered" unless settings_registered?(name)
|
31
|
+
name_to_settings[name].initialize_settings(settings)
|
32
|
+
end
|
33
|
+
|
34
|
+
def register_settings(names, defaults = {})
|
35
|
+
SettingsLoader.register_settings(names, self)
|
36
|
+
@defaults = defaults
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize_settings(settings = {})
|
40
|
+
@settings = @defaults.merge(settings)
|
41
|
+
validate_settings!
|
42
|
+
end
|
43
|
+
|
44
|
+
def settings
|
45
|
+
raise "Settings for #{self} not initalized" unless @settings
|
46
|
+
@settings
|
47
|
+
end
|
48
|
+
|
49
|
+
def validate_settings!
|
50
|
+
raise 'Only symbols expected in keys' unless @settings.keys.all? { |key| key.is_a? Symbol }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Proxy::Dynflow
|
2
|
+
module TaskLauncher
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'smart_proxy_dynflow/task_launcher/abstract'
|
7
|
+
require 'smart_proxy_dynflow/task_launcher/single'
|
8
|
+
require 'smart_proxy_dynflow/task_launcher/batch'
|
9
|
+
require 'smart_proxy_dynflow/task_launcher/group'
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Proxy::Dynflow
|
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 Proxy::Dynflow
|
2
|
+
module TaskLauncher
|
3
|
+
class Batch < Abstract
|
4
|
+
def launch!(input)
|
5
|
+
trigger(nil, Proxy::Dynflow::Action::Batch, 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,48 @@
|
|
1
|
+
require 'smart_proxy_dynflow/runner'
|
2
|
+
|
3
|
+
module Proxy::Dynflow
|
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, Action::SingleRunnerBatch, self, input)
|
12
|
+
end
|
13
|
+
|
14
|
+
def launch_children(parent, input_hash)
|
15
|
+
super(parent, input_hash)
|
16
|
+
trigger(parent, Action::BatchRunner, 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 => Action::OutputCollector)
|
36
|
+
end
|
37
|
+
|
38
|
+
def transform_input(input)
|
39
|
+
wipe_callback(input)
|
40
|
+
end
|
41
|
+
|
42
|
+
def wipe_callback(input)
|
43
|
+
callback = input['action_input']['callback']
|
44
|
+
input.merge('action_input' => input['action_input'].merge('callback' => nil, :task_id => callback['task_id']))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Proxy::Dynflow
|
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
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Proxy::Dynflow
|
2
|
+
class TaskLauncherRegistry
|
3
|
+
class << self
|
4
|
+
def register(name, launcher)
|
5
|
+
registry[name] = launcher
|
6
|
+
end
|
7
|
+
|
8
|
+
def fetch(name, default = nil)
|
9
|
+
if default.nil?
|
10
|
+
registry.fetch(name)
|
11
|
+
else
|
12
|
+
registry.fetch(name, default)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def key?(name)
|
17
|
+
registry.key?(name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def operations
|
21
|
+
registry.keys
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def registry
|
27
|
+
@registry ||= {}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'dynflow/testing'
|
2
|
+
|
3
|
+
unless defined? DYNFLOW_TESTING_LOG_LEVEL
|
4
|
+
DYNFLOW_TESTING_LOG_LEVEL = 4
|
5
|
+
end
|
6
|
+
|
7
|
+
module Proxy::Dynflow
|
8
|
+
# Helper for usage in other dependent plugins that need Dynflow
|
9
|
+
# related things, such as testing instance of world etc.
|
10
|
+
module Testing
|
11
|
+
class << self
|
12
|
+
def create_world(&block)
|
13
|
+
Core.ensure_initialized
|
14
|
+
Core.instance.create_world do |config|
|
15
|
+
config.exit_on_terminate = false
|
16
|
+
config.auto_terminate = false
|
17
|
+
config.logger_adapter = ::Dynflow::LoggerAdapters::Simple.new $stderr, DYNFLOW_TESTING_LOG_LEVEL
|
18
|
+
config.execution_plan_cleaner = nil
|
19
|
+
yield(config) if block
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'dynflow'
|
2
|
+
|
3
|
+
module Proxy::Dynflow
|
4
|
+
class Ticker < ::Dynflow::Actor
|
5
|
+
attr_reader :clock
|
6
|
+
|
7
|
+
def initialize(clock, logger, refresh_interval)
|
8
|
+
@clock = clock
|
9
|
+
@logger = logger
|
10
|
+
@events = []
|
11
|
+
@refresh_interval = refresh_interval
|
12
|
+
plan_next_tick
|
13
|
+
end
|
14
|
+
|
15
|
+
def tick
|
16
|
+
@logger.debug("Ticker ticking for #{@events.size} events")
|
17
|
+
@events.each do |(target, args)|
|
18
|
+
pass_event(target, args)
|
19
|
+
end
|
20
|
+
@events = []
|
21
|
+
ensure
|
22
|
+
@planned = false
|
23
|
+
plan_next_tick
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_event(target, args)
|
27
|
+
@events << [target, args]
|
28
|
+
plan_next_tick
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def pass_event(target, args)
|
34
|
+
target.tell(args)
|
35
|
+
rescue => e
|
36
|
+
@logger.error("Failed passing event to #{target} with #{args}")
|
37
|
+
@logger.error(e)
|
38
|
+
end
|
39
|
+
|
40
|
+
def plan_next_tick
|
41
|
+
if !@planned && !@events.empty?
|
42
|
+
@clock.ping(reference, Time.now.getlocal + @refresh_interval, :tick)
|
43
|
+
@planned = true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
---
|
2
2
|
:enabled: true
|
3
3
|
:database: /var/lib/foreman-proxy/dynflow/dynflow.sqlite
|
4
|
-
:core_url: 'http://127.0.0.1:8008'
|
5
4
|
|
6
|
-
#
|
7
|
-
#
|
8
|
-
|
9
|
-
#
|
5
|
+
# Require a valid cert to access Dynflow console
|
6
|
+
# :console_auth: true
|
7
|
+
|
8
|
+
# Maximum age of execution plans to keep before having them cleaned
|
9
|
+
# by the execution plan cleaner (in seconds), defaults to 24 hours
|
10
|
+
# :execution_plan_cleaner_age: 86400
|
metadata
CHANGED
@@ -1,27 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_proxy_dynflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.1
|
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:
|
11
|
+
date: 2021-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: dynflow
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rest-client
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sqlite3
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
18
60
|
- !ruby/object:Gem::Version
|
19
61
|
version: '1.7'
|
20
62
|
type: :development
|
21
63
|
prerelease: false
|
22
64
|
version_requirements: !ruby/object:Gem::Requirement
|
23
65
|
requirements:
|
24
|
-
- - "
|
66
|
+
- - ">="
|
25
67
|
- !ruby/object:Gem::Version
|
26
68
|
version: '1.7'
|
27
69
|
- !ruby/object:Gem::Dependency
|
@@ -103,38 +145,67 @@ extra_rdoc_files: []
|
|
103
145
|
files:
|
104
146
|
- Gemfile
|
105
147
|
- LICENSE
|
106
|
-
- bundler.
|
148
|
+
- bundler.d/dynflow.rb
|
107
149
|
- lib/smart_proxy_dynflow.rb
|
150
|
+
- lib/smart_proxy_dynflow/action.rb
|
151
|
+
- lib/smart_proxy_dynflow/action/batch.rb
|
152
|
+
- lib/smart_proxy_dynflow/action/batch_callback.rb
|
153
|
+
- lib/smart_proxy_dynflow/action/batch_runner.rb
|
154
|
+
- lib/smart_proxy_dynflow/action/output_collector.rb
|
155
|
+
- lib/smart_proxy_dynflow/action/runner.rb
|
156
|
+
- lib/smart_proxy_dynflow/action/shareable.rb
|
157
|
+
- lib/smart_proxy_dynflow/action/single_runner_batch.rb
|
108
158
|
- lib/smart_proxy_dynflow/api.rb
|
109
159
|
- lib/smart_proxy_dynflow/callback.rb
|
160
|
+
- lib/smart_proxy_dynflow/continuous_output.rb
|
161
|
+
- lib/smart_proxy_dynflow/core.rb
|
110
162
|
- lib/smart_proxy_dynflow/helpers.rb
|
111
163
|
- lib/smart_proxy_dynflow/http_config.ru
|
164
|
+
- lib/smart_proxy_dynflow/log.rb
|
165
|
+
- lib/smart_proxy_dynflow/middleware/keep_current_request_id.rb
|
166
|
+
- lib/smart_proxy_dynflow/otp_manager.rb
|
112
167
|
- lib/smart_proxy_dynflow/plugin.rb
|
113
168
|
- lib/smart_proxy_dynflow/proxy_adapter.rb
|
169
|
+
- lib/smart_proxy_dynflow/runner.rb
|
170
|
+
- lib/smart_proxy_dynflow/runner/base.rb
|
171
|
+
- lib/smart_proxy_dynflow/runner/command.rb
|
172
|
+
- lib/smart_proxy_dynflow/runner/command_runner.rb
|
173
|
+
- lib/smart_proxy_dynflow/runner/dispatcher.rb
|
174
|
+
- lib/smart_proxy_dynflow/runner/parent.rb
|
175
|
+
- lib/smart_proxy_dynflow/runner/update.rb
|
176
|
+
- lib/smart_proxy_dynflow/settings.rb
|
177
|
+
- lib/smart_proxy_dynflow/settings_loader.rb
|
178
|
+
- lib/smart_proxy_dynflow/task_launcher.rb
|
179
|
+
- lib/smart_proxy_dynflow/task_launcher/abstract.rb
|
180
|
+
- lib/smart_proxy_dynflow/task_launcher/batch.rb
|
181
|
+
- lib/smart_proxy_dynflow/task_launcher/group.rb
|
182
|
+
- lib/smart_proxy_dynflow/task_launcher/single.rb
|
183
|
+
- lib/smart_proxy_dynflow/task_launcher_registry.rb
|
184
|
+
- lib/smart_proxy_dynflow/testing.rb
|
185
|
+
- lib/smart_proxy_dynflow/ticker.rb
|
114
186
|
- lib/smart_proxy_dynflow/version.rb
|
115
187
|
- settings.d/dynflow.yml.example
|
116
188
|
homepage: https://github.com/theforeman/smart_proxy_dynflow
|
117
189
|
licenses:
|
118
190
|
- GPL-3.0
|
119
191
|
metadata: {}
|
120
|
-
post_install_message:
|
192
|
+
post_install_message:
|
121
193
|
rdoc_options: []
|
122
194
|
require_paths:
|
123
195
|
- lib
|
124
196
|
required_ruby_version: !ruby/object:Gem::Requirement
|
125
197
|
requirements:
|
126
|
-
- - "
|
198
|
+
- - "~>"
|
127
199
|
- !ruby/object:Gem::Version
|
128
|
-
version: '
|
200
|
+
version: '2.5'
|
129
201
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
202
|
requirements:
|
131
203
|
- - ">="
|
132
204
|
- !ruby/object:Gem::Version
|
133
205
|
version: '0'
|
134
206
|
requirements: []
|
135
|
-
|
136
|
-
|
137
|
-
signing_key:
|
207
|
+
rubygems_version: 3.1.2
|
208
|
+
signing_key:
|
138
209
|
specification_version: 4
|
139
210
|
summary: Dynflow runtime for Foreman smart proxy
|
140
211
|
test_files: []
|