smart_proxy_dynflow_core 0.2.6 → 0.4.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 +4 -4
- data/Gemfile +6 -20
- data/lib/smart_proxy_dynflow_core.rb +8 -13
- data/lib/smart_proxy_dynflow_core/task_launcher_registry.rb +1 -29
- data/lib/smart_proxy_dynflow_core/version.rb +1 -1
- data/smart_proxy_dynflow_core.gemspec +6 -6
- metadata +37 -24
- data/bin/smart_proxy_dynflow_core +0 -32
- data/config/settings.yml.example +0 -50
- data/deploy/smart_proxy_dynflow_core.init +0 -92
- data/deploy/smart_proxy_dynflow_core.service +0 -13
- data/lib/smart_proxy_dynflow_core/api.rb +0 -81
- data/lib/smart_proxy_dynflow_core/bundler_helper.rb +0 -31
- data/lib/smart_proxy_dynflow_core/callback.rb +0 -86
- data/lib/smart_proxy_dynflow_core/core.rb +0 -122
- data/lib/smart_proxy_dynflow_core/helpers.rb +0 -73
- data/lib/smart_proxy_dynflow_core/launcher.rb +0 -167
- data/lib/smart_proxy_dynflow_core/log.rb +0 -86
- data/lib/smart_proxy_dynflow_core/sd_notify.rb +0 -33
- data/lib/smart_proxy_dynflow_core/settings.rb +0 -104
- data/lib/smart_proxy_dynflow_core/testing.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3226e9b143ecf53b28e97a765c2e760d42dc030ea3809736f5e7733b2db96cfe
|
4
|
+
data.tar.gz: eb70345b228d35506d36faa0a3fe59e09c8b1787d438f73d6554699736a70d3a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf3292bd295765e51968781f4a0a3678a5825977da06b56ddf86e073a232665f92f90cd5df25e0a6332304b4c3c15784404f2aae8d25f050cc77405d7520e57f
|
7
|
+
data.tar.gz: 1bdaaebb6e5b59fcf25250c4ba7695dadda3313854c8db343199bb8ec61529ed21deff5e948ac0545f6fde0eab6cde7bde73067b96943061e5bd013a22faa9db
|
data/Gemfile
CHANGED
@@ -10,28 +10,14 @@ group :test do
|
|
10
10
|
gem 'smart_proxy', :git => "https://github.com/theforeman/smart-proxy", :branch => "develop"
|
11
11
|
gem 'smart_proxy_dynflow', :path => '.'
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
else
|
17
|
-
gem 'public_suffix'
|
18
|
-
gem 'rubocop', '~> 0.52.1'
|
19
|
-
end
|
20
|
-
|
21
|
-
if RUBY_VERSION < '2.2'
|
22
|
-
gem 'rack-test', '< 0.8'
|
23
|
-
else
|
24
|
-
gem 'rack-test'
|
25
|
-
end
|
13
|
+
gem 'public_suffix'
|
14
|
+
gem 'rack-test'
|
15
|
+
gem 'rubocop', '~> 0.52.1'
|
26
16
|
end
|
27
17
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
else
|
32
|
-
gem 'rack', '>= 1.1'
|
33
|
-
gem 'sinatra'
|
34
|
-
end
|
18
|
+
gem 'logging-journald', '~> 2.0', :platforms => [:ruby], :require => false
|
19
|
+
gem 'rack', '>= 1.1'
|
20
|
+
gem 'sinatra'
|
35
21
|
|
36
22
|
# load bundler.d
|
37
23
|
Dir["#{File.dirname(__FILE__)}/bundler.d/*.rb"].each do |bundle|
|
@@ -1,18 +1,13 @@
|
|
1
|
-
|
1
|
+
# Whatever is here is just a compatibility layer
|
2
|
+
# Once all the _core have been migrated, this can be dropped.
|
2
3
|
|
3
|
-
require '
|
4
|
+
require 'smart_proxy_dynflow'
|
5
|
+
|
6
|
+
# REX core explicitly requires this file, otherwise we could use the trick we
|
7
|
+
# use with callback
|
4
8
|
require 'smart_proxy_dynflow_core/task_launcher_registry'
|
5
|
-
require 'foreman_tasks_core'
|
6
|
-
require 'smart_proxy_dynflow_core/log'
|
7
|
-
require 'smart_proxy_dynflow_core/settings'
|
8
|
-
require 'smart_proxy_dynflow_core/core'
|
9
|
-
require 'smart_proxy_dynflow_core/helpers'
|
10
|
-
require 'smart_proxy_dynflow_core/callback'
|
11
|
-
require 'smart_proxy_dynflow_core/api'
|
12
9
|
|
13
10
|
module SmartProxyDynflowCore
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
Core.register_silencer_matchers ForemanTasksCore.silent_dead_letter_matchers
|
11
|
+
Callback = Proxy::Dynflow::Callback
|
12
|
+
Log = Proxy::Dynflow::Log
|
18
13
|
end
|
@@ -1,31 +1,3 @@
|
|
1
1
|
module SmartProxyDynflowCore
|
2
|
-
|
3
|
-
class << self
|
4
|
-
def register(name, launcher)
|
5
|
-
registry[name] = launcher
|
6
|
-
end
|
7
|
-
|
8
|
-
def fetch(name, default = nil)
|
9
|
-
if default.nil?
|
10
|
-
registry.fetch(name)
|
11
|
-
else
|
12
|
-
registry.fetch(name, default)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def key?(name)
|
17
|
-
registry.key?(name)
|
18
|
-
end
|
19
|
-
|
20
|
-
def operations
|
21
|
-
registry.keys
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def registry
|
27
|
-
@registry ||= {}
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
2
|
+
TaskLauncherRegistry = Proxy::Dynflow::TaskLauncherRegistry
|
31
3
|
end
|
@@ -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
|
@@ -14,14 +13,14 @@ Gem::Specification.new do |gem|
|
|
14
13
|
Use the Dynflow inside Foreman smart proxy
|
15
14
|
EOS
|
16
15
|
|
17
|
-
gem.
|
18
|
-
|
19
|
-
'lib/smart_proxy_dynflow_core/*', 'LICENSE', 'Gemfile',
|
20
|
-
'bin/smart_proxy_dynflow_core', 'deploy/*', 'smart_proxy_dynflow_core.gemspec']
|
16
|
+
gem.files = Dir['lib/smart_proxy_dynflow_core.rb', 'lib/smart_proxy_dynflow_core/**/*',
|
17
|
+
'LICENSE', 'Gemfile', 'smart_proxy_dynflow_core.gemspec']
|
21
18
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
22
19
|
gem.require_paths = ["lib"]
|
23
20
|
gem.license = 'GPL-3.0'
|
24
21
|
|
22
|
+
gem.required_ruby_version = '~> 2.5'
|
23
|
+
|
25
24
|
gem.add_development_dependency "bundler", ">= 1.7"
|
26
25
|
gem.add_development_dependency('minitest')
|
27
26
|
gem.add_development_dependency('mocha', '~> 1')
|
@@ -31,10 +30,11 @@ Gem::Specification.new do |gem|
|
|
31
30
|
|
32
31
|
gem.add_runtime_dependency('dynflow', "~> 1.1")
|
33
32
|
gem.add_runtime_dependency('foreman-tasks-core', '>= 0.3.3')
|
33
|
+
gem.add_runtime_dependency('logging')
|
34
34
|
gem.add_runtime_dependency('rack')
|
35
35
|
gem.add_runtime_dependency('rest-client')
|
36
|
+
gem.add_runtime_dependency('sd_notify', '~> 0.1')
|
36
37
|
gem.add_runtime_dependency('sequel')
|
37
38
|
gem.add_runtime_dependency('sinatra')
|
38
39
|
gem.add_runtime_dependency('sqlite3')
|
39
40
|
end
|
40
|
-
# rubocop:enable Metrics/BlockLength
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_proxy_dynflow_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.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:
|
11
|
+
date: 2021-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: 0.3.3
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: logging
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: rack
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,6 +164,20 @@ dependencies:
|
|
150
164
|
- - ">="
|
151
165
|
- !ruby/object:Gem::Version
|
152
166
|
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: sd_notify
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0.1'
|
174
|
+
type: :runtime
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0.1'
|
153
181
|
- !ruby/object:Gem::Dependency
|
154
182
|
name: sequel
|
155
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -195,52 +223,37 @@ dependencies:
|
|
195
223
|
description: " Use the Dynflow inside Foreman smart proxy\n"
|
196
224
|
email:
|
197
225
|
- inecas@redhat.com
|
198
|
-
executables:
|
199
|
-
- smart_proxy_dynflow_core
|
226
|
+
executables: []
|
200
227
|
extensions: []
|
201
228
|
extra_rdoc_files: []
|
202
229
|
files:
|
203
230
|
- Gemfile
|
204
231
|
- LICENSE
|
205
|
-
- bin/smart_proxy_dynflow_core
|
206
|
-
- config/settings.yml.example
|
207
|
-
- deploy/smart_proxy_dynflow_core.init
|
208
|
-
- deploy/smart_proxy_dynflow_core.service
|
209
232
|
- lib/smart_proxy_dynflow_core.rb
|
210
|
-
- lib/smart_proxy_dynflow_core/api.rb
|
211
|
-
- lib/smart_proxy_dynflow_core/bundler_helper.rb
|
212
|
-
- lib/smart_proxy_dynflow_core/callback.rb
|
213
|
-
- lib/smart_proxy_dynflow_core/core.rb
|
214
|
-
- lib/smart_proxy_dynflow_core/helpers.rb
|
215
|
-
- lib/smart_proxy_dynflow_core/launcher.rb
|
216
|
-
- lib/smart_proxy_dynflow_core/log.rb
|
217
|
-
- lib/smart_proxy_dynflow_core/sd_notify.rb
|
218
|
-
- lib/smart_proxy_dynflow_core/settings.rb
|
219
233
|
- lib/smart_proxy_dynflow_core/task_launcher_registry.rb
|
220
|
-
- lib/smart_proxy_dynflow_core/testing.rb
|
221
234
|
- lib/smart_proxy_dynflow_core/version.rb
|
222
235
|
- smart_proxy_dynflow_core.gemspec
|
223
236
|
homepage: https://github.com/theforeman/smart_proxy_dynflow
|
224
237
|
licenses:
|
225
238
|
- GPL-3.0
|
226
239
|
metadata: {}
|
227
|
-
post_install_message:
|
240
|
+
post_install_message:
|
228
241
|
rdoc_options: []
|
229
242
|
require_paths:
|
230
243
|
- lib
|
231
244
|
required_ruby_version: !ruby/object:Gem::Requirement
|
232
245
|
requirements:
|
233
|
-
- - "
|
246
|
+
- - "~>"
|
234
247
|
- !ruby/object:Gem::Version
|
235
|
-
version: '
|
248
|
+
version: '2.5'
|
236
249
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
237
250
|
requirements:
|
238
251
|
- - ">="
|
239
252
|
- !ruby/object:Gem::Version
|
240
253
|
version: '0'
|
241
254
|
requirements: []
|
242
|
-
rubygems_version: 3.
|
243
|
-
signing_key:
|
255
|
+
rubygems_version: 3.1.2
|
256
|
+
signing_key:
|
244
257
|
specification_version: 4
|
245
258
|
summary: Dynflow runtime for Foreman smart proxy
|
246
259
|
test_files: []
|
@@ -1,32 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'dynflow'
|
3
|
-
require 'rack'
|
4
|
-
require 'smart_proxy_dynflow_core/launcher'
|
5
|
-
require 'yaml'
|
6
|
-
require 'optparse'
|
7
|
-
|
8
|
-
options = {}
|
9
|
-
OptionParser.new do |opts|
|
10
|
-
opts.on('-c', '--config-dir CONFIG_DIR', String, 'Directory to load settings from') do |value|
|
11
|
-
options[:config_dir] = value
|
12
|
-
end
|
13
|
-
|
14
|
-
opts.on('-1', '--one-config', 'Do not load more than 1 config') do |value|
|
15
|
-
options[:one_config] = true
|
16
|
-
end
|
17
|
-
|
18
|
-
opts.on('-d', '--[no-]daemonize', 'Fork to background after start') do |value|
|
19
|
-
options[:daemonize] = value
|
20
|
-
end
|
21
|
-
|
22
|
-
opts.on('-p', '--pid-file PID_FILE', String, 'Write pid to this file') do |value|
|
23
|
-
options[:pid_file] = value
|
24
|
-
end
|
25
|
-
|
26
|
-
opts.on_tail('-h', '--help', 'Show usage help') do
|
27
|
-
puts opts
|
28
|
-
exit
|
29
|
-
end
|
30
|
-
end.parse!
|
31
|
-
|
32
|
-
SmartProxyDynflowCore::Launcher.launch! options
|
data/config/settings.yml.example
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
---
|
2
|
-
# Path to dynflow database, leave blank for in-memory non-persistent database
|
3
|
-
:database:
|
4
|
-
|
5
|
-
# URL of the foreman, used for reporting back
|
6
|
-
:foreman_url: 'http://localhost:3000'
|
7
|
-
|
8
|
-
# SSL settings for client authentication against Foreman
|
9
|
-
# :foreman_ssl_ca: ssl/foreman_ca.pem
|
10
|
-
# :foreman_ssl_key: ssl/foreman_key.pem
|
11
|
-
# :foreman_ssl_cert: ssl/foreman_cert.pem
|
12
|
-
|
13
|
-
:console_auth: false
|
14
|
-
|
15
|
-
# Set to true to make the core fork to background after start
|
16
|
-
# :daemonize: false
|
17
|
-
# :pid_file: /var/run/foreman-proxy/smart_proxy_dynflow_core.pid
|
18
|
-
|
19
|
-
# Listen on address
|
20
|
-
:listen: 127.0.0.1
|
21
|
-
|
22
|
-
# Listen on port
|
23
|
-
:port: 8008
|
24
|
-
|
25
|
-
# SSL settings for running core as https service
|
26
|
-
# :use_https: false
|
27
|
-
# :ssl_ca_file: ssl/ca.pem
|
28
|
-
# :ssl_private_key: ssl/localhost.pem
|
29
|
-
# :ssl_certificate: ssl/certs/localhost.pem
|
30
|
-
|
31
|
-
# Use this option only if you need to disable certain cipher suites.
|
32
|
-
# Note: we use the OpenSSL suite name, take a look at:
|
33
|
-
# https://www.openssl.org/docs/manmaster/apps/ciphers.html#CIPHER-SUITE-NAMES
|
34
|
-
# for more information.
|
35
|
-
#:ssl_disabled_ciphers: [CIPHER-SUITE-1, CIPHER-SUITE-2]
|
36
|
-
|
37
|
-
# Use this option only if you need to strictly specify TLS versions to be
|
38
|
-
# disabled. SSLv3 and TLS v1.0 are always disabled and cannot be configured.
|
39
|
-
# Specify versions like: '1.1', or '1.2'
|
40
|
-
#:tls_disabled_versions: []
|
41
|
-
|
42
|
-
# File to log to, leave empty for logging to STDOUT
|
43
|
-
# :log_file: /var/log/foreman-proxy/smart_proxy_dynflow_core.log
|
44
|
-
|
45
|
-
# Log level, one of UNKNOWN, FATAL, ERROR, WARN, INFO, DEBUG
|
46
|
-
# :log_level: ERROR
|
47
|
-
|
48
|
-
# Maximum age of execution plans to keep before having them cleaned
|
49
|
-
# by the execution plan cleaner (in seconds), defaults to 24 hours
|
50
|
-
# :execution_plan_cleaner_age: 86400
|
@@ -1,92 +0,0 @@
|
|
1
|
-
#!/bin/bash
|
2
|
-
#
|
3
|
-
# Init script for foreman smart proxy dynflow core service
|
4
|
-
#
|
5
|
-
# chkconfig: - 85 15
|
6
|
-
# description: Init script for foreman proxy dynflow core service
|
7
|
-
|
8
|
-
# Source function library.
|
9
|
-
. /etc/rc.d/init.d/functions
|
10
|
-
|
11
|
-
prog=smart_proxy_dynflow_core
|
12
|
-
RETVAL=0
|
13
|
-
SMART_PROXY_DYNFLOW_CORE_PID=/var/run/foreman-proxy/$prog.pid
|
14
|
-
SMART_PROXY_DYNFLOW_CORE_USER=${SMART_PROXY_DYNFLOW_CORE_USER:-foreman-proxy}
|
15
|
-
|
16
|
-
start() {
|
17
|
-
echo -n $"Starting $prog: "
|
18
|
-
ulimit -n 65536
|
19
|
-
daemon --user ${SMART_PROXY_DYNFLOW_CORE_USER} /usr/bin/smart_proxy_dynflow_core -d -p $SMART_PROXY_DYNFLOW_CORE_PID > /dev/null
|
20
|
-
RETVAL=$?
|
21
|
-
if [ $RETVAL = 0 ]
|
22
|
-
then
|
23
|
-
echo_success
|
24
|
-
else
|
25
|
-
echo_failure
|
26
|
-
fi
|
27
|
-
|
28
|
-
echo
|
29
|
-
return $RETVAL
|
30
|
-
}
|
31
|
-
|
32
|
-
stop() {
|
33
|
-
echo -n $"Stopping $prog: "
|
34
|
-
if [ -f ${SMART_PROXY_DYNFLOW_CORE_PID} ]; then
|
35
|
-
killproc -p ${SMART_PROXY_DYNFLOW_CORE_PID}
|
36
|
-
RETVAL=$?
|
37
|
-
else
|
38
|
-
echo -n $"$prog was not running.";
|
39
|
-
failure $"$prog was not running.";
|
40
|
-
echo
|
41
|
-
return 1
|
42
|
-
fi
|
43
|
-
echo
|
44
|
-
[ $RETVAL -eq 0 ] && rm -f ${SMART_PROXY_DYNFLOW_CORE_PID}
|
45
|
-
return $RETVAL
|
46
|
-
}
|
47
|
-
|
48
|
-
logrotate() {
|
49
|
-
echo -n $"Rotating logs for $prog: "
|
50
|
-
if [ -f ${SMART_PROXY_DYNFLOW_CORE_PID} ]; then
|
51
|
-
killproc -p ${SMART_PROXY_DYNFLOW_CORE_PID} $prog -USR1
|
52
|
-
RETVAL=$?
|
53
|
-
echo
|
54
|
-
else
|
55
|
-
echo -n $"$prog was not running.";
|
56
|
-
failure $"$prog was not running.";
|
57
|
-
echo
|
58
|
-
return 1
|
59
|
-
fi
|
60
|
-
return $RETVAL
|
61
|
-
}
|
62
|
-
|
63
|
-
# See how we were called.
|
64
|
-
case "$1" in
|
65
|
-
start)
|
66
|
-
start
|
67
|
-
;;
|
68
|
-
stop)
|
69
|
-
stop
|
70
|
-
;;
|
71
|
-
status)
|
72
|
-
echo -n "$prog"
|
73
|
-
status -p $SMART_PROXY_DYNFLOW_CORE_PID
|
74
|
-
RETVAL=$?
|
75
|
-
;;
|
76
|
-
restart)
|
77
|
-
stop
|
78
|
-
start
|
79
|
-
;;
|
80
|
-
condrestart)
|
81
|
-
stop
|
82
|
-
[ $? -eq 0 ] && start
|
83
|
-
;;
|
84
|
-
logrotate)
|
85
|
-
logrotate
|
86
|
-
;;
|
87
|
-
*)
|
88
|
-
echo $"Usage: $prog {start|stop|restart|condrestart|logrotate}"
|
89
|
-
exit 1
|
90
|
-
esac
|
91
|
-
|
92
|
-
exit $RETVAL
|
@@ -1,13 +0,0 @@
|
|
1
|
-
[Unit]
|
2
|
-
Description=Foreman smart proxy dynflow core service
|
3
|
-
Documentation=https://github.com/theforeman/smart_proxy_dynflow
|
4
|
-
After=network.target remote-fs.target nss-lookup.target
|
5
|
-
|
6
|
-
[Service]
|
7
|
-
Type=notify
|
8
|
-
User=foreman-proxy
|
9
|
-
ExecStart=/usr/bin/smart_proxy_dynflow_core --no-daemonize
|
10
|
-
EnvironmentFile=-/etc/sysconfig/smart_proxy_dynflow_core
|
11
|
-
|
12
|
-
[Install]
|
13
|
-
WantedBy=multi-user.target
|
@@ -1,81 +0,0 @@
|
|
1
|
-
require 'sinatra/base'
|
2
|
-
require 'multi_json'
|
3
|
-
|
4
|
-
module SmartProxyDynflowCore
|
5
|
-
class Api < ::Sinatra::Base
|
6
|
-
TASK_UPDATE_REGEXP_PATH = %r{/tasks/(\S+)/(update|done)}
|
7
|
-
helpers Helpers
|
8
|
-
|
9
|
-
before do
|
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
|
17
|
-
content_type :json
|
18
|
-
end
|
19
|
-
|
20
|
-
post "/tasks/status" do
|
21
|
-
params = MultiJson.load(request.body.read)
|
22
|
-
ids = params.fetch('task_ids', [])
|
23
|
-
result = world.persistence
|
24
|
-
.find_execution_plans(:filters => { :uuid => ids }).reduce({}) do |acc, plan|
|
25
|
-
acc.update(plan.id => { 'state' => plan.state, 'result' => plan.result })
|
26
|
-
end
|
27
|
-
MultiJson.dump(result)
|
28
|
-
end
|
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
|
-
|
37
|
-
post "/tasks/?" do
|
38
|
-
params = MultiJson.load(request.body.read)
|
39
|
-
trigger_task(::Dynflow::Utils.constantize(params['action_name']),
|
40
|
-
params['action_input'].merge(:callback_host => callback_host(params, request))).to_json
|
41
|
-
end
|
42
|
-
|
43
|
-
post "/tasks/:task_id/cancel" do |task_id|
|
44
|
-
cancel_task(task_id).to_json
|
45
|
-
end
|
46
|
-
|
47
|
-
get "/tasks/:task_id/status" do |task_id|
|
48
|
-
task_status(task_id).to_json
|
49
|
-
end
|
50
|
-
|
51
|
-
get "/tasks/count" do
|
52
|
-
tasks_count(params['state']).to_json
|
53
|
-
end
|
54
|
-
|
55
|
-
# capturing post "/tasks/:task_id/(update|done)"
|
56
|
-
post TASK_UPDATE_REGEXP_PATH do |task_id, _action|
|
57
|
-
data = MultiJson.load(request.body.read)
|
58
|
-
dispatch_external_event(task_id, data)
|
59
|
-
end
|
60
|
-
|
61
|
-
get "/tasks/operations" do
|
62
|
-
TaskLauncherRegistry.operations.to_json
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def callback_host(params, request)
|
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
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module SmartProxyDynflowCore
|
2
|
-
class BundlerHelper
|
3
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
4
|
-
def self.require_groups(*groups)
|
5
|
-
if File.exist?(File.expand_path('../../../Gemfile.in', __FILE__))
|
6
|
-
# If there is a Gemfile.in file, we will not use Bundler but BundlerExt
|
7
|
-
# gem which parses this file and loads all dependencies from the system
|
8
|
-
# rathern then trying to download them from rubygems.org. It always
|
9
|
-
# loads all gemfile groups.
|
10
|
-
begin
|
11
|
-
require 'bundler_ext' unless defined?(BundlerExt)
|
12
|
-
rescue LoadError
|
13
|
-
# Debian packaging guidelines state to avoid needing rubygems, so
|
14
|
-
# we only try to load it if the first require fails (for RPMs)
|
15
|
-
begin
|
16
|
-
require 'rubygems' rescue nil
|
17
|
-
require 'bundler_ext'
|
18
|
-
rescue LoadError
|
19
|
-
puts "`bundler_ext` gem is required to run smart_proxy"
|
20
|
-
exit 1
|
21
|
-
end
|
22
|
-
end
|
23
|
-
BundlerExt.system_require(File.expand_path('../../../Gemfile.in', __FILE__), *groups)
|
24
|
-
else
|
25
|
-
require 'bundler' unless defined?(Bundler)
|
26
|
-
Bundler.require(*groups)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
30
|
-
end
|
31
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
require 'rest-client'
|
2
|
-
|
3
|
-
# rubocop:disable Lint/HandleExceptions
|
4
|
-
begin
|
5
|
-
require 'smart_proxy_dynflow/callback'
|
6
|
-
rescue LoadError
|
7
|
-
end
|
8
|
-
# rubocop:enable Lint/HandleExceptions
|
9
|
-
|
10
|
-
module SmartProxyDynflowCore
|
11
|
-
module Callback
|
12
|
-
class Request
|
13
|
-
class << self
|
14
|
-
def send_to_foreman_tasks(callback_info, data)
|
15
|
-
self.new.callback(prepare_payload(callback_info, data))
|
16
|
-
end
|
17
|
-
|
18
|
-
# 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
|
48
|
-
end
|
49
|
-
|
50
|
-
def callback(payload)
|
51
|
-
response = callback_resource.post(payload, :content_type => :json)
|
52
|
-
if response.code.to_s != "200"
|
53
|
-
raise "Failed performing callback to Foreman server: #{response.code} #{response.body}"
|
54
|
-
end
|
55
|
-
response
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
def callback_resource
|
61
|
-
@resource ||= RestClient::Resource.new(Settings.instance.foreman_url + '/foreman_tasks/api/tasks/callback',
|
62
|
-
self.class.ssl_options)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
class Action < ::Dynflow::Action
|
67
|
-
def plan(callback, data)
|
68
|
-
plan_self(:callback => callback, :data => data)
|
69
|
-
end
|
70
|
-
|
71
|
-
def run
|
72
|
-
Callback::Request.send_to_foreman_tasks(input[:callback], input[:data])
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
module PlanHelper
|
77
|
-
def plan_with_callback(input)
|
78
|
-
input = input.dup
|
79
|
-
callback = input.delete('callback')
|
80
|
-
|
81
|
-
planned_action = plan_self(input)
|
82
|
-
plan_action(Callback::Action, callback, planned_action.output) if callback
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
@@ -1,122 +0,0 @@
|
|
1
|
-
module SmartProxyDynflowCore
|
2
|
-
class Core
|
3
|
-
attr_accessor :world, :accepted_cert_serial
|
4
|
-
|
5
|
-
def initialize
|
6
|
-
@world = create_world
|
7
|
-
cert_file = Settings.instance.foreman_ssl_cert || Settings.instance.ssl_certificate
|
8
|
-
if cert_file
|
9
|
-
client_cert = File.read(cert_file)
|
10
|
-
# we trust only requests using the same certificate as we are
|
11
|
-
# (in other words the local proxy only)
|
12
|
-
@accepted_cert_serial = OpenSSL::X509::Certificate.new(client_cert).serial
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def create_world(&block)
|
17
|
-
config = default_world_config(&block)
|
18
|
-
::Dynflow::World.new(config)
|
19
|
-
end
|
20
|
-
|
21
|
-
def persistence_conn_string
|
22
|
-
return ENV['DYNFLOW_DB_CONN_STRING'] if ENV.key? 'DYNFLOW_DB_CONN_STRING'
|
23
|
-
db_conn_string = 'sqlite:/'
|
24
|
-
|
25
|
-
db_file = Settings.instance.database
|
26
|
-
if db_file.nil? || db_file.empty?
|
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
|
-
else
|
30
|
-
db_conn_string += "/#{db_file}"
|
31
|
-
end
|
32
|
-
|
33
|
-
db_conn_string
|
34
|
-
end
|
35
|
-
|
36
|
-
def persistence_adapter
|
37
|
-
::Dynflow::PersistenceAdapters::Sequel.new persistence_conn_string
|
38
|
-
end
|
39
|
-
|
40
|
-
def default_world_config
|
41
|
-
::Dynflow::Config.new.tap do |config|
|
42
|
-
config.auto_rescue = true
|
43
|
-
config.logger_adapter = logger_adapter
|
44
|
-
config.persistence_adapter = persistence_adapter
|
45
|
-
config.execution_plan_cleaner = execution_plan_cleaner
|
46
|
-
# TODO: There has to be a better way
|
47
|
-
matchers = config.silent_dead_letter_matchers.call.concat(self.class.silencer_matchers)
|
48
|
-
config.silent_dead_letter_matchers = matchers
|
49
|
-
yield config if block_given?
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def logger_adapter
|
54
|
-
if Settings.instance.standalone
|
55
|
-
Log::ProxyAdapter.new(Log.instance, Log.instance.level)
|
56
|
-
else
|
57
|
-
Log::ProxyAdapter.new(Proxy::LogBuffer::Decorator.instance, Log.instance.level)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def execution_plan_cleaner
|
62
|
-
proc do |world|
|
63
|
-
age = Settings.instance.execution_plan_cleaner_age
|
64
|
-
options = { :poll_interval => age, :max_age => age }
|
65
|
-
::Dynflow::Actors::ExecutionPlanCleaner.new(world, options)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
class << self
|
70
|
-
attr_reader :instance
|
71
|
-
|
72
|
-
def ensure_initialized
|
73
|
-
return @instance if @instance
|
74
|
-
@instance = Core.new
|
75
|
-
after_initialize_blocks.each { |block| block.call(@instance) }
|
76
|
-
@instance
|
77
|
-
end
|
78
|
-
|
79
|
-
def silencer_matchers
|
80
|
-
@matchers ||= []
|
81
|
-
end
|
82
|
-
|
83
|
-
def register_silencer_matchers(matchers)
|
84
|
-
silencer_matchers.concat matchers
|
85
|
-
end
|
86
|
-
|
87
|
-
def web_console
|
88
|
-
require 'dynflow/web'
|
89
|
-
dynflow_console = ::Dynflow::Web.setup do
|
90
|
-
# we can't use the proxy's after_activation hook, as
|
91
|
-
# it happens before the Daemon forks the process (including
|
92
|
-
# closing opened file descriptors)
|
93
|
-
# TODO: extend smart proxy to enable hooks that happen after
|
94
|
-
# the forking
|
95
|
-
helpers Helpers
|
96
|
-
|
97
|
-
before do
|
98
|
-
authorize_with_ssl_client if Settings.instance.console_auth
|
99
|
-
end
|
100
|
-
|
101
|
-
Core.ensure_initialized
|
102
|
-
set :world, Core.world
|
103
|
-
end
|
104
|
-
dynflow_console
|
105
|
-
end
|
106
|
-
|
107
|
-
def world
|
108
|
-
instance.world
|
109
|
-
end
|
110
|
-
|
111
|
-
def after_initialize(&block)
|
112
|
-
after_initialize_blocks << block
|
113
|
-
end
|
114
|
-
|
115
|
-
private
|
116
|
-
|
117
|
-
def after_initialize_blocks
|
118
|
-
@after_initialize_blocks ||= []
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
@@ -1,73 +0,0 @@
|
|
1
|
-
module SmartProxyDynflowCore
|
2
|
-
module Helpers
|
3
|
-
def world
|
4
|
-
SmartProxyDynflowCore::Core.world
|
5
|
-
end
|
6
|
-
|
7
|
-
def authorize_with_token(task_id:, clear: true)
|
8
|
-
if request.env.key? 'HTTP_AUTHORIZATION'
|
9
|
-
if defined?(::ForemanTasksCore)
|
10
|
-
auth = request.env['HTTP_AUTHORIZATION']
|
11
|
-
basic_prefix = /\ABasic /
|
12
|
-
if !auth.to_s.empty? && auth =~ basic_prefix &&
|
13
|
-
ForemanTasksCore::OtpManager.authenticate(auth.gsub(basic_prefix, ''),
|
14
|
-
expected_user: task_id, clear: clear)
|
15
|
-
Log.instance.debug('authorized with token')
|
16
|
-
return true
|
17
|
-
end
|
18
|
-
end
|
19
|
-
halt 403, MultiJson.dump(:error => 'Invalid username or password supplied')
|
20
|
-
end
|
21
|
-
false
|
22
|
-
end
|
23
|
-
|
24
|
-
def authorize_with_ssl_client
|
25
|
-
if %w[yes on 1].include? request.env['HTTPS'].to_s
|
26
|
-
if request.env['SSL_CLIENT_CERT'].to_s.empty?
|
27
|
-
Log.instance.error "No client SSL certificate supplied"
|
28
|
-
halt 403, MultiJson.dump(:error => "No client SSL certificate supplied")
|
29
|
-
else
|
30
|
-
client_cert = OpenSSL::X509::Certificate.new(request.env['SSL_CLIENT_CERT'])
|
31
|
-
unless SmartProxyDynflowCore::Core.instance.accepted_cert_serial == client_cert.serial
|
32
|
-
Log.instance.error "SSL certificate with unexpected serial supplied"
|
33
|
-
halt 403, MultiJson.dump(:error => "SSL certificate with unexpected serial supplied")
|
34
|
-
end
|
35
|
-
end
|
36
|
-
else
|
37
|
-
Log.instance.debug 'require_ssl_client_verification: skipping, non-HTTPS request'
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def trigger_task(*args)
|
42
|
-
triggered = world.trigger(*args)
|
43
|
-
{ :task_id => triggered.id }
|
44
|
-
end
|
45
|
-
|
46
|
-
def cancel_task(task_id)
|
47
|
-
execution_plan = world.persistence.load_execution_plan(task_id)
|
48
|
-
cancel_events = execution_plan.cancel
|
49
|
-
{ :task_id => task_id, :canceled_steps_count => cancel_events.size }
|
50
|
-
end
|
51
|
-
|
52
|
-
def task_status(task_id)
|
53
|
-
ep = world.persistence.load_execution_plan(task_id)
|
54
|
-
ep.to_hash.merge(:actions => ep.actions.map(&:to_hash))
|
55
|
-
rescue KeyError => _e
|
56
|
-
status 404
|
57
|
-
{}
|
58
|
-
end
|
59
|
-
|
60
|
-
def tasks_count(state)
|
61
|
-
state ||= 'all'
|
62
|
-
filter = state != 'all' ? { :filters => { :state => [state] } } : {}
|
63
|
-
tasks = world.persistence.find_execution_plans(filter)
|
64
|
-
{ :count => tasks.count, :state => state }
|
65
|
-
end
|
66
|
-
|
67
|
-
def dispatch_external_event(task_id, params)
|
68
|
-
world.event(task_id,
|
69
|
-
params['step_id'].to_i,
|
70
|
-
::ForemanTasksCore::Runner::ExternalEvent.new(params))
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
@@ -1,167 +0,0 @@
|
|
1
|
-
require 'webrick/https'
|
2
|
-
require 'smart_proxy_dynflow_core/bundler_helper'
|
3
|
-
require 'smart_proxy_dynflow_core/settings'
|
4
|
-
require 'smart_proxy_dynflow_core/sd_notify'
|
5
|
-
|
6
|
-
module SmartProxyDynflowCore
|
7
|
-
class Launcher
|
8
|
-
CIPHERS = ['ECDHE-RSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES256-GCM-SHA384',
|
9
|
-
'AES128-GCM-SHA256', 'AES256-GCM-SHA384', 'AES128-SHA256',
|
10
|
-
'AES256-SHA256', 'AES128-SHA', 'AES256-SHA'].freeze
|
11
|
-
|
12
|
-
def self.launch!(options)
|
13
|
-
self.new.start options
|
14
|
-
end
|
15
|
-
|
16
|
-
def start(options)
|
17
|
-
load_settings!(options)
|
18
|
-
Settings.instance.standalone = true
|
19
|
-
install_usr1_trap
|
20
|
-
Rack::Server.new(rack_settings).start do |_server|
|
21
|
-
SmartProxyDynflowCore::Core.ensure_initialized
|
22
|
-
SmartProxyDynflowCore::SdNotify.new.tap { |sd| sd.ready if sd.active? }
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def load_settings!(options = {})
|
27
|
-
config_dir, one_config = options.values_at(:config_dir, :one_config)
|
28
|
-
possible_config_dirs = [
|
29
|
-
'/etc/smart_proxy_dynflow_core',
|
30
|
-
File.expand_path('~/.config/smart_proxy_dynflow_core'),
|
31
|
-
File.join(File.dirname(__FILE__), '..', '..', 'config'),
|
32
|
-
]
|
33
|
-
possible_config_dirs << config_dir if config_dir
|
34
|
-
BundlerHelper.require_groups(:default)
|
35
|
-
possible_config_dirs.reverse! if one_config
|
36
|
-
possible_config_dirs.select { |config_dir| File.directory? config_dir }.each do |config_dir|
|
37
|
-
break if load_config_dir(config_dir) && one_config
|
38
|
-
end
|
39
|
-
Settings.instance.daemonize = options[:daemonize] if options.key?(:daemonize)
|
40
|
-
Settings.instance.pid_file = options[:pid_file] if options.key?(:pid_file)
|
41
|
-
Settings.loaded!
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.route_mapping(rack_builder)
|
45
|
-
rack_builder.map '/console' do
|
46
|
-
run Core.web_console
|
47
|
-
end
|
48
|
-
|
49
|
-
rack_builder.map '/' do
|
50
|
-
run Api
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def install_usr1_trap
|
55
|
-
trap(:USR1) do
|
56
|
-
Log.instance.roll_log
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
def rack_settings
|
63
|
-
settings = if https_enabled?
|
64
|
-
Log.instance.debug "Using HTTPS"
|
65
|
-
https_app
|
66
|
-
else
|
67
|
-
Log.instance.debug "Using HTTP"
|
68
|
-
{}
|
69
|
-
end
|
70
|
-
settings.merge(base_settings)
|
71
|
-
end
|
72
|
-
|
73
|
-
def app
|
74
|
-
Rack::Builder.new do
|
75
|
-
SmartProxyDynflowCore::Launcher.route_mapping(self)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def base_settings
|
80
|
-
{
|
81
|
-
:app => app,
|
82
|
-
:Host => Settings.instance.listen,
|
83
|
-
:Port => Settings.instance.port,
|
84
|
-
:AccessLog => [[Log.instance, WEBrick::AccessLog::COMMON_LOG_FORMAT]],
|
85
|
-
:Logger => Log.instance,
|
86
|
-
:daemonize => Settings.instance.daemonize,
|
87
|
-
:pid => Settings.instance.daemonize && Settings.instance.pid_file,
|
88
|
-
:server => :webrick
|
89
|
-
}
|
90
|
-
end
|
91
|
-
|
92
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
93
|
-
def https_app
|
94
|
-
ssl_options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
|
95
|
-
ssl_options |= OpenSSL::SSL::OP_CIPHER_SERVER_PREFERENCE if defined?(OpenSSL::SSL::OP_CIPHER_SERVER_PREFERENCE)
|
96
|
-
# This is required to disable SSLv3 on Ruby 1.8.7
|
97
|
-
ssl_options |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2)
|
98
|
-
ssl_options |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3)
|
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)
|
101
|
-
|
102
|
-
if Settings.instance.tls_disabled_versions
|
103
|
-
Settings.instance.tls_disabled_versions.each do |version|
|
104
|
-
constant = OpenSSL::SSL.const_get("OP_NO_TLSv#{version.to_s.tr('.', '_')}") rescue nil
|
105
|
-
|
106
|
-
if constant
|
107
|
-
Log.instance.info "TLSv#{version} will be disabled."
|
108
|
-
ssl_options |= constant
|
109
|
-
else
|
110
|
-
Log.instance.warn "TLSv#{version} was not found."
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
{
|
116
|
-
:SSLEnable => true,
|
117
|
-
:SSLVerifyClient => OpenSSL::SSL::VERIFY_PEER,
|
118
|
-
:SSLPrivateKey => ssl_private_key,
|
119
|
-
:SSLCertificate => ssl_certificate,
|
120
|
-
:SSLCACertificateFile => Settings.instance.ssl_ca_file,
|
121
|
-
:SSLCiphers => CIPHERS - SmartProxyDynflowCore::Settings.instance.ssl_disabled_ciphers,
|
122
|
-
:SSLOptions => ssl_options
|
123
|
-
}
|
124
|
-
end
|
125
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
126
|
-
|
127
|
-
def https_enabled?
|
128
|
-
Settings.instance.use_https
|
129
|
-
end
|
130
|
-
|
131
|
-
def ssl_private_key
|
132
|
-
OpenSSL::PKey::RSA.new(File.read(Settings.instance.ssl_private_key))
|
133
|
-
rescue Exception => 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}"
|
136
|
-
raise e
|
137
|
-
end
|
138
|
-
|
139
|
-
def ssl_certificate
|
140
|
-
OpenSSL::X509::Certificate.new(File.read(Settings.instance.ssl_certificate))
|
141
|
-
rescue Exception => e
|
142
|
-
Log.instance.fatal "Unable to load SSL certificate. Are the values " \
|
143
|
-
"correct in settings.yml and do permissions allow reading?: #{e}"
|
144
|
-
raise e
|
145
|
-
end
|
146
|
-
|
147
|
-
def load_config_dir(dir)
|
148
|
-
settings_yml = File.join(dir, 'settings.yml')
|
149
|
-
if File.exist? settings_yml
|
150
|
-
Log.instance.debug "Loading settings from #{dir}"
|
151
|
-
Settings.load_global_settings settings_yml
|
152
|
-
Dir[File.join(dir, 'settings.d', '*.yml')].each { |path| Settings.load_plugin_settings(path) }
|
153
|
-
true
|
154
|
-
end
|
155
|
-
ForemanTasksCore::SettingsLoader.settings_registry.each_key do |settings_keys|
|
156
|
-
settings = settings_keys.inject({}) do |h, settings_key|
|
157
|
-
if SETTINGS.plugins.key?(settings_key.to_s)
|
158
|
-
h.merge(SETTINGS.plugins[settings_key.to_s].to_h)
|
159
|
-
else
|
160
|
-
h
|
161
|
-
end
|
162
|
-
end
|
163
|
-
ForemanTasksCore::SettingsLoader.setup_settings(settings_keys.first, settings)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
require 'logger'
|
2
|
-
|
3
|
-
module SmartProxyDynflowCore
|
4
|
-
class Log < ::Logger
|
5
|
-
alias_method :write, :debug
|
6
|
-
|
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
|
15
|
-
|
16
|
-
def instance=(logger)
|
17
|
-
@logger = logger
|
18
|
-
end
|
19
|
-
|
20
|
-
def reload!
|
21
|
-
@logger = nil
|
22
|
-
instance
|
23
|
-
end
|
24
|
-
|
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
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def log_file
|
34
|
-
if Settings.instance.loaded && Settings.instance.log_file
|
35
|
-
Settings.instance.log_file
|
36
|
-
else
|
37
|
-
$stdout
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
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
|
48
|
-
|
49
|
-
def roll_log
|
50
|
-
unless @file.is_a? IO
|
51
|
-
@fd.reopen @file, 'a'
|
52
|
-
@fd.sync = true
|
53
|
-
end
|
54
|
-
end
|
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
|
-
|
76
|
-
class ProxyAdapter < ::Dynflow::LoggerAdapters::Simple
|
77
|
-
def initialize(logger, level = Logger::DEBUG, _formatters = [])
|
78
|
-
@logger = logger
|
79
|
-
@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])
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
@@ -1,33 +0,0 @@
|
|
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
|
@@ -1,104 +0,0 @@
|
|
1
|
-
require 'ostruct'
|
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
|
-
module SmartProxyDynflowCore
|
21
|
-
class Settings < OpenStruct
|
22
|
-
DEFAULT_SETTINGS = {
|
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
|
46
|
-
|
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
|
52
|
-
|
53
|
-
def initialize(settings = {})
|
54
|
-
super(DEFAULT_SETTINGS.merge(settings))
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.instance
|
58
|
-
SmartProxyDynflowCore::SETTINGS
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.load_global_settings(path)
|
62
|
-
if File.exist? File.join(path)
|
63
|
-
YAML.load_file(path).each do |key, value|
|
64
|
-
SETTINGS[key] = value
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.loaded!
|
70
|
-
Settings.instance.loaded = true
|
71
|
-
Log.instance.info 'Settings loaded, reloading logger'
|
72
|
-
Log.reload!
|
73
|
-
end
|
74
|
-
|
75
|
-
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
|
83
|
-
PROXY_SETTINGS.each do |key|
|
84
|
-
SETTINGS[key] = Proxy::SETTINGS[key]
|
85
|
-
end
|
86
|
-
PLUGIN_SETTINGS.each do |key|
|
87
|
-
SETTINGS[key] = settings[key] if settings.key?(key)
|
88
|
-
end
|
89
|
-
SETTINGS.plugins.values.each(&:load_settings_from_proxy)
|
90
|
-
Settings.loaded!
|
91
|
-
end
|
92
|
-
|
93
|
-
def self.load_plugin_settings(path)
|
94
|
-
settings = YAML.load_file(path)
|
95
|
-
name = File.basename(path).gsub(/\.yml$/, '')
|
96
|
-
if SETTINGS.plugins.key? name
|
97
|
-
settings = SETTINGS.plugins[name].to_h.merge(settings)
|
98
|
-
end
|
99
|
-
SETTINGS.plugins[name] = OpenStruct.new settings
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
SmartProxyDynflowCore::SETTINGS = SmartProxyDynflowCore::Settings.new
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'dynflow/testing'
|
2
|
-
|
3
|
-
unless defined? DYNFLOW_TESTING_LOG_LEVEL
|
4
|
-
DYNFLOW_TESTING_LOG_LEVEL = 4
|
5
|
-
end
|
6
|
-
|
7
|
-
module SmartProxyDynflowCore
|
8
|
-
class Dynflow
|
9
|
-
# Helper for usage in other dependent plugins that need Dynflow
|
10
|
-
# related things, such as testing instance of world etc.
|
11
|
-
module Testing
|
12
|
-
class << self
|
13
|
-
def create_world(&block)
|
14
|
-
Core.ensure_initialized
|
15
|
-
Core.instance.create_world do |config|
|
16
|
-
config.exit_on_terminate = false
|
17
|
-
config.auto_terminate = false
|
18
|
-
config.logger_adapter = ::Dynflow::LoggerAdapters::Simple.new $stderr, DYNFLOW_TESTING_LOG_LEVEL
|
19
|
-
config.execution_plan_cleaner = nil
|
20
|
-
yield(config) if block
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
Concurrent.disable_at_exit_handlers!
|