smart_proxy_dynflow_core 0.2.2 → 0.3.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
- SHA1:
3
- metadata.gz: c2aa6a1c4c6ccf4382d03834690a695627f66d10
4
- data.tar.gz: 6aedf16460fbc6924fac95e1dd4be0ead1b4fc37
2
+ SHA256:
3
+ metadata.gz: 467f03a2c2c0ad4e3b168039abdb8e9a465a46b8ecf44aade57c5a09bbeafbfc
4
+ data.tar.gz: e966e14e4a95f42af61b5bcf47595ad6afa241271656b6724e5000b3e2cd354d
5
5
  SHA512:
6
- metadata.gz: 5aac4b464edb1a3171bb52a6599823e336f532d0dec0dff6a9ffda3343bfea7900ae23e45eba36070f16a34f8fbffd6be97fd53e7af1c81a360a3bcc50a23714
7
- data.tar.gz: fcee792dcf9c2494a1437799f4c57bf67cbe5dd6de6debb41ce406edc48cff00948158fe74d70fb180f72c0ae2e08476512f82a38461d303cac1bea1b54a7c7b
6
+ metadata.gz: e6a3b2b7b4dc313c1b6cc215c2de6cda4f49ad9f901bc7ab949b0ed4a16521e021b9c39a0fc371091e54172610787f968a2bb8577f68086ef15308bd805fc970
7
+ data.tar.gz: 7cbfc949016d5d824ebbb421093c8ef687c24d33c6699e7ef0c875145e035e8233317ff64c7757597bd0e76c9186566dec4e407397e32803b6d42ea26602fb6f
data/Gemfile CHANGED
@@ -10,29 +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
- gem 'rubocop', '< 0.51.0'
17
- else
18
- gem 'public_suffix'
19
- gem 'rubocop', '~> 0.52.1'
20
- end
21
-
22
- if RUBY_VERSION < '2.2'
23
- gem 'rack-test', '< 0.8'
24
- else
25
- gem 'rack-test'
26
- end
13
+ gem 'public_suffix'
14
+ gem 'rack-test'
15
+ gem 'rubocop', '~> 0.52.1'
27
16
  end
28
17
 
29
- if RUBY_VERSION < '2.2'
30
- gem 'rack', '>= 1.1', '< 2.0.0'
31
- gem 'sinatra', '< 2'
32
- else
33
- gem 'rack', '>= 1.1'
34
- gem 'sinatra'
35
- end
18
+ gem 'logging-journald', '~> 2.0', :platforms => [:ruby]
19
+ gem 'rack', '>= 1.1'
20
+ gem 'sinatra'
36
21
 
37
22
  # load bundler.d
38
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,4 +1,7 @@
1
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'
2
5
  require 'smart_proxy_dynflow_core/task_launcher_registry'
3
6
  require 'foreman_tasks_core'
4
7
  require 'smart_proxy_dynflow_core/log'
@@ -3,10 +3,25 @@ require 'multi_json'
3
3
 
4
4
  module SmartProxyDynflowCore
5
5
  class Api < ::Sinatra::Base
6
+ TASK_UPDATE_REGEXP_PATH = %r{/tasks/(\S+)/(update|done)}
6
7
  helpers Helpers
7
8
 
9
+ configure do
10
+ if Settings.instance.standalone
11
+ ::Sinatra::Base.set :logging, false
12
+ ::Sinatra::Base.use ::SmartProxyDynflowCore::RequestIdMiddleware
13
+ ::Sinatra::Base.use ::SmartProxyDynflowCore::LoggerMiddleware
14
+ end
15
+ end
16
+
8
17
  before do
9
- authorize_with_token || authorize_with_ssl_client
18
+ if match = request.path_info.match(TASK_UPDATE_REGEXP_PATH)
19
+ task_id = match[1]
20
+ action = match[2]
21
+ authorize_with_token(task_id: task_id, clear: action == 'done')
22
+ else
23
+ authorize_with_ssl_client
24
+ end
10
25
  content_type :json
11
26
  end
12
27
 
@@ -45,9 +60,10 @@ module SmartProxyDynflowCore
45
60
  tasks_count(params['state']).to_json
46
61
  end
47
62
 
