smart_proxy_dynflow_core 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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!