smart_proxy_dynflow_core 0.2.5 → 0.3.3

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: 1e605170d98b043dbebe0199fa07878a479c49517398b76b9ea8763b3f11a944
4
- data.tar.gz: 3ca809db6838f8922b523c05b9009f7c06f6f3b7b225f708c0250dab92ee42e5
3
+ metadata.gz: 8c8d92f97c019f9624f042ba66a48f3121b341b1c5f9cfdb3fe5a35a4f83f074
4
+ data.tar.gz: 9707da718ef1d2d042dd4bade34e2b6d869236058bd9bf0bfcea07011862cf16
5
5
  SHA512:
6
- metadata.gz: 83e7a7cefc7149bbdd9ea1fe75e10abcf3b3264aff1831e64aa87ac9e136404e35c5caf18d376e40be6d7ea845815f30aaa7a3a654d25236d437d7db84472f95
7
- data.tar.gz: f748d215cca4ddf825b5f692568f162afdaf16aa394efb776df551365eaf1a09a925f9698a30f16e68c249865976a3aa8115ce5149e845403d1a7598f5de6380
6
+ metadata.gz: 45ced7ab76fefbdbea72fceee20b9b7c77c9394464045d7bff56cccb2882a9fa89f2d01a858e9b2aecd6a29c09f20388b3775873b8bcd65bfdb836a540b0a848
7
+ data.tar.gz: 4a08ac7bf67111e7644071d2627d341d741496282b13ae134014a8b74956ac1310f397124ea49a9468fc00bf051fd524cba244feae7fc17b050b91cfa14e3048
data/Gemfile CHANGED
@@ -10,28 +10,14 @@ group :test do
10
10
  gem 'smart_proxy', :git => "https://github.com/theforeman/smart-proxy", :branch => "develop"
11
11
  gem 'smart_proxy_dynflow', :path => '.'
12
12
 
13
- if RUBY_VERSION < '2.1'
14
- gem 'public_suffix', '< 3'
15
- gem 'rainbow', '< 3'
16
- else
17
- gem 'public_suffix'
18
- gem 'rubocop', '~> 0.52.1'
19
- end
20
-
21
- if RUBY_VERSION < '2.2'
22
- gem 'rack-test', '< 0.8'
23
- else
24
- gem 'rack-test'
25
- end
13
+ gem 'public_suffix'
14
+ gem 'rack-test'
15
+ gem 'rubocop', '~> 0.52.1'
26
16
  end
27
17
 
28
- if RUBY_VERSION < '2.2'
29
- gem 'rack', '>= 1.1', '< 2.0.0'
30
- gem 'sinatra', '< 2'
31
- else
32
- gem 'rack', '>= 1.1'
33
- gem 'sinatra'
34
- end
18
+ gem 'logging-journald', '~> 2.0', :platforms => [:ruby], :require => false
19
+ gem 'rack', '>= 1.1'
20
+ gem 'sinatra'
35
21
 
36
22
  # load bundler.d
37
23
  Dir["#{File.dirname(__FILE__)}/bundler.d/*.rb"].each do |bundle|
@@ -39,11 +39,27 @@
39
39
  # Specify versions like: '1.1', or '1.2'
40
40
  #:tls_disabled_versions: []
41
41
 
42
- # File to log to, leave empty for logging to STDOUT
43
- # :log_file: /var/log/foreman-proxy/smart_proxy_dynflow_core.log
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
44
 
45
45
  # Log level, one of UNKNOWN, FATAL, ERROR, WARN, INFO, DEBUG
46
- # :log_level: ERROR
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'
47
63
 
48
64
  # Maximum age of execution plans to keep before having them cleaned
49
65
  # by the execution plan cleaner (in seconds), defaults to 24 hours
@@ -4,10 +4,9 @@ Documentation=https://github.com/theforeman/smart_proxy_dynflow
4
4
  After=network.target remote-fs.target nss-lookup.target
5
5
 
6
6
  [Service]
7
- Type=forking
7
+ Type=notify
8
8
  User=foreman-proxy
9
- PIDFile=/var/run/foreman-proxy/smart_proxy_dynflow_core.pid
10
- ExecStart=/usr/bin/smart_proxy_dynflow_core -d -p /var/run/foreman-proxy/smart_proxy_dynflow_core.pid
9
+ ExecStart=/usr/bin/smart_proxy_dynflow_core --no-daemonize
11
10
  EnvironmentFile=-/etc/sysconfig/smart_proxy_dynflow_core
