smart_proxy_dynflow_core 0.2.1 → 0.2.6

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: '08a1626af21a13a55a6cd092d7aa9f8d65e21db8'
4
- data.tar.gz: 8ca74216c0cb587d61b7c0049454b9a1204fa8c0
2
+ SHA256:
3
+ metadata.gz: 84ea792e8e6d9f6ddcd145428485d5faadf92da27acd184fa42956fa4873e7fd
4
+ data.tar.gz: 07adc8b3c623462086d0797455afaf822e27212bcdcda345a950df7e49296814
5
5
  SHA512:
6
- metadata.gz: 72a360aa24771a1bc0fc6d01a6aac0aa92e526c127487b7ff33d0afc80d53b72d1a83f3f585e0fe507ba846a9c50d58840369d464b5e9913b709591c6651154f
7
- data.tar.gz: f67485e909fedc9b7651c46cf5a9d16ae521cc6cadb78688a4a38a570b0f6889d336d254030d065fdff6ee126514b760b9677da9f1eb6f317993e567ad70856c
6
+ metadata.gz: 989f9619b041039a3897de03cac1edc5ce1415a19792b3a5b2e907b174b97472b3a56f19cd5cab9977c26e5d5c83c38636afe8c49186dbd2bfce1c7e3dbfcc84
7
+ data.tar.gz: 7caa3ee4ddce3560970bd8f7a7b8e2b99dd96f1fae456e78475673ec98478e0c608e5feb29442b7046e4eed07e61f0d9a009dade6646e534f6ef6f033192f572
data/Gemfile CHANGED
@@ -7,16 +7,15 @@ group :development do
7
7
  end
8
8
 
9
9
  group :test do
10
- gem 'smart_proxy_dynflow', :path => '.'
11
10
  gem 'smart_proxy', :git => "https://github.com/theforeman/smart-proxy", :branch => "develop"
11
+ gem 'smart_proxy_dynflow', :path => '.'
12
12
 
13
13
  if RUBY_VERSION < '2.1'
14
14
  gem 'public_suffix', '< 3'
15
- gem 'rubocop', '< 0.51.0'
16
15
  gem 'rainbow', '< 3'
17
16
  else
18
- gem 'rubocop', '~> 0.52.1'
19
17
  gem 'public_suffix'
18
+ gem 'rubocop', '~> 0.52.1'
20
19
  end
21
20
 
22
21
  if RUBY_VERSION < '2.2'
@@ -27,11 +26,11 @@ group :test do
27
26
  end
28
27
 
29
28
  if RUBY_VERSION < '2.2'
30
- gem 'sinatra', '< 2'
31
29
  gem 'rack', '>= 1.1', '< 2.0.0'
30
+ gem 'sinatra', '< 2'
32
31
  else
33
- gem 'sinatra'
34
32
  gem 'rack', '>= 1.1'
33
+ gem 'sinatra'
35
34
  end
36
35
 
37
36
  # load bundler.d
@@ -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
+ raise LoadError, 'Ruby >= 2.1 is required' unless RUBY_VERSION >= '2.1'
2
+
1
3
  require 'dynflow'
4
+ require 'smart_proxy_dynflow_core/task_launcher_registry'
2
5
  require 'foreman_tasks_core'
3
6
  require 'smart_proxy_dynflow_core/log'
4
7
  require 'smart_proxy_dynflow_core/settings'
@@ -7,7 +10,9 @@ require 'smart_proxy_dynflow_core/helpers'
7
10
  require 'smart_proxy_dynflow_core/callback'
8
11
  require 'smart_proxy_dynflow_core/api'
9
12
 
10
- SmartProxyDynflowCore::Core.after_initialize do |dynflow_core|
11
- ForemanTasksCore.dynflow_setup(dynflow_core.world)
13
+ module SmartProxyDynflowCore
14
+ Core.after_initialize do |dynflow_core|
15
+ ForemanTasksCore.dynflow_setup(dynflow_core.world)
16
+ end
17
+ Core.register_silencer_matchers ForemanTasksCore.silent_dead_letter_matchers
12
18
  end
13
- SmartProxyDynflowCore::Core.register_silencer_matchers ForemanTasksCore.silent_dead_letter_matchers
@@ -3,11 +3,17 @@ 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
 
8
9
  before do
9
- logger = Log.instance
10
- authorize_with_token || authorize_with_ssl_client
10
+ if match = request.path_info.match(TASK_UPDATE_REGEXP_PATH)
11
+ task_id = match[1]
12
+ action = match[2]
13
+ authorize_with_token(task_id: task_id, clear: action == 'done')
14
+ else
15
+ authorize_with_ssl_client
16
+ end
11
17
  content_type :json