48
- post "/tasks/:task_id/done" do |task_id|
63
+ # capturing post "/tasks/:task_id/(update|done)"
64
+ post TASK_UPDATE_REGEXP_PATH do |task_id, _action|
49
65
  data = MultiJson.load(request.body.read)
50
- complete_task(task_id, data)
66
+ dispatch_external_event(task_id, data)
51
67
  end
52
68
 
53
69
  get "/tasks/operations" do
@@ -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
@@ -4,13 +4,14 @@ module SmartProxyDynflowCore
4
4
  SmartProxyDynflowCore::Core.world
5
5
  end
6
6
 
7
- def authorize_with_token
7
+ def authorize_with_token(task_id:, clear: true)
8
8
  if request.env.key? 'HTTP_AUTHORIZATION'
9
9
  if defined?(::ForemanTasksCore)
10
10
  auth = request.env['HTTP_AUTHORIZATION']
11
11
  basic_prefix = /\ABasic /
12
12
  if !auth.to_s.empty? && auth =~ basic_prefix &&
13
- ForemanTasksCore::OtpManager.authenticate(auth.gsub(basic_prefix, ''))
13
+ ForemanTasksCore::OtpManager.authenticate(auth.gsub(basic_prefix, ''),
14
+ expected_user: task_id, clear: clear)
14
15
  Log.instance.debug('authorized with token')
15
16
  return true
16
17
  end
@@ -63,7 +64,7 @@ module SmartProxyDynflowCore
63
64
  { :count => tasks.count, :state => state }
64
65
  end
65
66
 
66
- def complete_task(task_id, params)
67
+ def dispatch_external_event(task_id, params)
67
68
  world.event(task_id,
68
69
  params['step_id'].to_i,
69
70
  ::ForemanTasksCore::Runner::ExternalEvent.new(params))
@@ -1,20 +1,28 @@
1
1
  require 'webrick/https'
2
2
  require 'smart_proxy_dynflow_core/bundler_helper'
3
3
  require 'smart_proxy_dynflow_core/settings'
4
- require 'smart_proxy_dynflow_core/webrick-patch'
4
+ require 'sd_notify'
5
+
5
6
  module SmartProxyDynflowCore
6
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
+
7
12
  def self.launch!(options)
8
13
  self.new.start options
9
14
  end
10
15
 
11
16
  def start(options)
12
- load_settings!(options)
13
17
  Settings.instance.standalone = true
18
+ load_settings!(options)
14
19
  install_usr1_trap
15
20
  Rack::Server.new(rack_settings).start do |_server|
16
21
  SmartProxyDynflowCore::Core.ensure_initialized
22
+ ::SdNotify.ready
17
23
  end
24
+ Log.instance.info "Finished shutting down"
25
+ Logging.shutdown
18
26
  end
19
27
 
20
28
  def load_settings!(options = {})
@@ -47,7 +55,7 @@ module SmartProxyDynflowCore
47
55
 
48
56
  def install_usr1_trap
49
57
  trap(:USR1) do
50
- Log.instance.roll_log
58
+ Log.reopen
51
59
  end
52
60
  end
53
61
 
@@ -75,15 +83,14 @@ module SmartProxyDynflowCore
75
83
  :app => app,
76
84
  :Host => Settings.instance.listen,
77
85
  :Port => Settings.instance.port,
78
- :AccessLog => [[Log.instance, WEBrick::AccessLog::COMMON_LOG_FORMAT]],
86
+ :AccessLog => [],
79
87
  :Logger => Log.instance,
80
88
  :daemonize => Settings.instance.daemonize,
81
- :pid => Settings.instance.pid_file,
89
+ :pid => Settings.instance.daemonize && Settings.instance.pid_file,
82
90
  :server => :webrick
83
91
  }
84
92
  end
85
93
 
86
- # rubocop:disable Metrics/PerceivedComplexity
87
94
  def https_app
88
95
  ssl_options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
89
96
  ssl_options |= OpenSSL::SSL::OP_CIPHER_SERVER_PREFERENCE if defined?(OpenSSL::SSL::OP_CIPHER_SERVER_PREFERENCE)
@@ -91,17 +98,16 @@ module SmartProxyDynflowCore
91
98
  ssl_options |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2)
92
99
  ssl_options |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3)
93
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)
94
102
 