12
11
 
13
12
  [Install]
@@ -1,6 +1,7 @@
1
- raise LoadError, 'Ruby >= 2.1 is required' unless RUBY_VERSION >= '2.1'
2
-
3
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'
4
5
  require 'smart_proxy_dynflow_core/task_launcher_registry'
5
6
  require 'foreman_tasks_core'
6
7
  require 'smart_proxy_dynflow_core/log'
@@ -1,18 +1,39 @@
1
1
  require 'sinatra/base'
2
2
  require 'multi_json'
3
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
+
4
13
  module SmartProxyDynflowCore
5
14
  class Api < ::Sinatra::Base
6
15
  TASK_UPDATE_REGEXP_PATH = %r{/tasks/(\S+)/(update|done)}
7
16
  helpers Helpers
8
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
+
9
28
  before do
10
29
  if match = request.path_info.match(TASK_UPDATE_REGEXP_PATH)
11
30
  task_id = match[1]
12
31
  action = match[2]
13
32
  authorize_with_token(task_id: task_id, clear: action == 'done')
14
- else
33
+ elsif Settings.instance.standalone
15
34
  authorize_with_ssl_client
35
+ else
36
+ do_authorize_any
16
37
  end
17
38
  content_type :json
18
39
  end
@@ -1,6 +1,5 @@
1
1
  module SmartProxyDynflowCore
2
2
  class BundlerHelper
3
- # rubocop:disable Metrics/PerceivedComplexity
4
3
  def self.require_groups(*groups)
5
4
  if File.exist?(File.expand_path('../../../Gemfile.in', __FILE__))
6
5
  # If there is a Gemfile.in file, we will not use Bundler but BundlerExt
@@ -15,7 +15,6 @@ module SmartProxyDynflowCore
15
15
  self.new.callback(prepare_payload(callback_info, data))
16
16
  end
17
17
 
18
- # rubocop:disable Metrics/PerceivedComplexity
19
18
  def ssl_options
20
19
  return @ssl_options if defined? @ssl_options
21
20
  @ssl_options = {}
@@ -15,7 +15,9 @@ module SmartProxyDynflowCore
15
15
 
16
16
  def create_world(&block)
17
17
  config = default_world_config(&block)
18
- ::Dynflow::World.new(config)
18
+ world = ::Dynflow::World.new(config)
19
+ world.middleware.use ::Actions::Middleware::KeepCurrentRequestID
20
+ world
19
21
  end
20
22
 
21
23
  def persistence_conn_string
@@ -1,6 +1,7 @@
1
1
  require 'webrick/https'
2
2
  require 'smart_proxy_dynflow_core/bundler_helper'
3
3
  require 'smart_proxy_dynflow_core/settings'
4
+ require 'sd_notify'
4
5
 
5
6
  module SmartProxyDynflowCore
6
7
  class Launcher
@@ -13,12 +14,15 @@ module SmartProxyDynflowCore
13
14
  end
14
15
 
15
16
  def start(options)
16
- load_settings!(options)
17
17
  Settings.instance.standalone = true
18
+ load_settings!(options)
18
19
  install_usr1_trap
19
20
  Rack::Server.new(rack_settings).start do |_server|
20
21
  SmartProxyDynflowCore::Core.ensure_initialized
22
+ ::SdNotify.ready
21
23
  end
24
+ Log.instance.info "Finished shutting down"
25
+ Logging.shutdown
22
26
  end
23
27
 
24
28
  def load_settings!(options = {})
@@ -51,7 +55,7 @@ module SmartProxyDynflowCore
51
55
 
52
56
  def install_usr1_trap
53
57
  trap(:USR1) do
54
- Log.instance.roll_log
58
+ Log.reopen
55
59
  end
56
60
  end
57
61
 
@@ -79,15 +83,14 @@ module SmartProxyDynflowCore
79
83
  :app => app,
80
84
  :Host => Settings.instance.listen,
81
85
  :Port => Settings.instance.port,
82
- :AccessLog => [[Log.instance, WEBrick::AccessLog::COMMON_LOG_FORMAT]],
86
+ :AccessLog => [],
83
87
  :Logger => Log.instance,