12
18
  end
13
19
 
@@ -21,6 +27,13 @@ module SmartProxyDynflowCore
21
27
  MultiJson.dump(result)
22
28
  end
23
29
 
30
+ post "/tasks/launch/?" do
31
+ params = MultiJson.load(request.body.read)
32
+ launcher = launcher_class(params).new(world, callback_host(params, request), params.fetch('options', {}))
33
+ launcher.launch!(params['input'])
34
+ launcher.results.to_json
35
+ end
36
+
24
37
  post "/tasks/?" do
25
38
  params = MultiJson.load(request.body.read)
26
39
  trigger_task(::Dynflow::Utils.constantize(params['action_name']),
@@ -39,15 +52,30 @@ module SmartProxyDynflowCore
39
52
  tasks_count(params['state']).to_json
40
53
  end
41
54
 
42
- post "/tasks/:task_id/done" do |task_id|
55
+ # capturing post "/tasks/:task_id/(update|done)"
56
+ post TASK_UPDATE_REGEXP_PATH do |task_id, _action|
43
57
  data = MultiJson.load(request.body.read)
44
- complete_task(task_id, data)
58
+ dispatch_external_event(task_id, data)
59
+ end
60
+
61
+ get "/tasks/operations" do
62
+ TaskLauncherRegistry.operations.to_json
45
63
  end
46
64
 
47
65
  private
48
66
 
49
67
  def callback_host(params, request)
50
- params.fetch('action_input', {})['proxy_url'] || request.env.values_at('HTTP_X_FORWARDED_FOR', 'HTTP_HOST').compact.first
68
+ params.fetch('action_input', {})['proxy_url'] ||
69
+ request.env.values_at('HTTP_X_FORWARDED_FOR', 'HTTP_HOST').compact.first
70
+ end
71
+
72
+ def launcher_class(params)
73
+ operation = params.fetch('operation')
74
+ if TaskLauncherRegistry.key?(operation)
75
+ TaskLauncherRegistry.fetch(operation)
76
+ else
77
+ halt 404, MultiJson.dump(:error => "Unknown operation '#{operation}' requested.")
78
+ end
51
79
  end
52
80
  end
53
81
  end
@@ -1,5 +1,6 @@
1
1
  module SmartProxyDynflowCore
2
2
  class BundlerHelper
3
+ # rubocop:disable Metrics/PerceivedComplexity
3
4
  def self.require_groups(*groups)
4
5
  if File.exist?(File.expand_path('../../../Gemfile.in', __FILE__))
5
6
  # If there is a Gemfile.in file, we will not use Bundler but BundlerExt
@@ -25,5 +26,6 @@ module SmartProxyDynflowCore
25
26
  Bundler.require(*groups)
26
27
  end
27
28
  end
29
+ # rubocop:enable Metrics/PerceivedComplexity
28
30
  end
29
31
  end
@@ -1,23 +1,52 @@
1
1
  require 'rest-client'
2
2
 
3
+ # rubocop:disable Lint/HandleExceptions
3
4
  begin
4
5
  require 'smart_proxy_dynflow/callback'
5
6
  rescue LoadError
6
7
  end
8
+ # rubocop:enable Lint/HandleExceptions
7
9
 
8
10
  module SmartProxyDynflowCore
9
11
  module Callback
10
- class Action < Dynflow::Action
11
- def plan(callback, data)
12
- plan_self(:callback => callback, :data => data)
13
- end
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
14
17
 
15
- def run
16
- Request.send_to_foreman_tasks(input[:callback], input[:data])
18
+ # rubocop:disable Metrics/PerceivedComplexity
19
+ def ssl_options
20
+ return @ssl_options if defined? @ssl_options
21
+ @ssl_options = {}
22
+ settings = Settings.instance
23
+ return @ssl_options unless URI.parse(settings.foreman_url).scheme == 'https'
24
+
25
+ @ssl_options[:verify_ssl] = OpenSSL::SSL::VERIFY_PEER
26
+
27
+ private_key_file = settings.foreman_ssl_key || settings.ssl_private_key
28
+ if private_key_file
29
+ private_key = File.read(private_key_file)
30
+ @ssl_options[:ssl_client_key] = OpenSSL::PKey::RSA.new(private_key)
31
+ end
32
+ certificate_file = settings.foreman_ssl_cert || settings.ssl_certificate
33
+ if certificate_file
34
+ certificate = File.read(certificate_file)
35
+ @ssl_options[:ssl_client_cert] = OpenSSL::X509::Certificate.new(certificate)
36
+ end
37
+ ca_file = settings.foreman_ssl_ca || settings.ssl_ca_file
38
+ @ssl_options[:ssl_ca_file] = ca_file if ca_file
39
+ @ssl_options
40
+ end
41
+ # rubocop:enable Metrics/PerceivedComplexity
42
+
43
+ private
44
+
45
+ def prepare_payload(callback, data)
46
+ { :callback => callback, :data => data }.to_json
47
+ end
17
48
  end
18
- end
19
49
 
20
- class Request
21
50
  def callback(payload)
22
51
  response = callback_resource.post(payload, :content_type => :json)
23
52
  if response.code.to_s != "200"
@@ -26,43 +55,12 @@ module SmartProxyDynflowCore
26
55
  response
27
56
  end
28
57
 
29
- def self.send_to_foreman_tasks(callback_info, data)
30
- self.new.callback(self.prepare_payload(callback_info, data))
31
- end
32
-
33
58
  private
34
59
 
35
- def self.prepare_payload(callback, data)
36
- { :callback => callback, :data => data }.to_json
37
- end
38
-
39
60
  def callback_resource
40
61
  @resource ||= RestClient::Resource.new(Settings.instance.foreman_url + '/foreman_tasks/api/tasks/callback',
41
62
  self.class.ssl_options)
42
63
  end
43
-
44
- def self.ssl_options
45
- return @ssl_options if defined? @ssl_options
46
- @ssl_options = {}
47
- settings = Settings.instance
48
- return @ssl_options unless URI.parse(settings.foreman_url).scheme == 'https'
49
-
50
- @ssl_options[:verify_ssl] = OpenSSL::SSL::VERIFY_PEER
51
-
52
- private_key_file = settings.foreman_ssl_key || settings.ssl_private_key
53
- if private_key_file
54
- private_key = File.read(private_key_file)
55
- @ssl_options[:ssl_client_key] = OpenSSL::PKey::RSA.new(private_key)
56
- end
57
- certificate_file = settings.foreman_ssl_cert || settings.ssl_certificate
58
- if certificate_file
59
- certificate = File.read(certificate_file)
60
- @ssl_options[:ssl_client_cert] = OpenSSL::X509::Certificate.new(certificate)
61
- end
62
- ca_file = settings.foreman_ssl_ca || settings.ssl_ca_file
63
- @ssl_options[:ssl_ca_file] = ca_file if ca_file
64
- @ssl_options
65
- end
66
64
  end
67
65
 
68
66
  class Action < ::Dynflow::Action
@@ -1,6 +1,5 @@
1
1
  module SmartProxyDynflowCore
2
2
  class Core
3
-
4
3
  attr_accessor :world, :accepted_cert_serial
5
4
 
6
5
  def initialize
@@ -25,7 +24,8 @@ module SmartProxyDynflowCore
25
24
 
26
25
  db_file = Settings.instance.database
27
26
  if db_file.nil? || db_file.empty?
28
- Log.instance.warn "Could not open DB for dynflow at '#{db_file}', will keep data in memory. Restart will drop all dynflow data."
27
+ Log.instance.warn "Could not open DB for dynflow at '#{db_file}', " \
28
+ "will keep data in memory. Restart will drop all dynflow data."
29
29
  else
30
30
  db_conn_string += "/#{db_file}"
31
31
  end
@@ -44,7 +44,7 @@ module SmartProxyDynflowCore
44
44
  config.persistence_adapter = persistence_adapter
45
45
  config.execution_plan_cleaner = execution_plan_cleaner
46
46
  # TODO: There has to be a better way
47
- matchers = config.silent_dead_letter_matchers.call().concat(self.class.silencer_matchers)
47
+ matchers = config.silent_dead_letter_matchers.call.concat(self.class.silencer_matchers)
48
48
  config.silent_dead_letter_matchers = matchers
49
49
  yield config if block_given?
50
50
  end
@@ -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
@@ -21,7 +22,7 @@ module SmartProxyDynflowCore
21
22
  end
22
23
 
23
24
  def authorize_with_ssl_client
24
- if %w(yes on 1).include? request.env['HTTPS'].to_s
25
+ if %w[yes on 1].include? request.env['HTTPS'].to_s
25
26
  if request.env['SSL_CLIENT_CERT'].to_s.empty?
26
27
  Log.instance.error "No client SSL certificate supplied"
27
28
  halt 403, MultiJson.dump(:error => "No client SSL certificate supplied")
@@ -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,9 +1,13 @@
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 'smart_proxy_dynflow_core/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
7
11
 
8
12
  def self.launch!(options)
9
13
  self.new.start options
@@ -15,6 +19,7 @@ module SmartProxyDynflowCore
15
19
  install_usr1_trap
16
20
  Rack::Server.new(rack_settings).start do |_server|
17
21
  SmartProxyDynflowCore::Core.ensure_initialized
22
+ SmartProxyDynflowCore::SdNotify.new.tap { |sd| sd.ready if sd.active? }
18
23
  end
19
24
  end
20
25
 
@@ -79,11 +84,12 @@ module SmartProxyDynflowCore
79
84
  :AccessLog => [[Log.instance, WEBrick::AccessLog::COMMON_LOG_FORMAT]],
80
85
  :Logger => Log.instance,
81
86
  :daemonize => Settings.instance.daemonize,
82
- :pid => Settings.instance.pid_file,
87
+ :pid => Settings.instance.daemonize && Settings.instance.pid_file,
83
88
  :server => :webrick
84
89
  }
