smart_proxy_dynflow_core 0.2.2 → 0.3.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
- 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