smart_proxy_dynflow 0.2.4 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +6 -25
  3. data/{bundler.plugins.d → bundler.d}/dynflow.rb +0 -0
  4. data/lib/smart_proxy_dynflow.rb +16 -1
  5. data/lib/smart_proxy_dynflow/action.rb +12 -0
  6. data/lib/smart_proxy_dynflow/action/batch.rb +21 -0
  7. data/lib/smart_proxy_dynflow/action/batch_callback.rb +20 -0
  8. data/lib/smart_proxy_dynflow/action/batch_runner.rb +14 -0
  9. data/lib/smart_proxy_dynflow/action/output_collector.rb +8 -0
  10. data/lib/smart_proxy_dynflow/action/runner.rb +76 -0
  11. data/lib/smart_proxy_dynflow/action/shareable.rb +25 -0
  12. data/lib/smart_proxy_dynflow/action/single_runner_batch.rb +39 -0
  13. data/lib/smart_proxy_dynflow/api.rb +63 -40
  14. data/lib/smart_proxy_dynflow/callback.rb +69 -25
  15. data/lib/smart_proxy_dynflow/continuous_output.rb +50 -0
  16. data/lib/smart_proxy_dynflow/core.rb +121 -0
  17. data/lib/smart_proxy_dynflow/helpers.rb +52 -6
  18. data/lib/smart_proxy_dynflow/http_config.ru +6 -16
  19. data/lib/smart_proxy_dynflow/log.rb +52 -0
  20. data/lib/smart_proxy_dynflow/middleware/keep_current_request_id.rb +59 -0
  21. data/lib/smart_proxy_dynflow/otp_manager.rb +36 -0
  22. data/lib/smart_proxy_dynflow/plugin.rb +9 -14
  23. data/lib/smart_proxy_dynflow/proxy_adapter.rb +1 -1
  24. data/lib/smart_proxy_dynflow/runner.rb +10 -0
  25. data/lib/smart_proxy_dynflow/runner/base.rb +98 -0
  26. data/lib/smart_proxy_dynflow/runner/command.rb +40 -0
  27. data/lib/smart_proxy_dynflow/runner/command_runner.rb +11 -0
  28. data/lib/smart_proxy_dynflow/runner/dispatcher.rb +191 -0
  29. data/lib/smart_proxy_dynflow/runner/parent.rb +57 -0
  30. data/lib/smart_proxy_dynflow/runner/update.rb +28 -0
  31. data/lib/smart_proxy_dynflow/settings.rb +9 -0
  32. data/lib/smart_proxy_dynflow/settings_loader.rb +53 -0
  33. data/lib/smart_proxy_dynflow/task_launcher.rb +9 -0
  34. data/lib/smart_proxy_dynflow/task_launcher/abstract.rb +44 -0
  35. data/lib/smart_proxy_dynflow/task_launcher/batch.rb +37 -0
  36. data/lib/smart_proxy_dynflow/task_launcher/group.rb +48 -0
  37. data/lib/smart_proxy_dynflow/task_launcher/single.rb +17 -0
  38. data/lib/smart_proxy_dynflow/task_launcher_registry.rb +31 -0
  39. data/lib/smart_proxy_dynflow/testing.rb +24 -0
  40. data/lib/smart_proxy_dynflow/ticker.rb +47 -0
  41. data/lib/smart_proxy_dynflow/version.rb +2 -2
  42. data/settings.d/dynflow.yml.example +6 -5
  43. metadata +83 -11
@@ -0,0 +1,9 @@
1
+ # require 'ostruct'
2
+
3
+ module Proxy::Dynflow
4
+ class Settings
5
+ def self.instance
6
+ Proxy::Dynflow::Plugin.settings
7
+ end
8
+ end
9
+ end
@@ -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,5 +1,5 @@
1
1
  module Proxy
2
- class Dynflow
3
- VERSION = '0.2.4'.freeze
2
+ module Dynflow
3
+ VERSION = '0.5.2'.freeze
4
4
  end
5
5
  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
- # If true, external core will be used even if the core gem is available
7
- # If false, the feature will be disabled if the core gem is not available
8
- # If unset, the process will fallback to external core if the core gem is not available
9
- # :external_core: true
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.2.4
4
+ version: 0.5.2
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-10-04 00:00:00.000000000 Z
11
+ date: 2021-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bundler
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,37 +145,67 @@ extra_rdoc_files: []
103
145
  files:
104
146
  - Gemfile
105
147
  - LICENSE
106
- - bundler.plugins.d/dynflow.rb
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: '0'
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
- rubygems_version: 3.0.3
136
- signing_key:
207
+ rubygems_version: 3.1.2
208
+ signing_key:
137
209
  specification_version: 4
138
210
  summary: Dynflow runtime for Foreman smart proxy
139
211
  test_files: []