85
90
  end
86
91
 
92
+ # rubocop:disable Metrics/PerceivedComplexity
87
93
  def https_app
88
94
  ssl_options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
89
95
  ssl_options |= OpenSSL::SSL::OP_CIPHER_SERVER_PREFERENCE if defined?(OpenSSL::SSL::OP_CIPHER_SERVER_PREFERENCE)
@@ -91,10 +97,11 @@ module SmartProxyDynflowCore
91
97
  ssl_options |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2)
92
98
  ssl_options |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3)
93
99
  ssl_options |= OpenSSL::SSL::OP_NO_TLSv1 if defined?(OpenSSL::SSL::OP_NO_TLSv1)
100
+ ssl_options |= OpenSSL::SSL::OP_NO_TLSv1_1 if defined?(OpenSSL::SSL::OP_NO_TLSv1_1)
94
101
 
95
102
  if Settings.instance.tls_disabled_versions
96
103
  Settings.instance.tls_disabled_versions.each do |version|
97
- constant = OpenSSL::SSL.const_get("OP_NO_TLSv#{version.to_s.gsub(/\./, '_')}") rescue nil
104
+ constant = OpenSSL::SSL.const_get("OP_NO_TLSv#{version.to_s.tr('.', '_')}") rescue nil
98
105
 