84
88
  :daemonize => Settings.instance.daemonize,
85
- :pid => Settings.instance.pid_file,
89
+ :pid => Settings.instance.daemonize && Settings.instance.pid_file,
86
90
  :server => :webrick
87
91
  }
88
92
  end
89
93
 
90
- # rubocop:disable Metrics/PerceivedComplexity
91
94
  def https_app
92
95
  ssl_options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
93
96
  ssl_options |= OpenSSL::SSL::OP_CIPHER_SERVER_PREFERENCE if defined?(OpenSSL::SSL::OP_CIPHER_SERVER_PREFERENCE)
@@ -97,16 +100,14 @@ module SmartProxyDynflowCore
97
100
  ssl_options |= OpenSSL::SSL::OP_NO_TLSv1 if defined?(OpenSSL::SSL::OP_NO_TLSv1)
98
101
  ssl_options |= OpenSSL::SSL::OP_NO_TLSv1_1 if defined?(OpenSSL::SSL::OP_NO_TLSv1_1)
99
102
 
100
- if Settings.instance.tls_disabled_versions
101
- Settings.instance.tls_disabled_versions.each do |version|
102
- constant = OpenSSL::SSL.const_get("OP_NO_TLSv#{version.to_s.tr('.', '_')}") rescue nil
103
+ Settings.instance.tls_disabled_versions&.each do |version|
104
+ constant = OpenSSL::SSL.const_get("OP_NO_TLSv#{version.to_s.tr('.', '_')}") rescue nil
103
105
 
104
- if constant
105
- Log.instance.info "TLSv#{version} will be disabled."
106
- ssl_options |= constant
107
- else
108
- Log.instance.warn "TLSv#{version} was not found."
109
- end
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."
110
111
  end
111
112
  end
112
113
 
@@ -1,61 +1,126 @@
1
- require 'logger'
1
+ require 'logging'
2
2
 
3
3
  module SmartProxyDynflowCore
4
- class Log < ::Logger
5
- alias_method :write, :debug
4
+ class ReopenAppender < ::Logging::Appender
5
+ def initialize(name, logger, opts = {})
6
+ @reopen = false
7
+ @logger = logger
8
+ super(name, opts)
9
+ end
6
10
 
7
- class << self
8
- def instance
9
- if @logger.nil?
10
- @logger = self.new log_file
11
- @logger.level = log_level
12
- end
13
- @logger
14
- end
11
+ def set(status = true)
12
+ @reopen = status
13
+ end
15
14
 
16
- def instance=(logger)
17
- @logger = logger
15
+ def append(_event)
16
+ if @reopen
17
+ Logging.reopen
18
+ @reopen = false
18
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
19
33
 
34
+ class << self
20
35
  def reload!
36
+ Logging.logger[LOGGER_NAME].appenders.each(&:close)
37
+ Logging.logger[LOGGER_NAME].clear_appenders
21
38
  @logger = nil
22
39
  instance
23
40
  end
24
41
 
25
- def log_level
26
- if Settings.instance.loaded && Settings.instance.log_level
27
- ::Logger.const_get(Settings.instance.log_level.upcase)
28
- else
29
- Logger::WARN
42
+ def reopen
43
+ return if @logger.nil? || @reopen.nil?
44
+ if Settings.instance.log_file !~ /^(STDOUT|SYSLOG|JOURNALD?)$/i
45
+ @reopen.set
30
46
  end
31
47
  end
32
48
 
33
- def log_file
34
- if Settings.instance.loaded && Settings.instance.log_file
35
- Settings.instance.log_file
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
36
73
  else
37
- $stdout
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
38
87
  end
88
+ @logger.level = ::Logging.level_num(Settings.instance.log_level)
89
+ @logger
39
90
  end
40
- end
41
91
 
42
- def initialize(file, *rest)
43
- @file = file
44
- @fd = @file.is_a?(IO) ? @file : File.open(@file, 'a')
45
- @fd.sync = true
46
- super(@fd, rest)
47
- end
92
+ def with_fields(fields = {})
93
+ ::Logging.ndc.push(fields) do
94
+ yield
95
+ end
96
+ end
48
97
 
49
- def roll_log
50
- unless @file.is_a? IO
51
- @fd.reopen @file, 'a'
52
- @fd.sync = true
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
53
118
  end
54
119
  end
55
120
 
