foreman-tasks 0.10.0 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +0 -2
- data/app/assets/javascripts/{trigger_form.js → foreman_tasks/trigger_form.js} +0 -0
- data/app/controllers/foreman_tasks/recurring_logics_controller.rb +6 -1
- data/app/controllers/foreman_tasks/tasks_controller.rb +16 -2
- data/app/lib/actions/proxy_action.rb +7 -0
- data/app/models/foreman_tasks/task/dynflow_task.rb +19 -4
- data/app/models/foreman_tasks/task/summarizer.rb +3 -1
- data/app/views/common/_trigger_form.html.erb +1 -1
- data/app/views/foreman_tasks/recurring_logics/index.html.erb +1 -2
- data/app/views/foreman_tasks/tasks/dashboard/_latest_tasks_in_error_warning.html.erb +1 -1
- data/app/views/foreman_tasks/tasks/dashboard/_tasks_status.html.erb +2 -0
- data/app/views/foreman_tasks/tasks/index.html.erb +1 -2
- data/config/routes.rb +1 -0
- data/foreman-tasks.gemspec +1 -3
- data/lib/foreman_tasks.rb +2 -1
- data/lib/foreman_tasks/dynflow.rb +2 -108
- data/lib/foreman_tasks/dynflow/configuration.rb +7 -142
- data/lib/foreman_tasks/dynflow/persistence.rb +3 -2
- data/lib/foreman_tasks/engine.rb +2 -2
- data/lib/foreman_tasks/version.rb +1 -1
- data/test/controllers/recurring_logics_controller_test.rb +14 -0
- data/test/controllers/tasks_controller_test.rb +17 -0
- data/test/unit/otp_manager_test.rb +70 -0
- metadata +12 -43
- data/bin/dynflow-executor +0 -71
- data/bin/foreman-tasks +0 -5
- data/deploy/foreman-tasks.init +0 -231
- data/deploy/foreman-tasks.service +0 -16
- data/deploy/foreman-tasks.sysconfig +0 -26
- data/lib/foreman_tasks/dynflow/daemon.rb +0 -143
- data/lib/foreman_tasks/tasks/dynflow.rake +0 -7
- data/test/unit/daemon_test.rb +0 -86
@@ -1,16 +0,0 @@
|
|
1
|
-
[Unit]
|
2
|
-
Description=Foreman jobs daemon
|
3
|
-
Documentation=https://github.com/theforeman/foreman-tasks
|
4
|
-
After=network.target remote-fs.target nss-lookup.target
|
5
|
-
|
6
|
-
[Service]
|
7
|
-
Type=forking
|
8
|
-
User=foreman
|
9
|
-
TimeoutSec=600
|
10
|
-
WorkingDirectory=/usr/share/foreman
|
11
|
-
ExecStart=/usr/bin/foreman-tasks start
|
12
|
-
ExecStop=/usr/bin/foreman-tasks stop
|
13
|
-
EnvironmentFile=-/etc/sysconfig/foreman-tasks
|
14
|
-
|
15
|
-
[Install]
|
16
|
-
WantedBy=multi-user.target
|
@@ -1,26 +0,0 @@
|
|
1
|
-
FOREMAN_USER=foreman
|
2
|
-
BUNDLER_EXT_HOME=/usr/share/foreman
|
3
|
-
RAILS_RELATIVE_URL_ROOT=$FOREMAN_PREFIX
|
4
|
-
RAILS_ENV=production
|
5
|
-
FOREMAN_LOGGING=warn
|
6
|
-
FOREMAN_LOGGING_SQL=warn
|
7
|
-
FOREMAN_TASK_PARAMS="-p foreman"
|
8
|
-
FOREMAN_LOG_DIR=/var/log/foreman
|
9
|
-
|
10
|
-
RUBY_GC_MALLOC_LIMIT=4000100
|
11
|
-
RUBY_GC_MALLOC_LIMIT_MAX=16000100
|
12
|
-
RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR=1.1
|
13
|
-
RUBY_GC_OLDMALLOC_LIMIT=16000100
|
14
|
-
RUBY_GC_OLDMALLOC_LIMIT_MAX=16000100
|
15
|
-
|
16
|
-
#Set the number of executors you want to run
|
17
|
-
#EXECUTORS_COUNT=1
|
18
|
-
|
19
|
-
#Set memory limit for executor process, before it's restarted automatically
|
20
|
-
#EXECUTOR_MEMORY_LIMIT=2gb
|
21
|
-
|
22
|
-
#Set delay before first memory polling to let executor initialize (in sec)
|
23
|
-
#EXECUTOR_MEMORY_MONITOR_DELAY=7200 #default: 2 hours
|
24
|
-
|
25
|
-
#Set memory polling interval, process memory will be checked every N seconds.
|
26
|
-
#EXECUTOR_MEMORY_MONITOR_INTERVAL=60
|
@@ -1,143 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
require 'daemons'
|
3
|
-
require 'get_process_mem'
|
4
|
-
require 'dynflow/watchers/memory_consumption_watcher'
|
5
|
-
|
6
|
-
module ForemanTasks
|
7
|
-
class Dynflow::Daemon
|
8
|
-
attr_reader :dynflow_memory_watcher_class,
|
9
|
-
:daemons_class
|
10
|
-
|
11
|
-
# make Daemon dependency injection ready for testing purposes
|
12
|
-
def initialize(
|
13
|
-
dynflow_memory_watcher_class = ::Dynflow::Watchers::MemoryConsumptionWatcher,
|
14
|
-
daemons_class = ::Daemons
|
15
|
-
)
|
16
|
-
@dynflow_memory_watcher_class = dynflow_memory_watcher_class
|
17
|
-
@daemons_class = daemons_class
|
18
|
-
end
|
19
|
-
|
20
|
-
# load the Rails environment and initialize the executor
|
21
|
-
# in this thread.
|
22
|
-
def run(foreman_root = Dir.pwd, options = {})
|
23
|
-
STDERR.puts('Starting Rails environment')
|
24
|
-
foreman_env_file = File.expand_path('./config/environment.rb', foreman_root)
|
25
|
-
unless File.exist?(foreman_env_file)
|
26
|
-
raise "#{foreman_root} doesn't seem to be a foreman root directory"
|
27
|
-
end
|
28
|
-
|
29
|
-
STDERR.puts("Starting dynflow with the following options: #{options}")
|
30
|
-
|
31
|
-
ForemanTasks.dynflow.executor!
|
32
|
-
|
33
|
-
if options[:memory_limit] > 0
|
34
|
-
ForemanTasks.dynflow.config.on_init do |world|
|
35
|
-
memory_watcher = initialize_memory_watcher(world, options[:memory_limit], options)
|
36
|
-
world.terminated.on_completion do
|
37
|
-
STDERR.puts("World has been terminated")
|
38
|
-
memory_watcher = nil # the object can be disposed
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
require foreman_env_file
|
44
|
-
STDERR.puts("Everything ready for world: #{(ForemanTasks.dynflow.initialized? ? ForemanTasks.dynflow.world.id : nil)}")
|
45
|
-
sleep
|
46
|
-
ensure
|
47
|
-
STDERR.puts('Exiting')
|
48
|
-
end
|
49
|
-
|
50
|
-
# run the executor as a daemon
|
51
|
-
def run_background(command = 'start', options = {})
|
52
|
-
options = default_options.merge(options)
|
53
|
-
FileUtils.mkdir_p(options[:pid_dir])
|
54
|
-
begin
|
55
|
-
require 'daemons'
|
56
|
-
rescue LoadError
|
57
|
-
raise "You need to add gem 'daemons' to your Gemfile if you wish to use it."
|
58
|
-
end
|
59
|
-
|
60
|
-
unless %w[start stop restart run].include?(command)
|
61
|
-
raise "Command exptected to be 'start', 'stop', 'restart', 'run', was #{command.inspect}"
|
62
|
-
end
|
63
|
-
|
64
|
-
STDERR.puts("Dynflow Executor: #{command} in progress")
|
65
|
-
|
66
|
-
options[:executors_count].times do
|
67
|
-
daemons_class.run_proc(
|
68
|
-
options[:process_name],
|
69
|
-
daemons_options(command, options)
|
70
|
-
) do |*_args|
|
71
|
-
begin
|
72
|
-
::Logging.reopen
|
73
|
-
run(options[:foreman_root], options)
|
74
|
-
rescue => e
|
75
|
-
STDERR.puts e.message
|
76
|
-
Foreman::Logging.exception('Failed running foreman-tasks daemon', e)
|
77
|
-
exit 1
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
protected
|
84
|
-
|
85
|
-
def world
|
86
|
-
ForemanTasks.dynflow.world
|
87
|
-
end
|
88
|
-
|
89
|
-
private
|
90
|
-
|
91
|
-
def daemons_options(command, options)
|
92
|
-
{
|
93
|
-
:multiple => true,
|
94
|
-
:dir => options[:pid_dir],
|
95
|
-
:log_dir => options[:log_dir],
|
96
|
-
:dir_mode => :normal,
|
97
|
-
:monitor => true,
|
98
|
-
:log_output => true,
|
99
|
-
:log_output_syslog => true,
|
100
|
-
:monitor_interval => [options[:memory_polling_interval] / 2, 30].min,
|
101
|
-
:ARGV => [command]
|
102
|
-
}
|
103
|
-
end
|
104
|
-
|
105
|
-
def default_options
|
106
|
-
{
|
107
|
-
foreman_root: Dir.pwd,
|
108
|
-
process_name: 'dynflow_executor',
|
109
|
-
pid_dir: "#{Rails.root}/tmp/pids",
|
110
|
-
log_dir: File.join(Rails.root, 'log'),
|
111
|
-
wait_attempts: 300,
|
112
|
-
wait_sleep: 1,
|
113
|
-
executors_count: (ENV['EXECUTORS_COUNT'] || 1).to_i,
|
114
|
-
memory_limit: begin
|
115
|
-
(ENV['EXECUTOR_MEMORY_LIMIT'] || '').to_gb.gigabytes
|
116
|
-
rescue RuntimeError
|
117
|
-
ENV['EXECUTOR_MEMORY_LIMIT'].to_i
|
118
|
-
end,
|
119
|
-
memory_init_delay: (ENV['EXECUTOR_MEMORY_MONITOR_DELAY'] || 7200).to_i, # 2 hours
|
120
|
-
memory_polling_interval: (ENV['EXECUTOR_MEMORY_MONITOR_INTERVAL'] || 60).to_i
|
121
|
-
}
|
122
|
-
end
|
123
|
-
|
124
|
-
def initialize_memory_watcher(world, memory_limit, options)
|
125
|
-
watcher_options = {}
|
126
|
-
watcher_options[:polling_interval] = options[:memory_polling_interval]
|
127
|
-
watcher_options[:initial_wait] = options[:memory_init_delay]
|
128
|
-
watcher_options[:memory_checked_callback] = ->(current_memory, memory_limit) { log_memory_within_limit(current_memory, memory_limit) }
|
129
|
-
watcher_options[:memory_limit_exceeded_callback] = ->(current_memory, memory_limit) { log_memory_limit_exceeded(current_memory, memory_limit) }
|
130
|
-
dynflow_memory_watcher_class.new(world, memory_limit, watcher_options)
|
131
|
-
end
|
132
|
-
|
133
|
-
def log_memory_limit_exceeded(current_memory, memory_limit)
|
134
|
-
message = "Memory level exceeded, registered #{current_memory} bytes, which is greater than #{memory_limit} limit."
|
135
|
-
Foreman::Logging.logger('foreman-tasks').error(message)
|
136
|
-
end
|
137
|
-
|
138
|
-
def log_memory_within_limit(current_memory, memory_limit)
|
139
|
-
message = "Memory level OK, registered #{current_memory} bytes, which is less than #{memory_limit} limit."
|
140
|
-
Foreman::Logging.logger('foreman-tasks').debug(message)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
data/test/unit/daemon_test.rb
DELETED
@@ -1,86 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class DaemonTest < ActiveSupport::TestCase
|
4
|
-
setup do
|
5
|
-
@dynflow_memory_watcher = mock('memory_watcher')
|
6
|
-
@daemons = mock('daemons')
|
7
|
-
@daemon = ForemanTasks::Dynflow::Daemon.new(
|
8
|
-
@dynflow_memory_watcher,
|
9
|
-
@daemons
|
10
|
-
)
|
11
|
-
@world_class = mock('dummy world factory')
|
12
|
-
@dummy_world = Dynflow::Testing::DummyWorld.new
|
13
|
-
@dummy_world.stubs(:auto_execute)
|
14
|
-
@dummy_world.stubs(:terminated).returns(Concurrent.event)
|
15
|
-
@world_class.stubs(:new).returns(@dummy_world)
|
16
|
-
@dynflow = ForemanTasks::Dynflow.new(@world_class)
|
17
|
-
ForemanTasks.stubs(:dynflow).returns(@dynflow)
|
18
|
-
@dynflow.require!
|
19
|
-
end
|
20
|
-
|
21
|
-
test 'run command creates a watcher if memory_limit option specified' do
|
22
|
-
current_folder = File.expand_path('../', __FILE__)
|
23
|
-
|
24
|
-
@dynflow_memory_watcher.expects(:new).with do |_world, memory_limit, _watcher_options|
|
25
|
-
memory_limit == 1000
|
26
|
-
end
|
27
|
-
@daemon.stubs(:sleep).returns(true) # don't pause the execution
|
28
|
-
|
29
|
-
@daemon.run(current_folder, memory_limit: 1000)
|
30
|
-
# initialization should be performed inside the foreman environment,
|
31
|
-
# which is mocked here
|
32
|
-
@dynflow.initialize!
|
33
|
-
end
|
34
|
-
|
35
|
-
test 'run command sets parameters to watcher' do
|
36
|
-
current_folder = File.expand_path('../', __FILE__)
|
37
|
-
|
38
|
-
@dynflow_memory_watcher.expects(:new).with do |_world, memory_limit, watcher_options|
|
39
|
-
memory_limit == 1000 &&
|
40
|
-
watcher_options[:polling_interval] == 100 &&
|
41
|
-
watcher_options[:initial_wait] == 200
|
42
|
-
end
|
43
|
-
@daemon.stubs(:sleep).returns(true) # don't pause the execution
|
44
|
-
|
45
|
-
@daemon.run(
|
46
|
-
current_folder,
|
47
|
-
memory_limit: 1000,
|
48
|
-
memory_polling_interval: 100,
|
49
|
-
memory_init_delay: 200
|
50
|
-
)
|
51
|
-
# initialization should be performed inside the foreman environment,
|
52
|
-
# which is mocked here
|
53
|
-
@dynflow.initialize!
|
54
|
-
end
|
55
|
-
|
56
|
-
test 'run_background command executes run with all params set as a daemon' do
|
57
|
-
@daemon.expects(:run).twice.with do |_folder, options|
|
58
|
-
options[:memory_limit] == 1000 &&
|
59
|
-
options[:memory_init_delay] == 100 &&
|
60
|
-
options[:memory_polling_interval] == 200
|
61
|
-
end
|
62
|
-
@daemons.expects(:run_proc).twice.yields
|
63
|
-
|
64
|
-
@daemon.run_background(
|
65
|
-
'start',
|
66
|
-
executors_count: 2,
|
67
|
-
memory_limit: 1000,
|
68
|
-
memory_init_delay: 100,
|
69
|
-
memory_polling_interval: 200
|
70
|
-
)
|
71
|
-
end
|
72
|
-
|
73
|
-
test 'default options read values from ENV' do
|
74
|
-
ENV['EXECUTORS_COUNT'] = '2'
|
75
|
-
ENV['EXECUTOR_MEMORY_LIMIT'] = '1gb'
|
76
|
-
ENV['EXECUTOR_MEMORY_MONITOR_DELAY'] = '3'
|
77
|
-
ENV['EXECUTOR_MEMORY_MONITOR_INTERVAL'] = '4'
|
78
|
-
|
79
|
-
actual = @daemon.send(:default_options)
|
80
|
-
|
81
|
-
assert_equal 2, actual[:executors_count]
|
82
|
-
assert_equal 1.gigabytes, actual[:memory_limit]
|
83
|
-
assert_equal 3, actual[:memory_init_delay]
|
84
|
-
assert_equal 4, actual[:memory_polling_interval]
|
85
|
-
end
|
86
|
-
end
|