99
106
  if constant
100
107
  Log.instance.info "TLSv#{version} will be disabled."
@@ -111,9 +118,11 @@ module SmartProxyDynflowCore
111
118
  :SSLPrivateKey => ssl_private_key,
112
119
  :SSLCertificate => ssl_certificate,
113
120
  :SSLCACertificateFile => Settings.instance.ssl_ca_file,
121
+ :SSLCiphers => CIPHERS - SmartProxyDynflowCore::Settings.instance.ssl_disabled_ciphers,
114
122
  :SSLOptions => ssl_options
115
123
  }
116
124
  end
125
+ # rubocop:enable Metrics/PerceivedComplexity
117
126
 
118
127
  def https_enabled?
119
128
  Settings.instance.use_https
@@ -122,14 +131,16 @@ module SmartProxyDynflowCore
122
131
  def ssl_private_key
123
132
  OpenSSL::PKey::RSA.new(File.read(Settings.instance.ssl_private_key))
124
133
  rescue Exception => e
125
- Log.instance.fatal "Unable to load private SSL key. Are the values correct in settings.yml and do permissions allow reading?: #{e}"
134
+ Log.instance.fatal "Unable to load private SSL key. Are the values "\
135
+ "correct in settings.yml and do permissions allow reading?: #{e}"
126
136
  raise e
127
137
  end
128
138
 
129
139
  def ssl_certificate
130
140
  OpenSSL::X509::Certificate.new(File.read(Settings.instance.ssl_certificate))
131
141
  rescue Exception => e
132
- Log.instance.fatal "Unable to load SSL certificate. Are the values correct in settings.yml and do permissions allow reading?: #{e}"
142
+ Log.instance.fatal "Unable to load SSL certificate. Are the values " \
143
+ "correct in settings.yml and do permissions allow reading?: #{e}"
133
144
  raise e
134
145
  end
135
146
 
@@ -141,7 +152,7 @@ module SmartProxyDynflowCore
141
152
  Dir[File.join(dir, 'settings.d', '*.yml')].each { |path| Settings.load_plugin_settings(path) }
142
153
  true
143
154
  end
144
- ForemanTasksCore::SettingsLoader.settings_registry.keys.each do |settings_keys|
155
+ ForemanTasksCore::SettingsLoader.settings_registry.each_key do |settings_keys|
145
156
  settings = settings_keys.inject({}) do |h, settings_key|
146
157
  if SETTINGS.plugins.key?(settings_key.to_s)