56
121
  class ProxyStructuredFormater < ::Dynflow::LoggerAdapters::Formatters::Abstract
57
- def call(_severity, _datetime, _prog_name, message)
58
- if message.is_a?(::Exception)
122
+ def format(message)
123
+ if message.is_a?(Exception)
59
124
  subject = "#{message.message} (#{message.class})"
60
125
  if @base.respond_to?(:exception)
61
126
  @base.exception("Error details", message)
@@ -64,22 +129,17 @@ module SmartProxyDynflowCore
64
129
  "#{subject}\n#{message.backtrace.join("\n")}"
65
130
  end
66
131
  else
67
- message
132
+ @original_formatter.call(severity, datetime, prog_name, message)
68
133
  end
69
134
  end
70
-
71
- def format(message)
72
- call(nil, nil, nil, message)
73
- end
74
135
  end
75
136
 
76
137
  class ProxyAdapter < ::Dynflow::LoggerAdapters::Simple
77
138
  def initialize(logger, level = Logger::DEBUG, _formatters = [])
78
139
  @logger = logger
79
140
  @logger.level = level
80
- @logger.formatter = ProxyStructuredFormater.new(@logger)
81
- @action_logger = apply_formatters(ProgNameWrapper.new(@logger, ' action'), [ProxyStructuredFormater])
82
- @dynflow_logger = apply_formatters(ProgNameWrapper.new(@logger, 'dynflow'), [ProxyStructuredFormater])
141
+ @action_logger = apply_formatters(ProgNameWrapper.new(@logger, ' action'), [])
142
+ @dynflow_logger = apply_formatters(ProgNameWrapper.new(@logger, 'dynflow'), [])
83
143
  end
84
144
  end
85
145
  end
@@ -0,0 +1,31 @@
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
@@ -0,0 +1,59 @@
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
@@ -0,0 +1,18 @@
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,22 +1,5 @@
1
1
  require 'ostruct'
2
2
 
3
- # Implement hash-like access for 1.9.3 and older
4
- if RUBY_VERSION.split('.').first.to_i < 2
5
- class OpenStruct
6
- def [](key)
7
- self.send key
8
- end
9
-
10
- def []=(key, value)
11
- self.send "#{key}=", value
12
- end
13
-
14
- def to_h
15
- marshal_dump
16
- end
17
- end
18
- end
19
-
20
3
  module SmartProxyDynflowCore
21
4
  class Settings < OpenStruct
22
5
  DEFAULT_SETTINGS = {
@@ -41,7 +24,12 @@ module SmartProxyDynflowCore
41
24
  :pid_file => '/var/run/foreman-proxy/smart_proxy_dynflow_core.pid',
42
25
  :daemonize => false,
43
26
  :execution_plan_cleaner_age => 60 * 60 * 24,
44
- :loaded => false
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'
45
33
  }.freeze
46
34
 