95
- if Settings.instance.tls_disabled_versions
96
- Settings.instance.tls_disabled_versions.each do |version|
97
- 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
98
105
 
99
- if constant
100
- Log.instance.info "TLSv#{version} will be disabled."
101
- ssl_options |= constant
102
- else
103
- Log.instance.warn "TLSv#{version} was not found."
104
- 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."
105
111
  end
106
112
  end
107
113
 
@@ -111,6 +117,7 @@ module SmartProxyDynflowCore
111
117
  :SSLPrivateKey => ssl_private_key,
112
118
  :SSLCertificate => ssl_certificate,
113
119
  :SSLCACertificateFile => Settings.instance.ssl_ca_file,
120
+ :SSLCiphers => CIPHERS - SmartProxyDynflowCore::Settings.instance.ssl_disabled_ciphers,
114
121
  :SSLOptions => ssl_options
115
122
  }
116
123
  end
@@ -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 ::Exception === message
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
- def initialize(logger, level = Logger::DEBUG, formatters = [])
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,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
@@ -1,7 +1,6 @@
1
1
  module SmartProxyDynflowCore
2
2
  class TaskLauncherRegistry
3
3
  class << self
4
-
5
4
  def register(name, launcher)
6
5
  registry[name] = launcher
7
6
  end
@@ -1,3 +1,3 @@
1
1
  module SmartProxyDynflowCore
2
- VERSION = '0.2.2'.freeze
2
+ VERSION = '0.3.0'.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
@@ -22,20 +21,22 @@ Gem::Specification.new do |gem|
22
21
  gem.require_paths = ["lib"]
23
22
  gem.license = 'GPL-3.0'
24
23
 
25
- gem.add_development_dependency "bundler", "~> 1.7"
24
+ gem.required_ruby_version = '~> 2.5'
25
+
26
+ gem.add_development_dependency "bundler", ">= 1.7"
26
27
  gem.add_development_dependency('minitest')
27
28
  gem.add_development_dependency('mocha', '~> 1')
28
29
  gem.add_development_dependency('rack-test', '~> 0')
29
30
  gem.add_development_dependency "rake", "~> 10.0"
30
- gem.add_development_dependency('rubocop', '~> 0.52.1')
31
31
  gem.add_development_dependency('webmock', '~> 1')
32
32
 
33
33
  gem.add_runtime_dependency('dynflow', "~> 1.1")
34
- gem.add_runtime_dependency('foreman-tasks-core', '>= 0.1.7')
34
+ gem.add_runtime_dependency('foreman-tasks-core', '>= 0.3.3')
35
+ gem.add_runtime_dependency('logging')
35
36
  gem.add_runtime_dependency('rack')
36
37
  gem.add_runtime_dependency('rest-client')
38
+ gem.add_runtime_dependency('sd_notify', '~> 0.1')
37
39
  gem.add_runtime_dependency('sequel')
38
40
  gem.add_runtime_dependency('sinatra')
39
41
  gem.add_runtime_dependency('sqlite3')
40
42
  end
41
- # rubocop:enable Metrics/BlockLength
metadata CHANGED
@@ -1,27 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_proxy_dynflow_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Nečas
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-08 00:00:00.000000000 Z
11
+ date: 1980-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.7'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.7'
27
27
  - !ruby/object:Gem::Dependency
@@ -81,61 +81,61 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '10.0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rubocop
84
+ name: webmock
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 0.52.1
89
+ version: '1'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 0.52.1
96
+ version: '1'
97
97
  - !ruby/object:Gem::Dependency
98
- name: webmock
98
+ name: dynflow
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '1'
104
- type: :development
103
+ version: '1.1'
104
+ type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '1'
110
+ version: '1.1'
111
111
  - !ruby/object:Gem::Dependency
112
- name: dynflow
112
+ name: foreman-tasks-core
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - "~>"
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: '1.1'
117
+ version: 0.3.3
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - "~>"
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: '1.1'
124
+ version: 0.3.3
125
125
  - !ruby/object:Gem::Dependency
126
- name: foreman-tasks-core
126
+ name: logging
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - ">="
130
130
  - !ruby/object:Gem::Version
131
- version: 0.1.7
131
+ version: '0'
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
- version: 0.1.7
138
+ version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: rack
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
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'
167
181
  - !ruby/object:Gem::Dependency
168
182
  name: sequel