147
158
  h.merge(SETTINGS.plugins[settings_key.to_s].to_h)
@@ -2,7 +2,6 @@ require 'logger'
2
2
 
3
3
  module SmartProxyDynflowCore
4
4
  class Log < ::Logger
5
-
6
5
  alias_method :write, :debug
7
6
 
8
7
  class << self
@@ -42,25 +41,45 @@ module SmartProxyDynflowCore
42
41
 
43
42
  def initialize(file, *rest)
44
43
  @file = file
45
- @fd = @file.kind_of?(IO) ? @file : File.open(@file, 'a')
44
+ @fd = @file.is_a?(IO) ? @file : File.open(@file, 'a')
46
45
  @fd.sync = true
47
46
  super(@fd, rest)
48
47
  end
49
48
 
50
49
  def roll_log
51
- unless @file.kind_of? IO
50
+ unless @file.is_a? IO
52
51
  @fd.reopen @file, 'a'
53
52
  @fd.sync = true
54
53
  end
55
54
  end
56
55
 
56
+ class ProxyStructuredFormater < ::Dynflow::LoggerAdapters::Formatters::Abstract
57
+ def call(_severity, _datetime, _prog_name, message)
58
+ if message.is_a?(::Exception)
59
+ subject = "#{message.message} (#{message.class})"
60
+ if @base.respond_to?(:exception)
61
+ @base.exception("Error details", message)
62
+ subject
63
+ else
64
+ "#{subject}\n#{message.backtrace.join("\n")}"
65
+ end
66
+ else
67
+ message
68
+ end
69
+ end
70
+
71
+ def format(message)
72
+ call(nil, nil, nil, message)
73
+ end
74
+ end
75
+
57
76
  class ProxyAdapter < ::Dynflow::LoggerAdapters::Simple
58
- def initialize(logger, level = Logger::DEBUG, formatters = [::Dynflow::LoggerAdapters::Formatters::Exception])
77
+ def initialize(logger, level = Logger::DEBUG, _formatters = [])
59
78
  @logger = logger
60
79
  @logger.level = level
61
- @logger.formatter = method(:formatter).to_proc
62
- @action_logger = apply_formatters ProgNameWrapper.new(@logger, ' action'), formatters
63
- @dynflow_logger = apply_formatters ProgNameWrapper.new(@logger, 'dynflow'), formatters
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])
64
83
  end
65
84
  end
66
85
  end
@@ -0,0 +1,33 @@
1
+ # Shamelessly taken from theforeman/smart-proxy @ 99e9e5b
2
+ # kudos to domcleal
3
+
4
+ require 'socket'
5
+
6
+ # Implementation of libsystemd's sd_notify API, sends current state via socket
7
+ module SmartProxyDynflowCore
8
+ class SdNotify
9
+ def active?
10
+ !ENV['NOTIFY_SOCKET'].nil?
11
+ end
12
+
13
+ def notify(message)
14
+ create_socket.tap do |socket|
15
+ socket.sendmsg(message.chomp + "\n") # ensure trailing \n
16
+ socket.close
17
+ end
18
+ end
19
+
20
+ def ready(state = 1)
21
+ notify("READY=#{state}")
22
+ end
23
+
24
+ private
25
+
26
+ def create_socket
27
+ raise 'Missing NOTIFY_SOCKET environment variable, is this process running under systemd?' unless active?
28
+ Socket.new(Socket::AF_UNIX, Socket::SOCK_DGRAM, 0).tap do |socket|
29
+ socket.connect(Socket.pack_sockaddr_un(ENV['NOTIFY_SOCKET']))
30
+ end
31
+ end
32
+ end
33
+ end
@@ -19,37 +19,36 @@ end
19
19
 
20
20
  module SmartProxyDynflowCore
21
21
  class Settings < OpenStruct
