smart_proxy_dynflow_core 0.3.3 → 0.4.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8c8d92f97c019f9624f042ba66a48f3121b341b1c5f9cfdb3fe5a35a4f83f074
4
- data.tar.gz: 9707da718ef1d2d042dd4bade34e2b6d869236058bd9bf0bfcea07011862cf16
3
+ metadata.gz: 3226e9b143ecf53b28e97a765c2e760d42dc030ea3809736f5e7733b2db96cfe
4
+ data.tar.gz: eb70345b228d35506d36faa0a3fe59e09c8b1787d438f73d6554699736a70d3a
5
5
  SHA512:
6
- metadata.gz: 45ced7ab76fefbdbea72fceee20b9b7c77c9394464045d7bff56cccb2882a9fa89f2d01a858e9b2aecd6a29c09f20388b3775873b8bcd65bfdb836a540b0a848
7
- data.tar.gz: 4a08ac7bf67111e7644071d2627d341d741496282b13ae134014a8b74956ac1310f397124ea49a9468fc00bf051fd524cba244feae7fc17b050b91cfa14e3048
6
+ metadata.gz: cf3292bd295765e51968781f4a0a3678a5825977da06b56ddf86e073a232665f92f90cd5df25e0a6332304b4c3c15784404f2aae8d25f050cc77405d7520e57f
7
+ data.tar.gz: 1bdaaebb6e5b59fcf25250c4ba7695dadda3313854c8db343199bb8ec61529ed21deff5e948ac0545f6fde0eab6cde7bde73067b96943061e5bd013a22faa9db
@@ -1,19 +1,13 @@
1
- require 'dynflow'
2
- require 'smart_proxy_dynflow_core/request_id_middleware'
3
- require 'smart_proxy_dynflow_core/logger_middleware'
4
- require 'smart_proxy_dynflow_core/middleware/keep_current_request_id'
1
+ # Whatever is here is just a compatibility layer
2
+ # Once all the _core have been migrated, this can be dropped.
3
+
4
+ require 'smart_proxy_dynflow'
5
+
6
+ # REX core explicitly requires this file, otherwise we could use the trick we
7
+ # use with callback
5
8
  require 'smart_proxy_dynflow_core/task_launcher_registry'
6
- require 'foreman_tasks_core'
7
- require 'smart_proxy_dynflow_core/log'
8
- require 'smart_proxy_dynflow_core/settings'
9
- require 'smart_proxy_dynflow_core/core'
10
- require 'smart_proxy_dynflow_core/helpers'
11
- require 'smart_proxy_dynflow_core/callback'
12
- require 'smart_proxy_dynflow_core/api'
13
9
 
14
10
  module SmartProxyDynflowCore
15
- Core.after_initialize do |dynflow_core|
16
- ForemanTasksCore.dynflow_setup(dynflow_core.world)
17
- end
18
- Core.register_silencer_matchers ForemanTasksCore.silent_dead_letter_matchers
11
+ Callback = Proxy::Dynflow::Callback
12
+ Log = Proxy::Dynflow::Log
19
13
  end
@@ -1,31 +1,3 @@
1
1
  module SmartProxyDynflowCore
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
2
+ TaskLauncherRegistry = Proxy::Dynflow::TaskLauncherRegistry
31
3
  end
@@ -1,3 +1,3 @@
1
1
  module SmartProxyDynflowCore
2
- VERSION = '0.3.3'.freeze
2
+ VERSION = '0.4.0'.freeze
3
3
  end
@@ -13,10 +13,8 @@ Gem::Specification.new do |gem|
13
13
  Use the Dynflow inside Foreman smart proxy
14
14
  EOS
15
15
 
16
- gem.executables = ['smart_proxy_dynflow_core']
17
- gem.files = Dir['lib/smart_proxy_dynflow_core.rb', 'config/settings.yml.example',
18
- 'lib/smart_proxy_dynflow_core/**/*', 'LICENSE', 'Gemfile',
19
- 'bin/smart_proxy_dynflow_core', 'deploy/*', 'smart_proxy_dynflow_core.gemspec']
16
+ gem.files = Dir['lib/smart_proxy_dynflow_core.rb', 'lib/smart_proxy_dynflow_core/**/*',
17
+ 'LICENSE', 'Gemfile', 'smart_proxy_dynflow_core.gemspec']
20
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
21
19
  gem.require_paths = ["lib"]
22
20
  gem.license = 'GPL-3.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_proxy_dynflow_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.0
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: 2021-05-05 00:00:00.000000000 Z
11
+ date: 2021-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -223,31 +223,14 @@ dependencies:
223
223
  description: " Use the Dynflow inside Foreman smart proxy\n"
224
224
  email:
225
225
  - inecas@redhat.com
226
- executables:
227
- - smart_proxy_dynflow_core
226
+ executables: []
228
227
  extensions: []
229
228
  extra_rdoc_files: []
230
229
  files:
231
230
  - Gemfile
232
231
  - LICENSE
233
- - bin/smart_proxy_dynflow_core
234
- - config/settings.yml.example
235
- - deploy/smart_proxy_dynflow_core.init
236
- - deploy/smart_proxy_dynflow_core.service
237
232
  - lib/smart_proxy_dynflow_core.rb
238
- - lib/smart_proxy_dynflow_core/api.rb
239
- - lib/smart_proxy_dynflow_core/bundler_helper.rb
240
- - lib/smart_proxy_dynflow_core/callback.rb
241
- - lib/smart_proxy_dynflow_core/core.rb
242
- - lib/smart_proxy_dynflow_core/helpers.rb
243
- - lib/smart_proxy_dynflow_core/launcher.rb
244
- - lib/smart_proxy_dynflow_core/log.rb
245
- - lib/smart_proxy_dynflow_core/logger_middleware.rb
246
- - lib/smart_proxy_dynflow_core/middleware/keep_current_request_id.rb
247
- - lib/smart_proxy_dynflow_core/request_id_middleware.rb
248
- - lib/smart_proxy_dynflow_core/settings.rb
249
233
  - lib/smart_proxy_dynflow_core/task_launcher_registry.rb
250
- - lib/smart_proxy_dynflow_core/testing.rb
251
234
  - lib/smart_proxy_dynflow_core/version.rb
252
235
  - smart_proxy_dynflow_core.gemspec