169
183
  requirement: !ruby/object:Gem::Requirement
@@ -228,34 +242,34 @@ files:
228
242
  - lib/smart_proxy_dynflow_core/helpers.rb
229
243
  - lib/smart_proxy_dynflow_core/launcher.rb
230
244
  - lib/smart_proxy_dynflow_core/log.rb
245
+ - lib/smart_proxy_dynflow_core/logger_middleware.rb
246
+ - lib/smart_proxy_dynflow_core/request_id_middleware.rb
231
247
  - lib/smart_proxy_dynflow_core/settings.rb
232
248
  - lib/smart_proxy_dynflow_core/task_launcher_registry.rb
233
249
  - lib/smart_proxy_dynflow_core/testing.rb
234
250
  - lib/smart_proxy_dynflow_core/version.rb
235
- - lib/smart_proxy_dynflow_core/webrick-patch.rb
236
251
  - smart_proxy_dynflow_core.gemspec
237
252
  homepage: https://github.com/theforeman/smart_proxy_dynflow
238
253
  licenses:
239
254
  - GPL-3.0
240
255
  metadata: {}
241
- post_install_message:
256
+ post_install_message:
242
257
  rdoc_options: []
243
258
  require_paths:
244
259
  - lib
245
260
  required_ruby_version: !ruby/object:Gem::Requirement
246
261
  requirements:
247
- - - ">="
262
+ - - "~>"
248
263
  - !ruby/object:Gem::Version
249
- version: '0'
264
+ version: '2.5'
250
265
  required_rubygems_version: !ruby/object:Gem::Requirement
251
266
  requirements:
252
267
  - - ">="
253
268
  - !ruby/object:Gem::Version
254
269
  version: '0'
255
270
  requirements: []
256
- rubyforge_project:
257
- rubygems_version: 2.6.12
258
- signing_key:
271
+ rubygems_version: 3.1.2
272
+ signing_key:
259
273
  specification_version: 4
260
274
  summary: Dynflow runtime for Foreman smart proxy
261
275
  test_files: []
@@ -1,39 +0,0 @@
1
- require 'webrick/https'
2
-
3
- CIPHERS = ['ECDHE-RSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES256-GCM-SHA384',
4
- 'ECDHE-RSA-AES128-CBC-SHA', 'ECDHE-RSA-AES256-CBC-SHA',
5
- 'AES128-GCM-SHA256', 'AES256-GCM-SHA384', 'AES128-SHA256',
6
- 'AES256-SHA256', 'AES128-SHA', 'AES256-SHA'].freeze
7
-
8
- module WEBrick
9
- class GenericServer
10
- # rubocop:disable Metrics/AbcSize
11
- def setup_ssl_context(config) # :nodoc:
12
- unless config[:SSLCertificate]
13
- cn = config[:SSLCertName]
14
- comment = config[:SSLCertComment]
15
- cert, key = Utils.create_self_signed_cert(1024, cn, comment)
16
- config[:SSLCertificate] = cert
17
- config[:SSLPrivateKey] = key
18
- end
19
- ctx = OpenSSL::SSL::SSLContext.new
20
- ctx.set_params
21
- ctx.ciphers = (CIPHERS - SmartProxyDynflowCore::Settings.instance.ssl_disabled_ciphers).join(':')
22
- ctx.key = config[:SSLPrivateKey]
23
- ctx.cert = config[:SSLCertificate]
24
- ctx.client_ca = config[:SSLClientCA]
25
- ctx.extra_chain_cert = config[:SSLExtraChainCert]
26
- ctx.ca_file = config[:SSLCACertificateFile]
27
- ctx.ca_path = config[:SSLCACertificatePath]
28
- ctx.cert_store = config[:SSLCertificateStore]
29
- ctx.tmp_dh_callback = config[:SSLTmpDhCallback]
30
- ctx.verify_mode = config[:SSLVerifyClient]
31
- ctx.verify_depth = config[:SSLVerifyDepth]
32
- ctx.verify_callback = config[:SSLVerifyCallback]
33
- ctx.timeout = config[:SSLTimeout]
34
- ctx.options |= config[:SSLOptions] unless config[:SSLOptions].nil?
35
- ctx
36
- end
37
- # rubocop:enable Metrics/AbcSize
38
- end
39
- end