22
-
23
22
  DEFAULT_SETTINGS = {
24
- :database => '/var/lib/foreman-proxy/dynflow/dynflow.sqlite',
25
- :foreman_url => 'https://127.0.0.1:3000',
26
- :console_auth => true,
27
- :listen => '127.0.0.1',
28
- :port => '8008',
29
- :use_https => false,
30
- :ssl_ca_file => nil,
31
- :ssl_private_key => nil,
32
- :ssl_certificate => nil,
33
- :ssl_disabled_ciphers => [],
34
- :tls_disabled_versions => [],
35
- :foreman_ssl_ca => nil,
36
- :foreman_ssl_key => nil,
37
- :foreman_ssl_cert => nil,
38
- :standalone => false,
39
- :log_file => '/var/log/foreman-proxy/smart_proxy_dynflow_core.log',
40
- :log_level => :ERROR,
41
- :plugins => {},
42
- :pid_file => '/var/run/foreman-proxy/smart_proxy_dynflow_core.pid',
43
- :daemonize => false,
44
- :execution_plan_cleaner_age => 60 * 60 * 24,
45
- :loaded => false
46
- }
23
+ :database => '/var/lib/foreman-proxy/dynflow/dynflow.sqlite',
24
+ :foreman_url => 'https://127.0.0.1:3000',
25
+ :console_auth => true,
26
+ :listen => '127.0.0.1',
27
+ :port => '8008',
28
+ :use_https => false,
29
+ :ssl_ca_file => nil,
30
+ :ssl_private_key => nil,
31
+ :ssl_certificate => nil,
32
+ :ssl_disabled_ciphers => [],
33
+ :tls_disabled_versions => [],
34
+ :foreman_ssl_ca => nil,
35
+ :foreman_ssl_key => nil,
36
+ :foreman_ssl_cert => nil,
37
+ :standalone => false,
38
+ :log_file => '/var/log/foreman-proxy/smart_proxy_dynflow_core.log',
39
+ :log_level => :ERROR,
40
+ :plugins => {},
41
+ :pid_file => '/var/run/foreman-proxy/smart_proxy_dynflow_core.pid',
42
+ :daemonize => false,
43
+ :execution_plan_cleaner_age => 60 * 60 * 24,
44
+ :loaded => false
45
+ }.freeze
47
46
 
48
- PROXY_SETTINGS = [:ssl_ca_file, :ssl_certificate, :ssl_private_key, :foreman_url,
49
- :foreman_ssl_ca, :foreman_ssl_cert, :foreman_ssl_key,
50
- :log_file, :log_level, :ssl_disabled_ciphers]
51
- PLUGIN_SETTINGS = [:database, :core_url, :console_auth,
52
- :execution_plan_cleaner_age]
47
+ PROXY_SETTINGS = %i[ssl_ca_file ssl_certificate ssl_private_key foreman_url
48
+ foreman_ssl_ca foreman_ssl_cert foreman_ssl_key
49
+ log_file log_level ssl_disabled_ciphers].freeze
50
+ PLUGIN_SETTINGS = %i[database core_url console_auth
51
+ execution_plan_cleaner_age].freeze
53
52
 
54
53
  def initialize(settings = {})
55
54
  super(DEFAULT_SETTINGS.merge(settings))
@@ -60,7 +59,7 @@ module SmartProxyDynflowCore
60
59
  end
61
60
 
62
61
  def self.load_global_settings(path)
63
- if File.exists? File.join(path)
62
+ if File.exist? File.join(path)
64
63
  YAML.load_file(path).each do |key, value|
65
64
  SETTINGS[key] = value
66
65
  end
@@ -87,7 +86,7 @@ module SmartProxyDynflowCore
87
86
  PLUGIN_SETTINGS.each do |key|
88
87
  SETTINGS[key] = settings[key] if settings.key?(key)
89
88
  end
90
- SETTINGS.plugins.values.each { |plugin| plugin.load_settings_from_proxy }
89
+ SETTINGS.plugins.values.each(&:load_settings_from_proxy)
91
90
  Settings.loaded!
92
91
  end
93
92
 
@@ -0,0 +1,31 @@
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
31
+ end
@@ -17,7 +17,7 @@ module SmartProxyDynflowCore
17
17
  config.auto_terminate = false
18
18
  config.logger_adapter = ::Dynflow::LoggerAdapters::Simple.new $stderr, DYNFLOW_TESTING_LOG_LEVEL
19
19
  config.execution_plan_cleaner = nil
20
- block.call(config) if block
20
+ yield(config) if block
21
21
  end
22
22
  end
23
23
  end
@@ -1,3 +1,3 @@
1
1
  module SmartProxyDynflowCore
2
- VERSION = '0.2.1'
2
+ VERSION = '0.2.6'.freeze
3
3
  end