47
35
  PROXY_SETTINGS = %i[ssl_ca_file ssl_certificate ssl_private_key foreman_url
@@ -73,13 +61,7 @@ module SmartProxyDynflowCore
73
61
  end
74
62
 
75
63
  def self.load_from_proxy(plugin)
76
- plugin_class = if Proxy::VERSION >= '1.16.0'
77
- plugin
78
- else
79
- # DEPRECATION: Remove this branch when dropping support for smart-proxy < 1.16
80
- plugin[:class]
81
- end
82
- settings = plugin_class.settings.to_h
64
+ settings = plugin.settings.to_h
83
65
  PROXY_SETTINGS.each do |key|
84
66
  SETTINGS[key] = Proxy::SETTINGS[key]
85
67
  end
@@ -94,7 +76,7 @@ module SmartProxyDynflowCore
94
76
  settings = YAML.load_file(path)
95
77
  name = File.basename(path).gsub(/\.yml$/, '')
96
78
  if SETTINGS.plugins.key? name
97
- settings = SETTINGS.plugins[name].to_h.merge(settings)
79
+ settings = SETTINGS.plugins[name].to_h.merge(settings || {})
98
80
  end
99
81
  SETTINGS.plugins[name] = OpenStruct.new settings
100
82
  end
@@ -1,3 +1,3 @@
1
1
  module SmartProxyDynflowCore
2
- VERSION = '0.2.5'.freeze
2
+ VERSION = '0.3.3'.freeze
3
3
  end
@@ -2,7 +2,6 @@ lib = File.expand_path('../lib', __FILE__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
  require 'smart_proxy_dynflow_core/version'
4
4
 
5
- # rubocop:disable Metrics/BlockLength
6
5
  Gem::Specification.new do |gem|
7
6
  gem.name = "smart_proxy_dynflow_core"
8
7
  gem.version = SmartProxyDynflowCore::VERSION
@@ -16,12 +15,14 @@ Gem::Specification.new do |gem|
16
15
 
17
16
  gem.executables = ['smart_proxy_dynflow_core']
18
17
  gem.files = Dir['lib/smart_proxy_dynflow_core.rb', 'config/settings.yml.example',
19
- 'lib/smart_proxy_dynflow_core/*', 'LICENSE', 'Gemfile',
18
+ 'lib/smart_proxy_dynflow_core/**/*', 'LICENSE', 'Gemfile',
20
19
  'bin/smart_proxy_dynflow_core', 'deploy/*', 'smart_proxy_dynflow_core.gemspec']
21
20
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
22
21
  gem.require_paths = ["lib"]
23
22
  gem.license = 'GPL-3.0'
24
23
 
24
+ gem.required_ruby_version = '~> 2.5'
25
+
25
26
  gem.add_development_dependency "bundler", ">= 1.7"
26
27
  gem.add_development_dependency('minitest')
27
28
  gem.add_development_dependency('mocha', '~> 1')
@@ -31,10 +32,11 @@ Gem::Specification.new do |gem|
31
32
 
32
33
  gem.add_runtime_dependency('dynflow', "~> 1.1")
33
34
  gem.add_runtime_dependency('foreman-tasks-core', '>= 0.3.3')
35
+ gem.add_runtime_dependency('logging')
34
36
  gem.add_runtime_dependency('rack')
35
37
  gem.add_runtime_dependency('rest-client')
38
+ gem.add_runtime_dependency('sd_notify', '~> 0.1')
36
39
  gem.add_runtime_dependency('sequel')
37
40
  gem.add_runtime_dependency('sinatra')
38
41
  gem.add_runtime_dependency('sqlite3')
39
42
  end
40
- # rubocop:enable Metrics/BlockLength
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.2.5
4
+ version: 0.3.3
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: 2020-05-06 00:00:00.000000000 Z
11
+ date: 2021-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: 0.3.3
125
+ - !ruby/object:Gem::Dependency
126
+ name: logging
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: rack
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -150,6 +164,20 @@ dependencies:
150
164
  - - ">="
151
165
  - !ruby/object:Gem::Version
152
166
  version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: sd_notify
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '0.1'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '0.1'
153
181
  - !ruby/object:Gem::Dependency
154
182
  name: sequel
155
183
  requirement: !ruby/object:Gem::Requirement
@@ -214,6 +242,9 @@ files:
214
242
  - lib/smart_proxy_dynflow_core/helpers.rb
215
243
  - lib/smart_proxy_dynflow_core/launcher.rb
216
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
217
248
  - lib/smart_proxy_dynflow_core/settings.rb
218
249
  - lib/smart_proxy_dynflow_core/task_launcher_registry.rb
219
250
  - lib/smart_proxy_dynflow_core/testing.rb
@@ -223,23 +254,23 @@ homepage: https://github.com/theforeman/smart_proxy_dynflow
223
254
  licenses:
224
255
  - GPL-3.0
225
256
  metadata: {}
226
- post_install_message:
257
+ post_install_message:
227
258
  rdoc_options: []
228
259
  require_paths:
229
260
  - lib
230
261
  required_ruby_version: !ruby/object:Gem::Requirement
231
262
  requirements:
232
- - - ">="
263
+ - - "~>"
233
264
  - !ruby/object:Gem::Version
234
- version: '0'
265
+ version: '2.5'
235
266
  required_rubygems_version: !ruby/object:Gem::Requirement
236
267
  requirements:
237
268
  - - ">="
238
269
  - !ruby/object:Gem::Version
239
270
  version: '0'
240
271
  requirements: []
241
- rubygems_version: 3.0.3
242
- signing_key:
272
+ rubygems_version: 3.1.2
273
+ signing_key:
243
274
  specification_version: 4
244
275
  summary: Dynflow runtime for Foreman smart proxy
245
276
  test_files: []