253
236
  homepage: https://github.com/theforeman/smart_proxy_dynflow
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'dynflow'
3
- require 'rack'
4
- require 'smart_proxy_dynflow_core/launcher'
5
- require 'yaml'
6
- require 'optparse'
7
-
8
- options = {}
9
- OptionParser.new do |opts|
10
- opts.on('-c', '--config-dir CONFIG_DIR', String, 'Directory to load settings from') do |value|
11
- options[:config_dir] = value
12
- end
13
-
14
- opts.on('-1', '--one-config', 'Do not load more than 1 config') do |value|
15
- options[:one_config] = true
16
- end
17
-
18
- opts.on('-d', '--[no-]daemonize', 'Fork to background after start') do |value|
19
- options[:daemonize] = value
20
- end
21
-
22
- opts.on('-p', '--pid-file PID_FILE', String, 'Write pid to this file') do |value|
23
- options[:pid_file] = value
24
- end
25
-
26
- opts.on_tail('-h', '--help', 'Show usage help') do
27
- puts opts
28
- exit
29
- end
30
- end.parse!
31
-
32
- SmartProxyDynflowCore::Launcher.launch! options
@@ -1,66 +0,0 @@
1
- ---
2
- # Path to dynflow database, leave blank for in-memory non-persistent database
3
- :database:
4
-
5
- # URL of the foreman, used for reporting back
6
- :foreman_url: 'http://localhost:3000'
7
-
8
- # SSL settings for client authentication against Foreman
9
- # :foreman_ssl_ca: ssl/foreman_ca.pem
10
- # :foreman_ssl_key: ssl/foreman_key.pem
11
- # :foreman_ssl_cert: ssl/foreman_cert.pem
12
-
13
- :console_auth: false
14
-
15
- # Set to true to make the core fork to background after start
16
- # :daemonize: false
17
- # :pid_file: /var/run/foreman-proxy/smart_proxy_dynflow_core.pid
18
-
19
- # Listen on address
20
- :listen: 127.0.0.1
21
-
22
- # Listen on port
23
- :port: 8008
24
-
25
- # SSL settings for running core as https service
26
- # :use_https: false
27
- # :ssl_ca_file: ssl/ca.pem
28
- # :ssl_private_key: ssl/localhost.pem
29
- # :ssl_certificate: ssl/certs/localhost.pem
30
-
31
- # Use this option only if you need to disable certain cipher suites.
32
- # Note: we use the OpenSSL suite name, take a look at:
33
- # https://www.openssl.org/docs/manmaster/apps/ciphers.html#CIPHER-SUITE-NAMES
34
- # for more information.
35
- #:ssl_disabled_ciphers: [CIPHER-SUITE-1, CIPHER-SUITE-2]
36
-
37
- # Use this option only if you need to strictly specify TLS versions to be
38
- # disabled. SSLv3 and TLS v1.0 are always disabled and cannot be configured.
39
- # Specify versions like: '1.1', or '1.2'
40
- #:tls_disabled_versions: []
41
-
42
- # File to log to, leave empty for stdout or use STDOUT, STDERR, SYSLOG or JOURNAL
43
- #:log_file: /var/log/foreman-proxy/smart_proxy_dynflow_core.log
44
-
45
- # Log level, one of UNKNOWN, FATAL, ERROR, WARN, INFO, DEBUG
46
- #:log_level: ERROR
47
-
48
- # The maximum size of a log file before it's rolled (in MiB) or zero to disable file rolling
49
- # and rely on logrotate or similar tool
50
- #:file_rolling_size: 0
51
-
52
- # The maximum age of a log file before it's rolled (in seconds). Also accepts 'daily', 'weekly', or 'monthly'.
53
- #:file_rolling_age: weekly
54
-
55
- # Number of log files to keep
56
- #:file_rolling_keep: 6
57
-
58
- # Logging pattern for file-based loging
59
- #:file_logging_pattern: '%d %.8X{request} [%.1l] %m'
60
-
61
- # Logging pattern for syslog or journal loging
62
- #:system_logging_pattern: '%.8X{request} [%.1l] %m'
63
-
64
- # Maximum age of execution plans to keep before having them cleaned
65
- # by the execution plan cleaner (in seconds), defaults to 24 hours
66
- # :execution_plan_cleaner_age: 86400
@@ -1,92 +0,0 @@
1
- #!/bin/bash
2
- #
3
- # Init script for foreman smart proxy dynflow core service
4
- #
5
- # chkconfig: - 85 15
6
- # description: Init script for foreman proxy dynflow core service
7
-
8
- # Source function library.
9
- . /etc/rc.d/init.d/functions
10
-
11
- prog=smart_proxy_dynflow_core
12
- RETVAL=0
13
- SMART_PROXY_DYNFLOW_CORE_PID=/var/run/foreman-proxy/$prog.pid
14
- SMART_PROXY_DYNFLOW_CORE_USER=${SMART_PROXY_DYNFLOW_CORE_USER:-foreman-proxy}
15
-
16
- start() {
17
- echo -n $"Starting $prog: "
18
- ulimit -n 65536
19
- daemon --user ${SMART_PROXY_DYNFLOW_CORE_USER} /usr/bin/smart_proxy_dynflow_core -d -p $SMART_PROXY_DYNFLOW_CORE_PID > /dev/null
20
- RETVAL=$?
21
- if [ $RETVAL = 0 ]
22
- then
23
- echo_success
24
- else
25
- echo_failure
26
- fi
27
-
28
- echo
29
- return $RETVAL
30
- }
31
-
32
- stop() {
33
- echo -n $"Stopping $prog: "
34
- if [ -f ${SMART_PROXY_DYNFLOW_CORE_PID} ]; then
35
- killproc -p ${SMART_PROXY_DYNFLOW_CORE_PID}
36
- RETVAL=$?
37
- else
38
- echo -n $"$prog was not running.";
39
- failure $"$prog was not running.";
40
- echo
41
- return 1
42
- fi
43
- echo
44
- [ $RETVAL -eq 0 ] && rm -f ${SMART_PROXY_DYNFLOW_CORE_PID}
45
- return $RETVAL
46
- }
47
-
48
- logrotate() {
49
- echo -n $"Rotating logs for $prog: "
50
- if [ -f ${SMART_PROXY_DYNFLOW_CORE_PID} ]; then
51
- killproc -p ${SMART_PROXY_DYNFLOW_CORE_PID} $prog -USR1
52
- RETVAL=$?
53
- echo
54
- else
55
- echo -n $"$prog was not running.";
56
- failure $"$prog was not running.";
57
- echo
58
- return 1
59
- fi
60
- return $RETVAL
61
- }
62
-
63
- # See how we were called.
64
- case "$1" in
65
- start)
66
- start
67
- ;;
68
- stop)
69
- stop
70
- ;;
71
- status)
72
- echo -n "$prog"
73
- status -p $SMART_PROXY_DYNFLOW_CORE_PID
74
- RETVAL=$?
75
- ;;
76
- restart)
77
- stop
78
- start
79
- ;;
80
- condrestart)
81
- stop
82
- [ $? -eq 0 ] && start
83
- ;;
84
- logrotate)
85
- logrotate
86
- ;;
87
- *)
88
- echo $"Usage: $prog {start|stop|restart|condrestart|logrotate}"
89
- exit 1
90
- esac
91
-
92
- exit $RETVAL
@@ -1,13 +0,0 @@
1
- [Unit]
2
- Description=Foreman smart proxy dynflow core service
3
- Documentation=https://github.com/theforeman/smart_proxy_dynflow
4
- After=network.target remote-fs.target nss-lookup.target
5
-
6
- [Service]
7
- Type=notify
8
- User=foreman-proxy
9
- ExecStart=/usr/bin/smart_proxy_dynflow_core --no-daemonize
10
- EnvironmentFile=-/etc/sysconfig/smart_proxy_dynflow_core
11
-
12
- [Install]
13
- WantedBy=multi-user.target
@@ -1,102 +0,0 @@
1
- require 'sinatra/base'
2
- require 'multi_json'
3
-
4
- # rubocop:disable Lint/HandleExceptions
5
- begin
6
- require 'proxy/log'
7
- require 'proxy/helpers'
8
- require 'sinatra/authorization'
9
- rescue LoadError
10
- end
11
- # rubocop:enable Lint/HandleExceptions
12
-
13
- module SmartProxyDynflowCore
14
- class Api < ::Sinatra::Base
15
- TASK_UPDATE_REGEXP_PATH = %r{/tasks/(\S+)/(update|done)}
16
- helpers Helpers
17
-
18
- include ::Sinatra::Authorization::Helpers if defined?(::Sinatra::Authorization::Helpers)
19
-
20
- configure do
21
- if Settings.instance.standalone
22
- ::Sinatra::Base.set :logging, false
23
- ::Sinatra::Base.use ::SmartProxyDynflowCore::RequestIdMiddleware
24
- ::Sinatra::Base.use ::SmartProxyDynflowCore::LoggerMiddleware
25
- end
26
- end
27
-
28
- before do
29
- if match = request.path_info.match(TASK_UPDATE_REGEXP_PATH)
30
- task_id = match[1]
31
- action = match[2]
32
- authorize_with_token(task_id: task_id, clear: action == 'done')
33
- elsif Settings.instance.standalone
34
- authorize_with_ssl_client
35
- else
36
- do_authorize_any
37
- end
38
- content_type :json
39
- end
40
-
41
- post "/tasks/status" do
42
- params = MultiJson.load(request.body.read)
43
- ids = params.fetch('task_ids', [])
44
- result = world.persistence
45
- .find_execution_plans(:filters => { :uuid => ids }).reduce({}) do |acc, plan|
46
- acc.update(plan.id => { 'state' => plan.state, 'result' => plan.result })
47
- end
48
- MultiJson.dump(result)
49
- end
50
-
51
- post "/tasks/launch/?" do
52
- params = MultiJson.load(request.body.read)
53
- launcher = launcher_class(params).new(world, callback_host(params, request), params.fetch('options', {}))
54
- launcher.launch!(params['input'])
55
- launcher.results.to_json
56
- end
57
-
58
- post "/tasks/?" do
59
- params = MultiJson.load(request.body.read)
60
- trigger_task(::Dynflow::Utils.constantize(params['action_name']),
61
- params['action_input'].merge(:callback_host => callback_host(params, request))).to_json
62
- end
63
-
64
- post "/tasks/:task_id/cancel" do |task_id|
65
- cancel_task(task_id).to_json
66
- end
67
-
68
- get "/tasks/:task_id/status" do |task_id|
69
- task_status(task_id).to_json
70
- end
71
-
72
- get "/tasks/count" do
73
- tasks_count(params['state']).to_json
74
- end
75
-
76
- # capturing post "/tasks/:task_id/(update|done)"
77
- post TASK_UPDATE_REGEXP_PATH do |task_id, _action|
78
- data = MultiJson.load(request.body.read)
79
- dispatch_external_event(task_id, data)
80
- end
81
-
82
- get "/tasks/operations" do
83
- TaskLauncherRegistry.operations.to_json
84
- end
85
-
86
- private
87
-
88
- def callback_host(params, request)
89
- params.fetch('action_input', {})['proxy_url'] ||
90
- request.env.values_at('HTTP_X_FORWARDED_FOR', 'HTTP_HOST').compact.first
91
- end
92
-
93
- def launcher_class(params)
94
- operation = params.fetch('operation')
95
- if TaskLauncherRegistry.key?(operation)
96
- TaskLauncherRegistry.fetch(operation)
97
- else
98
- halt 404, MultiJson.dump(:error => "Unknown operation '#{operation}' requested.")
99
- end
100
- end
101
- end
102
- end
@@ -1,30 +0,0 @@
1
- module SmartProxyDynflowCore
2
- class BundlerHelper
3
- def self.require_groups(*groups)
4
- if File.exist?(File.expand_path('../../../Gemfile.in', __FILE__))
5
- # If there is a Gemfile.in file, we will not use Bundler but BundlerExt
6
- # gem which parses this file and loads all dependencies from the system
7
- # rathern then trying to download them from rubygems.org. It always
8
- # loads all gemfile groups.
9
- begin
10
- require 'bundler_ext' unless defined?(BundlerExt)
11
- rescue LoadError
12
- # Debian packaging guidelines state to avoid needing rubygems, so
13
- # we only try to load it if the first require fails (for RPMs)
14
- begin
15
- require 'rubygems' rescue nil
16
- require 'bundler_ext'
17
- rescue LoadError
18
- puts "`bundler_ext` gem is required to run smart_proxy"
19
- exit 1
20
- end
21
- end
22
- BundlerExt.system_require(File.expand_path('../../../Gemfile.in', __FILE__), *groups)
23
- else
24
- require 'bundler' unless defined?(Bundler)
25
- Bundler.require(*groups)
26
- end
27
- end
28
- # rubocop:enable Metrics/PerceivedComplexity
29
- end
30
- end
@@ -1,85 +0,0 @@
1
- require 'rest-client'
2
-
3
- # rubocop:disable Lint/HandleExceptions
4
- begin
5
- require 'smart_proxy_dynflow/callback'
6
- rescue LoadError
7
- end
8
- # rubocop:enable Lint/HandleExceptions
9
-
10
- module SmartProxyDynflowCore
11
- module Callback
12
- class Request
13
- class << self
14
- def send_to_foreman_tasks(callback_info, data)
15
- self.new.callback(prepare_payload(callback_info, data))
16
- end
17
-
18
- def ssl_options
19
- return @ssl_options if defined? @ssl_options
20
- @ssl_options = {}
21
- settings = Settings.instance
22
- return @ssl_options unless URI.parse(settings.foreman_url).scheme == 'https'
23
-
24
- @ssl_options[:verify_ssl] = OpenSSL::SSL::VERIFY_PEER
25
-
26
- private_key_file = settings.foreman_ssl_key || settings.ssl_private_key
27
- if private_key_file
28
- private_key = File.read(private_key_file)
29
- @ssl_options[:ssl_client_key] = OpenSSL::PKey::RSA.new(private_key)
30
- end
31
- certificate_file = settings.foreman_ssl_cert || settings.ssl_certificate
32
- if certificate_file
33
- certificate = File.read(certificate_file)
34
- @ssl_options[:ssl_client_cert] = OpenSSL::X509::Certificate.new(certificate)
35
- end
36
- ca_file = settings.foreman_ssl_ca || settings.ssl_ca_file
37
- @ssl_options[:ssl_ca_file] = ca_file if ca_file
38
- @ssl_options
39
- end
40
- # rubocop:enable Metrics/PerceivedComplexity
41
-
42
- private
43
-
44
- def prepare_payload(callback, data)
45
- { :callback => callback, :data => data }.to_json
46
- end
47
- end
48
-
49
- def callback(payload)
50
- response = callback_resource.post(payload, :content_type => :json)
51
- if response.code.to_s != "200"
52
- raise "Failed performing callback to Foreman server: #{response.code} #{response.body}"
53
- end
54
- response
55
- end
56
-
57
- private
58
-
59
- def callback_resource
60
- @resource ||= RestClient::Resource.new(Settings.instance.foreman_url + '/foreman_tasks/api/tasks/callback',
61
- self.class.ssl_options)
62
- end
63
- end
64
-
65
- class Action < ::Dynflow::Action
66
- def plan(callback, data)
67
- plan_self(:callback => callback, :data => data)
68
- end
69
-
70
- def run
71
- Callback::Request.send_to_foreman_tasks(input[:callback], input[:data])
72
- end
73
- end
74
-
75
- module PlanHelper
76
- def plan_with_callback(input)
77
- input = input.dup
78
- callback = input.delete('callback')
79
-
80
- planned_action = plan_self(input)
81
- plan_action(Callback::Action, callback, planned_action.output) if callback
82
- end
83
- end
84
- end
85
- end
@@ -1,124 +0,0 @@
1
- module SmartProxyDynflowCore
2
- class Core
3
- attr_accessor :world, :accepted_cert_serial
4
-
5
- def initialize
6
- @world = create_world
7
- cert_file = Settings.instance.foreman_ssl_cert || Settings.instance.ssl_certificate
8
- if cert_file
9
- client_cert = File.read(cert_file)
10
- # we trust only requests using the same certificate as we are
11
- # (in other words the local proxy only)
12
- @accepted_cert_serial = OpenSSL::X509::Certificate.new(client_cert).serial
13
- end
14
- end
15
-
16
- def create_world(&block)
17
- config = default_world_config(&block)
18
- world = ::Dynflow::World.new(config)
19
- world.middleware.use ::Actions::Middleware::KeepCurrentRequestID
20
- world
21
- end
22
-
23
- def persistence_conn_string
24
- return ENV['DYNFLOW_DB_CONN_STRING'] if ENV.key? 'DYNFLOW_DB_CONN_STRING'
25
- db_conn_string = 'sqlite:/'
26
-
27
- db_file = Settings.instance.database
28
- if db_file.nil? || db_file.empty?
29
- Log.instance.warn "Could not open DB for dynflow at '#{db_file}', " \
30
- "will keep data in memory. Restart will drop all dynflow data."
31
- else
32
- db_conn_string += "/#{db_file}"
33
- end
34
-
35
- db_conn_string
36
- end
37
-
38
- def persistence_adapter
39
- ::Dynflow::PersistenceAdapters::Sequel.new persistence_conn_string
40
- end
41
-
42
- def default_world_config
43
- ::Dynflow::Config.new.tap do |config|
44
- config.auto_rescue = true
45
- config.logger_adapter = logger_adapter
46
- config.persistence_adapter = persistence_adapter
47
- config.execution_plan_cleaner = execution_plan_cleaner
48
- # TODO: There has to be a better way
49
- matchers = config.silent_dead_letter_matchers.call.concat(self.class.silencer_matchers)
50
- config.silent_dead_letter_matchers = matchers
51
- yield config if block_given?
52
- end
53
- end
54
-
55
- def logger_adapter
56
- if Settings.instance.standalone
57
- Log::ProxyAdapter.new(Log.instance, Log.instance.level)
58
- else
59
- Log::ProxyAdapter.new(Proxy::LogBuffer::Decorator.instance, Log.instance.level)
60
- end
61
- end
62
-
63
- def execution_plan_cleaner
64
- proc do |world|
65
- age = Settings.instance.execution_plan_cleaner_age
66
- options = { :poll_interval => age, :max_age => age }
67
- ::Dynflow::Actors::ExecutionPlanCleaner.new(world, options)
68
- end
69
- end
70
-
71
- class << self
72
- attr_reader :instance
73
-
74
- def ensure_initialized
75
- return @instance if @instance
76
- @instance = Core.new
77
- after_initialize_blocks.each { |block| block.call(@instance) }
78
- @instance
79
- end
80
-
81
- def silencer_matchers
82
- @matchers ||= []
83
- end
84
-
85
- def register_silencer_matchers(matchers)
86
- silencer_matchers.concat matchers
87
- end
88
-
89
- def web_console
90
- require 'dynflow/web'
91
- dynflow_console = ::Dynflow::Web.setup do
92
- # we can't use the proxy's after_activation hook, as
93
- # it happens before the Daemon forks the process (including
94
- # closing opened file descriptors)
95
- # TODO: extend smart proxy to enable hooks that happen after
96
- # the forking
97
- helpers Helpers
98
-
99
- before do
100
- authorize_with_ssl_client if Settings.instance.console_auth
101
- end
102
-
103
- Core.ensure_initialized
104
- set :world, Core.world
105
- end
106
- dynflow_console
107
- end
108
-
109
- def world
110
- instance.world
111
- end
112
-
113
- def after_initialize(&block)
114
- after_initialize_blocks << block
115
- end
116
-
117
- private
118
-
119
- def after_initialize_blocks
120
- @after_initialize_blocks ||= []
121
- end
122
- end
123
- end
124
- end
@@ -1,73 +0,0 @@
1
- module SmartProxyDynflowCore
2
- module Helpers
3
- def world
4
- SmartProxyDynflowCore::Core.world
5
- end
6
-
7
- def authorize_with_token(task_id:, clear: true)
8
- if request.env.key? 'HTTP_AUTHORIZATION'
9
- if defined?(::ForemanTasksCore)
10
- auth = request.env['HTTP_AUTHORIZATION']
11
- basic_prefix = /\ABasic /
12
- if !auth.to_s.empty? && auth =~ basic_prefix &&
13
- ForemanTasksCore::OtpManager.authenticate(auth.gsub(basic_prefix, ''),
14
- expected_user: task_id, clear: clear)
15
- Log.instance.debug('authorized with token')
16
- return true
17
- end
18
- end
19
- halt 403, MultiJson.dump(:error => 'Invalid username or password supplied')
20
- end
21
- false
22
- end
23
-
24
- def authorize_with_ssl_client
25
- if %w[yes on 1].include? request.env['HTTPS'].to_s
26
- if request.env['SSL_CLIENT_CERT'].to_s.empty?
27
- Log.instance.error "No client SSL certificate supplied"
28
- halt 403, MultiJson.dump(:error => "No client SSL certificate supplied")
29
- else
30
- client_cert = OpenSSL::X509::Certificate.new(request.env['SSL_CLIENT_CERT'])
31
- unless SmartProxyDynflowCore::Core.instance.accepted_cert_serial == client_cert.serial
32
- Log.instance.error "SSL certificate with unexpected serial supplied"
33
- halt 403, MultiJson.dump(:error => "SSL certificate with unexpected serial supplied")
34
- end
35
- end
36
- else
37
- Log.instance.debug 'require_ssl_client_verification: skipping, non-HTTPS request'
38
- end
39
- end
40
-
41
- def trigger_task(*args)
42
- triggered = world.trigger(*args)
43
- { :task_id => triggered.id }
44
- end
45
-
46
- def cancel_task(task_id)
47
- execution_plan = world.persistence.load_execution_plan(task_id)
48
- cancel_events = execution_plan.cancel
49
- { :task_id => task_id, :canceled_steps_count => cancel_events.size }
50
- end
51
-
52
- def task_status(task_id)
53
- ep = world.persistence.load_execution_plan(task_id)
54
- ep.to_hash.merge(:actions => ep.actions.map(&:to_hash))
55
- rescue KeyError => _e
56
- status 404
57
- {}
58
- end
59
-
60
- def tasks_count(state)
61
- state ||= 'all'
62
- filter = state != 'all' ? { :filters => { :state => [state] } } : {}
63
- tasks = world.persistence.find_execution_plans(filter)
64
- { :count => tasks.count, :state => state }
65
- end
66
-
67
- def dispatch_external_event(task_id, params)
68
- world.event(task_id,
69
- params['step_id'].to_i,
70
- ::ForemanTasksCore::Runner::ExternalEvent.new(params))
71
- end
72
- end
73
- end
@@ -1,166 +0,0 @@
1
- require 'webrick/https'
2
- require 'smart_proxy_dynflow_core/bundler_helper'
3
- require 'smart_proxy_dynflow_core/settings'
4
- require 'sd_notify'
5
-
6
- module SmartProxyDynflowCore
7
- class Launcher
8
- CIPHERS = ['ECDHE-RSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES256-GCM-SHA384',
9
- 'AES128-GCM-SHA256', 'AES256-GCM-SHA384', 'AES128-SHA256',
10
- 'AES256-SHA256', 'AES128-SHA', 'AES256-SHA'].freeze
11
-
12
- def self.launch!(options)
13
- self.new.start options
14
- end
15
-
16
- def start(options)
17
- Settings.instance.standalone = true
18
- load_settings!(options)
19
- install_usr1_trap
20
- Rack::Server.new(rack_settings).start do |_server|
21
- SmartProxyDynflowCore::Core.ensure_initialized
22
- ::SdNotify.ready
23
- end
24
- Log.instance.info "Finished shutting down"
25
- Logging.shutdown
26
- end
27
-
28
- def load_settings!(options = {})
29
- config_dir, one_config = options.values_at(:config_dir, :one_config)
30
- possible_config_dirs = [
31
- '/etc/smart_proxy_dynflow_core',
32
- File.expand_path('~/.config/smart_proxy_dynflow_core'),
33
- File.join(File.dirname(__FILE__), '..', '..', 'config'),
34
- ]
35
- possible_config_dirs << config_dir if config_dir
36
- BundlerHelper.require_groups(:default)
37
- possible_config_dirs.reverse! if one_config
38
- possible_config_dirs.select { |config_dir| File.directory? config_dir }.each do |config_dir|
39
- break if load_config_dir(config_dir) && one_config
40
- end
41
- Settings.instance.daemonize = options[:daemonize] if options.key?(:daemonize)
42
- Settings.instance.pid_file = options[:pid_file] if options.key?(:pid_file)
43
- Settings.loaded!
44
- end
45
-
46
- def self.route_mapping(rack_builder)
47
- rack_builder.map '/console' do
48
- run Core.web_console
49
- end
50
-
51
- rack_builder.map '/' do
52
- run Api
53
- end
54
- end
55
-
56
- def install_usr1_trap
57
- trap(:USR1) do
58
- Log.reopen
59
- end
60
- end
61
-
62
- private
63
-
64
- def rack_settings
65
- settings = if https_enabled?
66
- Log.instance.debug "Using HTTPS"
67
- https_app
68
- else
69
- Log.instance.debug "Using HTTP"
70
- {}
71
- end
72
- settings.merge(base_settings)
73
- end
74
-
75
- def app
76
- Rack::Builder.new do
77
- SmartProxyDynflowCore::Launcher.route_mapping(self)
78
- end
79
- end
80
-
81
- def base_settings
82
- {
83
- :app => app,
84
- :Host => Settings.instance.listen,
85
- :Port => Settings.instance.port,
86
- :AccessLog => [],
87
- :Logger => Log.instance,
88
- :daemonize => Settings.instance.daemonize,
89
- :pid => Settings.instance.daemonize && Settings.instance.pid_file,
90
- :server => :webrick
91
- }
92
- end
93
-
94
- def https_app
95
- ssl_options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
96
- ssl_options |= OpenSSL::SSL::OP_CIPHER_SERVER_PREFERENCE if defined?(OpenSSL::SSL::OP_CIPHER_SERVER_PREFERENCE)
97
- # This is required to disable SSLv3 on Ruby 1.8.7
98
- ssl_options |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2)
99
- ssl_options |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3)
100
- ssl_options |= OpenSSL::SSL::OP_NO_TLSv1 if defined?(OpenSSL::SSL::OP_NO_TLSv1)
101
- ssl_options |= OpenSSL::SSL::OP_NO_TLSv1_1 if defined?(OpenSSL::SSL::OP_NO_TLSv1_1)
102
-
103
- Settings.instance.tls_disabled_versions&.each do |version|
104
- constant = OpenSSL::SSL.const_get("OP_NO_TLSv#{version.to_s.tr('.', '_')}") rescue nil
105
-
106
- if constant
107
- Log.instance.info "TLSv#{version} will be disabled."
108
- ssl_options |= constant
109
- else
110
- Log.instance.warn "TLSv#{version} was not found."
111
- end
112
- end
113
-
114
- {
115
- :SSLEnable => true,
116
- :SSLVerifyClient => OpenSSL::SSL::VERIFY_PEER,
117
- :SSLPrivateKey => ssl_private_key,
118
- :SSLCertificate => ssl_certificate,
119
- :SSLCACertificateFile => Settings.instance.ssl_ca_file,
120
- :SSLCiphers => CIPHERS - SmartProxyDynflowCore::Settings.instance.ssl_disabled_ciphers,
121
- :SSLOptions => ssl_options
122
- }
123
- end
124
- # rubocop:enable Metrics/PerceivedComplexity
125
-
126
- def https_enabled?
127
- Settings.instance.use_https
128
- end
129
-
130
- def ssl_private_key
131
- OpenSSL::PKey::RSA.new(File.read(Settings.instance.ssl_private_key))
132
- rescue Exception => e
133
- Log.instance.fatal "Unable to load private SSL key. Are the values "\
134
- "correct in settings.yml and do permissions allow reading?: #{e}"
135
- raise e
136
- end
137
-
138
- def ssl_certificate
139
- OpenSSL::X509::Certificate.new(File.read(Settings.instance.ssl_certificate))
140
- rescue Exception => e
141
- Log.instance.fatal "Unable to load SSL certificate. Are the values " \
142
- "correct in settings.yml and do permissions allow reading?: #{e}"
143
- raise e
144
- end
145
-
146
- def load_config_dir(dir)
147
- settings_yml = File.join(dir, 'settings.yml')
148
- if File.exist? settings_yml
149
- Log.instance.debug "Loading settings from #{dir}"
150
- Settings.load_global_settings settings_yml
151
- Dir[File.join(dir, 'settings.d', '*.yml')].each { |path| Settings.load_plugin_settings(path) }
152
- true
153
- end
154
- ForemanTasksCore::SettingsLoader.settings_registry.each_key do |settings_keys|
155
- settings = settings_keys.inject({}) do |h, settings_key|
156
- if SETTINGS.plugins.key?(settings_key.to_s)
157
- h.merge(SETTINGS.plugins[settings_key.to_s].to_h)
158
- else
159
- h
160
- end
161
- end
162
- ForemanTasksCore::SettingsLoader.setup_settings(settings_keys.first, settings)
163
- end
164
- end
165
- end
166
- end
@@ -1,146 +0,0 @@
1
- require 'logging'
2
-
3
- module SmartProxyDynflowCore
4
- class ReopenAppender < ::Logging::Appender
5
- def initialize(name, logger, opts = {})
6
- @reopen = false
7
- @logger = logger
8
- super(name, opts)
9
- end
10
-
11
- def set(status = true)
12
- @reopen = status
13
- end
14
-
15
- def append(_event)
16
- if @reopen
17
- Logging.reopen
18
- @reopen = false
19
- end
20
- end
21
- end
22
-
23
- class Log
24
- BASE_LOG_SIZE = 1024 * 1024 # 1 MiB
25
- LOGGER_NAME = 'dynflow-core'.freeze
26
-
27
- begin
28
- require 'syslog/logger'
29
- @syslog_available = true
30
- rescue LoadError
31
- @syslog_available = false
32
- end
33
-
34
- class << self
35
- def reload!
36
- Logging.logger[LOGGER_NAME].appenders.each(&:close)
37
- Logging.logger[LOGGER_NAME].clear_appenders
38
- @logger = nil
39
- instance
40
- end
41
-
42
- def reopen
43
- return if @logger.nil? || @reopen.nil?
44
- if Settings.instance.log_file !~ /^(STDOUT|SYSLOG|JOURNALD?)$/i
45
- @reopen.set
46
- end
47
- end
48
-
49
- def instance
50
- return ::Proxy::LogBuffer::Decorator.instance unless Settings.instance.standalone
51
- return @logger if @logger
52
- layout = Logging::Layouts.pattern(pattern: Settings.instance.file_logging_pattern + "\n")
53
- notime_layout = Logging::Layouts.pattern(pattern: Settings.instance.system_logging_pattern + "\n")
54
- log_file = Settings.instance.log_file || ''
55
- @logger = Logging.logger[LOGGER_NAME]
56
- @reopen = ReopenAppender.new("Reopen dummy appender", @logger)
57
- @logger.add_appenders(@reopen)
58
- if !Settings.instance.loaded || log_file.casecmp('STDOUT').zero?
59
- @logger.add_appenders(Logging.appenders.stdout(LOGGER_NAME, layout: layout))
60
- elsif log_file.casecmp('SYSLOG').zero?
61
- unless @syslog_available
62
- puts "Syslog is not supported on this platform, use STDOUT or a file"
63
- exit(1)
64
- end
65
- @logger.add_appenders(Logging.appenders.syslog(LOGGER_NAME, layout: notime_layout, facility: ::Syslog::Constants::LOG_LOCAL5))
66
- elsif log_file.casecmp('JOURNAL').zero? || log_file.casecmp('JOURNALD').zero?
67
- begin
68
- @logger.add_appenders(Logging.appenders.journald(LOGGER_NAME, LOGGER_NAME: :proxy_logger, layout: notime_layout, facility: ::Syslog::Constants::LOG_LOCAL5))
69
- rescue NoMethodError
70
- @logger.add_appenders(Logging.appenders.stdout(LOGGER_NAME, layout: layout))
71
- @logger.warn "Journald is not available on this platform. Falling back to STDOUT."
72
- end
73
- else
74
- begin
75
- keep = Settings.instance.file_rolling_keep
76
- size = BASE_LOG_SIZE * Settings.instance.file_rolling_size
77
- age = Settings.instance.file_rolling_age
78
- if size.positive?
79
- @logger.add_appenders(Logging.appenders.rolling_file(LOGGER_NAME, layout: layout, filename: log_file, keep: keep, size: size, age: age, roll_by: 'number'))
80
- else
81
- @logger.add_appenders(Logging.appenders.file(LOGGER_NAME, layout: layout, filename: log_file))
82
- end
83
- rescue ArgumentError => ae
84
- @logger.add_appenders(Logging.appenders.stdout(LOGGER_NAME, layout: layout))
85
- @logger.warn "Log file #{log_file} cannot be opened. Falling back to STDOUT: #{ae}"
86
- end
87
- end
88
- @logger.level = ::Logging.level_num(Settings.instance.log_level)
89
- @logger
90
- end
91
-
92
- def with_fields(fields = {})
93
- ::Logging.ndc.push(fields) do
94
- yield
95
- end
96
- end
97
-
98
- # Standard way for logging exceptions to get the most data in the log. By default
99
- # it logs via warn level, this can be changed via options[:level]
100
- def exception(context_message, exception, options = {})
101
- level = options[:level] || :warn
102
- unless ::Logging::LEVELS.keys.include?(level.to_s)
103
- raise "Unexpected log level #{level}, expected one of #{::Logging::LEVELS.keys}"
104
- end
105
- # send class, message and stack as structured fields in addition to message string
106
- backtrace = exception.backtrace ? exception.backtrace : []
107
- extra_fields = {
108
- exception_class: exception.class.name,
109
- exception_message: exception.message,
110
- exception_backtrace: backtrace
111
- }
112
- extra_fields[:foreman_code] = exception.code if exception.respond_to?(:code)
113
- with_fields(extra_fields) do
114
- @logger.public_send(level) do
115
- ([context_message, "#{exception.class}: #{exception.message}"] + backtrace).join("\n")
116
- end
117
- end
118
- end
119
- end
120
-
121
- class ProxyStructuredFormater < ::Dynflow::LoggerAdapters::Formatters::Abstract
122
- def format(message)
123
- if message.is_a?(Exception)
124
- subject = "#{message.message} (#{message.class})"
125
- if @base.respond_to?(:exception)
126
- @base.exception("Error details", message)
127
- subject
128
- else
129
- "#{subject}\n#{message.backtrace.join("\n")}"
130
- end
131
- else
132
- @original_formatter.call(severity, datetime, prog_name, message)
133
- end
134
- end
135
- end
136
-
137
- class ProxyAdapter < ::Dynflow::LoggerAdapters::Simple
138
- def initialize(logger, level = Logger::DEBUG, _formatters = [])
139
- @logger = logger
140
- @logger.level = level
141
- @action_logger = apply_formatters(ProgNameWrapper.new(@logger, ' action'), [])
142
- @dynflow_logger = apply_formatters(ProgNameWrapper.new(@logger, 'dynflow'), [])
143
- end
144
- end
145
- end
146
- end
@@ -1,31 +0,0 @@
1
- module SmartProxyDynflowCore
2
- class LoggerMiddleware
3
- def initialize(app)
4
- @logger = SmartProxyDynflowCore::Log.instance
5
- @app = app
6
- end
7
-
8
- def call(env)
9
- before = Time.now.to_f
10
- status = 500
11
- env['rack.logger'] = @logger
12
- @logger.info { "Started #{env['REQUEST_METHOD']} #{env['PATH_INFO']} #{env['QUERY_STRING']}" }
13
- @logger.debug { 'Headers: ' + env.select { |k, v| k.start_with? 'HTTP_' }.inspect }
14
- if @logger.debug? && env['rack.input']
15
- body = env['rack.input'].read
16
- @logger.debug('Body: ' + body) unless body.empty?
17
- env['rack.input'].rewind
18
- end
19
- status, = @app.call(env)
20
- rescue Exception => e
21
- Log.exception "Error processing request '#{::Logging.mdc['request']}", e
22
- raise e
23
- ensure
24
- @logger.info do
25
- after = Time.now.to_f
26
- duration = (after - before) * 1000
27
- "Finished #{env['REQUEST_METHOD']} #{env['PATH_INFO']} with #{status} (#{duration.round(2)} ms)"
28
- end
29
- end
30
- end
31
- end
@@ -1,59 +0,0 @@
1
- module Actions
2
- module Middleware
3
- class KeepCurrentRequestID < Dynflow::Middleware
4
- def delay(*args)
5
- pass(*args).tap { store_current_request_id }
6
- end
7
-
8
- def plan(*args)
9
- with_current_request_id do
10
- pass(*args).tap { store_current_request_id }
11
- end
12
- end
13
-
14
- def run(*args)
15
- restore_current_request_id { pass(*args) }
16
- end
17
-
18
- def finalize
19
- restore_current_request_id { pass }
20
- end
21
-
22
- # Run all execution plan lifecycle hooks as the original request_id
23
- def hook(*args)
24
- restore_current_request_id { pass(*args) }
25
- end
26
-
27
- private
28
-
29
- def with_current_request_id
30
- if action.input[:current_request_id].nil?
31
- yield
32
- else
33
- restore_current_request_id { yield }
34
- end
35
- end
36
-
37
- def store_current_request_id
38
- action.input[:current_request_id] = ::Logging.mdc['request']
39
- end
40
-
41
- def restore_current_request_id
42
- unless (restored_id = action.input[:current_request_id]).nil?
43
- old_id = ::Logging.mdc['request']
44
- if !old_id.nil? && old_id != restored_id
45
- action.action_logger.warn('Changing request id %{request_id} to saved id %{saved_id}' % { :saved_id => restored_id, :request_id => old_id })
46
- end
47
- ::Logging.mdc['request'] = restored_id
48
- end
49
- yield
50
- ensure
51
- # Reset to original request id only when not nil
52
- # Otherwise, keep the id until it's cleaned in Dynflow's run_user_code block
53
- # so that it will stay valid for the rest of the processing of the current step
54
- # (even outside of the middleware lifecycle)
55
- ::Logging.mdc['request'] = old_id unless old_id.nil?
56
- end
57
- end
58
- end
59
- end
@@ -1,18 +0,0 @@
1
- module SmartProxyDynflowCore
2
- class RequestIdMiddleware
3
- def initialize(app)
4
- @app = app
5
- end
6
-
7
- def call(env)
8
- ::Logging.mdc['remote_ip'] = env['REMOTE_ADDR']
9
- if env.has_key?('HTTP_X_REQUEST_ID')
10
- ::Logging.mdc['request'] = env['HTTP_X_REQUEST_ID']
11
- else
12
- ::Logging.mdc['request'] = SecureRandom.uuid
13
- end
14
- status, header, body = @app.call(env)
15
- [status, header, ::Rack::BodyProxy.new(body) { ::Logging.mdc.clear }]
16
- end
17
- end
18
- end
@@ -1,86 +0,0 @@
1
- require 'ostruct'
2
-
3
- module SmartProxyDynflowCore
4
- class Settings < OpenStruct
5
- DEFAULT_SETTINGS = {
6
- :database => '/var/lib/foreman-proxy/dynflow/dynflow.sqlite',
7
- :foreman_url => 'https://127.0.0.1:3000',
8
- :console_auth => true,
9
- :listen => '127.0.0.1',
10
- :port => '8008',
11
- :use_https => false,
12
- :ssl_ca_file => nil,
13
- :ssl_private_key => nil,
14
- :ssl_certificate => nil,
15
- :ssl_disabled_ciphers => [],
16
- :tls_disabled_versions => [],
17
- :foreman_ssl_ca => nil,
18
- :foreman_ssl_key => nil,
19
- :foreman_ssl_cert => nil,
20
- :standalone => false,
21
- :log_file => '/var/log/foreman-proxy/smart_proxy_dynflow_core.log',
22
- :log_level => :ERROR,
23
- :plugins => {},
24
- :pid_file => '/var/run/foreman-proxy/smart_proxy_dynflow_core.pid',
25
- :daemonize => false,
26
- :execution_plan_cleaner_age => 60 * 60 * 24,
27
- :loaded => false,
28
- :file_logging_pattern => '%d %.8X{request} [%.1l] %m',
29
- :system_logging_pattern => '%.8X{request} [%.1l] %m',
30
- :file_rolling_keep => 6,
31
- :file_rolling_size => 0,
32
- :file_rolling_age => 'weekly'
33
- }.freeze
34
-
35
- PROXY_SETTINGS = %i[ssl_ca_file ssl_certificate ssl_private_key foreman_url
36
- foreman_ssl_ca foreman_ssl_cert foreman_ssl_key
37
- log_file log_level ssl_disabled_ciphers].freeze
38
- PLUGIN_SETTINGS = %i[database core_url console_auth
39
- execution_plan_cleaner_age].freeze
40
-
41
- def initialize(settings = {})
42
- super(DEFAULT_SETTINGS.merge(settings))
43
- end
44
-
45
- def self.instance
46
- SmartProxyDynflowCore::SETTINGS
47
- end
48
-
49
- def self.load_global_settings(path)
50
- if File.exist? File.join(path)
51
- YAML.load_file(path).each do |key, value|
52
- SETTINGS[key] = value
53
- end
54
- end
55
- end
56
-
57
- def self.loaded!
58
- Settings.instance.loaded = true
59
- Log.instance.info 'Settings loaded, reloading logger'
60
- Log.reload!
61
- end
62
-
63
- def self.load_from_proxy(plugin)
64
- settings = plugin.settings.to_h
65
- PROXY_SETTINGS.each do |key|
66
- SETTINGS[key] = Proxy::SETTINGS[key]
67
- end
68
- PLUGIN_SETTINGS.each do |key|
69
- SETTINGS[key] = settings[key] if settings.key?(key)
70
- end
71
- SETTINGS.plugins.values.each(&:load_settings_from_proxy)
72
- Settings.loaded!
73
- end
74
-
75
- def self.load_plugin_settings(path)
76
- settings = YAML.load_file(path)
77
- name = File.basename(path).gsub(/\.yml$/, '')
78
- if SETTINGS.plugins.key? name
79
- settings = SETTINGS.plugins[name].to_h.merge(settings || {})
80
- end
81
- SETTINGS.plugins[name] = OpenStruct.new settings
82
- end
83
- end
84
- end
85
-
86
- SmartProxyDynflowCore::SETTINGS = SmartProxyDynflowCore::Settings.new
@@ -1,28 +0,0 @@
1
- require 'dynflow/testing'
2
-
3
- unless defined? DYNFLOW_TESTING_LOG_LEVEL
4
- DYNFLOW_TESTING_LOG_LEVEL = 4
5
- end
6
-
7
- module SmartProxyDynflowCore
8
- class Dynflow
9
- # Helper for usage in other dependent plugins that need Dynflow
10
- # related things, such as testing instance of world etc.
11
- module Testing
12
- class << self
13
- def create_world(&block)
14
- Core.ensure_initialized
15
- Core.instance.create_world do |config|
16
- config.exit_on_terminate = false
17
- config.auto_terminate = false
18
- config.logger_adapter = ::Dynflow::LoggerAdapters::Simple.new $stderr, DYNFLOW_TESTING_LOG_LEVEL
19
- config.execution_plan_cleaner = nil
20
- yield(config) if block
21
- end
22
- end
23
- end
24
- end
25
- end
26
- end
27
-
28
- Concurrent.disable_at_exit_handlers!