@@ -1,8 +1,8 @@
1
- # -*- encoding: utf-8 -*-
2
1
  lib = File.expand_path('../lib', __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require 'smart_proxy_dynflow_core/version'
5
4
 
5
+ # rubocop:disable Metrics/BlockLength
6
6
  Gem::Specification.new do |gem|
7
7
  gem.name = "smart_proxy_dynflow_core"
8
8
  gem.version = SmartProxyDynflowCore::VERSION
@@ -22,19 +22,19 @@ Gem::Specification.new do |gem|
22
22
  gem.require_paths = ["lib"]
23
23
  gem.license = 'GPL-3.0'
24
24
 
25
- gem.add_development_dependency "bundler", "~> 1.7"
26
- gem.add_development_dependency "rake", "~> 10.0"
25
+ gem.add_development_dependency "bundler", ">= 1.7"
27
26
  gem.add_development_dependency('minitest')
28
27
  gem.add_development_dependency('mocha', '~> 1')
29
- gem.add_development_dependency('webmock', '~> 1')
30
28
  gem.add_development_dependency('rack-test', '~> 0')
31
- gem.add_development_dependency('rubocop', '~> 0.52.1')
29
+ gem.add_development_dependency "rake", "~> 10.0"
30
+ gem.add_development_dependency('webmock', '~> 1')
32
31
 
33
- gem.add_runtime_dependency('dynflow', "~> 1.0")
34
- gem.add_runtime_dependency('foreman-tasks-core', '>= 0.1.7')
35
- gem.add_runtime_dependency('sequel')
36
- gem.add_runtime_dependency('sqlite3')
37
- gem.add_runtime_dependency('sinatra')
32
+ gem.add_runtime_dependency('dynflow', "~> 1.1")
33
+ gem.add_runtime_dependency('foreman-tasks-core', '>= 0.3.3')
38
34
  gem.add_runtime_dependency('rack')
39
35
  gem.add_runtime_dependency('rest-client')
36
+ gem.add_runtime_dependency('sequel')
37
+ gem.add_runtime_dependency('sinatra')
38
+ gem.add_runtime_dependency('sqlite3')
40
39
  end
40
+ # rubocop:enable Metrics/BlockLength
metadata CHANGED
@@ -1,43 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_proxy_dynflow_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.6
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: 2018-09-20 00:00:00.000000000 Z
11
+ date: 2020-06-19 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
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '10.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '10.0'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: minitest
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -67,77 +53,77 @@ dependencies:
67
53
  - !ruby/object:Gem::Version
68
54
  version: '1'
69
55
  - !ruby/object:Gem::Dependency
70
- name: webmock
56
+ name: rack-test
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - "~>"
74
60
  - !ruby/object:Gem::Version
75
- version: '1'
61
+ version: '0'
76
62
  type: :development
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
66
  - - "~>"
81
67
  - !ruby/object:Gem::Version
82
- version: '1'
68
+ version: '0'
83
69
  - !ruby/object:Gem::Dependency
84
- name: rack-test
70
+ name: rake
85
71
  requirement: !ruby/object:Gem::Requirement
86
72
  requirements:
87
73
  - - "~>"
88
74
  - !ruby/object:Gem::Version
89
- version: '0'
75
+ version: '10.0'
90
76
  type: :development
91
77
  prerelease: false
92
78
  version_requirements: !ruby/object:Gem::Requirement
93
79
  requirements:
94
80
  - - "~>"
95
81
  - !ruby/object:Gem::Version
96
- version: '0'
82
+ version: '10.0'
97
83
  - !ruby/object:Gem::Dependency
98
- name: rubocop
84
+ name: webmock
99
85
  requirement: !ruby/object:Gem::Requirement
100
86
  requirements:
101
87
  - - "~>"
102
88
  - !ruby/object:Gem::Version
103
- version: 0.52.1
89
+ version: '1'
104
90
  type: :development
105
91
  prerelease: false
106
92
  version_requirements: !ruby/object:Gem::Requirement
107
93
  requirements:
108
94
  - - "~>"
109
95
  - !ruby/object:Gem::Version
110
- version: 0.52.1
96
+ version: '1'
111
97
  - !ruby/object:Gem::Dependency
112
98
  name: dynflow
113
99
  requirement: !ruby/object:Gem::Requirement
114
100
  requirements:
115
101
  - - "~>"
116
102
  - !ruby/object:Gem::Version
117
- version: '1.0'
103
+ version: '1.1'
118
104
  type: :runtime
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
107
  requirements:
122
108
  - - "~>"
123
109
  - !ruby/object:Gem::Version
124
- version: '1.0'
110
+ version: '1.1'
125
111
  - !ruby/object:Gem::Dependency
126
112
  name: foreman-tasks-core
127
113
  requirement: !ruby/object:Gem::Requirement
128
114
  requirements:
129
115
  - - ">="
130
116
  - !ruby/object:Gem::Version
131
- version: 0.1.7
117
+ version: 0.3.3
132
118
  type: :runtime
133
119
  prerelease: false
134
120
  version_requirements: !ruby/object:Gem::Requirement
135
121
  requirements:
136
122
  - - ">="
137
123
  - !ruby/object:Gem::Version
138
- version: 0.1.7
124
+ version: 0.3.3
139
125
  - !ruby/object:Gem::Dependency
140
- name: sequel
126
+ name: rack
141
127
  requirement: !ruby/object:Gem::Requirement
142
128
  requirements:
143
129
  - - ">="
@@ -151,7 +137,7 @@ dependencies:
151
137
  - !ruby/object:Gem::Version
152
138
  version: '0'
153
139
  - !ruby/object:Gem::Dependency
154
- name: sqlite3
140
+ name: rest-client
155
141
  requirement: !ruby/object:Gem::Requirement
156
142
  requirements:
157
143
  - - ">="
@@ -165,7 +151,7 @@ dependencies:
165
151
  - !ruby/object:Gem::Version
166
152
  version: '0'
167
153
  - !ruby/object:Gem::Dependency
168
- name: sinatra
154
+ name: sequel
169
155
  requirement: !ruby/object:Gem::Requirement
170
156
  requirements:
171
157
  - - ">="
@@ -179,7 +165,7 @@ dependencies:
179
165
  - !ruby/object:Gem::Version
180
166
  version: '0'
181
167
  - !ruby/object:Gem::Dependency
182
- name: rack
168
+ name: sinatra
183
169
  requirement: !ruby/object:Gem::Requirement
184
170
  requirements:
185
171
  - - ">="
@@ -193,7 +179,7 @@ dependencies:
193
179
  - !ruby/object:Gem::Version
194
180
  version: '0'
195
181
  - !ruby/object:Gem::Dependency
196
- name: rest-client
182
+ name: sqlite3
197
183
  requirement: !ruby/object:Gem::Requirement
198
184
  requirements:
199
185
  - - ">="
@@ -228,10 +214,11 @@ files:
228
214
  - lib/smart_proxy_dynflow_core/helpers.rb
229
215
  - lib/smart_proxy_dynflow_core/launcher.rb
230
216
  - lib/smart_proxy_dynflow_core/log.rb
217
+ - lib/smart_proxy_dynflow_core/sd_notify.rb
231
218
  - lib/smart_proxy_dynflow_core/settings.rb
219
+ - lib/smart_proxy_dynflow_core/task_launcher_registry.rb
232
220
  - lib/smart_proxy_dynflow_core/testing.rb
233
221
  - lib/smart_proxy_dynflow_core/version.rb
234
- - lib/smart_proxy_dynflow_core/webrick-patch.rb
235
222
  - smart_proxy_dynflow_core.gemspec
236
223
  homepage: https://github.com/theforeman/smart_proxy_dynflow
237
224
  licenses:
@@ -252,8 +239,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
252
239
  - !ruby/object:Gem::Version
253
240
  version: '0'
254
241
  requirements: []
255
- rubyforge_project:
256
- rubygems_version: 2.6.12
242
+ rubygems_version: 3.0.3
257
243
  signing_key:
258
244
  specification_version: 4
259
245
  summary: Dynflow runtime for Foreman smart proxy
@@ -1,37 +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']
7
-
8
- module WEBrick
9
- class GenericServer
10
- def setup_ssl_context(config) # :nodoc:
11
- unless config[:SSLCertificate]
12
- cn = config[:SSLCertName]
13
- comment = config[:SSLCertComment]
14
- cert, key = Utils::create_self_signed_cert(1024, cn, comment)
15
- config[:SSLCertificate] = cert
16
- config[:SSLPrivateKey] = key
17
- end
18
- ctx = OpenSSL::SSL::SSLContext.new
19
- ctx.set_params
20
- ctx.ciphers = (CIPHERS - SmartProxyDynflowCore::Settings.instance.ssl_disabled_ciphers).join(':')
21
- ctx.key = config[:SSLPrivateKey]
22
- ctx.cert = config[:SSLCertificate]
23
- ctx.client_ca = config[:SSLClientCA]
24
- ctx.extra_chain_cert = config[:SSLExtraChainCert]
25
- ctx.ca_file = config[:SSLCACertificateFile]
26
- ctx.ca_path = config[:SSLCACertificatePath]
27
- ctx.cert_store = config[:SSLCertificateStore]
28
- ctx.tmp_dh_callback = config[:SSLTmpDhCallback]
29
- ctx.verify_mode = config[:SSLVerifyClient]
30
- ctx.verify_depth = config[:SSLVerifyDepth]
31
- ctx.verify_callback = config[:SSLVerifyCallback]
32
- ctx.timeout = config[:SSLTimeout]
33
- ctx.options |= config[:SSLOptions] unless config[:SSLOptions].nil?
34
- ctx
35
- end
36
- end
37
- end