foreman-tasks 4.1.5 → 5.2.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/.github/workflows/ruby_tests.yml +0 -1
- data/.rubocop.yml +0 -4
- data/.rubocop_todo.yml +0 -2
- data/README.md +8 -6
- data/app/assets/javascripts/foreman_tasks/trigger_form.js +7 -0
- data/app/controllers/foreman_tasks/api/tasks_controller.rb +2 -2
- data/app/controllers/foreman_tasks/tasks_controller.rb +2 -2
- data/app/graphql/mutations/recurring_logics/cancel.rb +27 -0
- data/app/graphql/types/recurring_logic.rb +21 -0
- data/app/graphql/types/task.rb +25 -0
- data/app/graphql/types/triggering.rb +16 -0
- data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +4 -1
- data/app/lib/actions/helpers/with_continuous_output.rb +1 -1
- data/app/lib/actions/proxy_action.rb +2 -12
- data/app/lib/actions/trigger_proxy_batch.rb +79 -0
- data/app/models/foreman_tasks/recurring_logic.rb +10 -0
- data/app/models/foreman_tasks/remote_task.rb +3 -19
- data/app/models/foreman_tasks/task.rb +29 -0
- data/app/models/foreman_tasks/triggering.rb +14 -4
- data/app/views/foreman_tasks/api/tasks/show.json.rabl +1 -1
- data/app/views/foreman_tasks/layouts/react.html.erb +0 -1
- data/app/views/foreman_tasks/recurring_logics/index.html.erb +4 -2
- data/app/views/foreman_tasks/task_groups/recurring_logic_task_groups/_recurring_logic_task_group.html.erb +8 -0
- data/db/migrate/20210720115251_add_purpose_to_recurring_logic.rb +6 -0
- data/extra/foreman-tasks-cleanup.sh +127 -0
- data/extra/foreman-tasks-export.sh +121 -0
- data/foreman-tasks.gemspec +1 -4
- data/lib/foreman_tasks/continuous_output.rb +50 -0
- data/lib/foreman_tasks/engine.rb +8 -15
- data/lib/foreman_tasks/tasks/export_tasks.rake +29 -8
- data/lib/foreman_tasks/version.rb +1 -1
- data/lib/foreman_tasks.rb +2 -5
- data/locale/fr/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/ja/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/zh_CN/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/package.json +7 -9
- data/test/controllers/api/tasks_controller_test.rb +19 -1
- data/test/controllers/tasks_controller_test.rb +19 -0
- data/test/factories/recurring_logic_factory.rb +7 -1
- data/test/graphql/mutations/recurring_logics/cancel_mutation_test.rb +66 -0
- data/test/graphql/queries/recurring_logic_test.rb +28 -0
- data/test/graphql/queries/recurring_logics_query_test.rb +30 -0
- data/test/graphql/queries/task_query_test.rb +33 -0
- data/test/graphql/queries/tasks_query_test.rb +31 -0
- data/test/support/dummy_proxy_action.rb +6 -0
- data/test/unit/actions/proxy_action_test.rb +11 -11
- data/test/unit/actions/trigger_proxy_batch_test.rb +59 -0
- data/test/unit/remote_task_test.rb +0 -8
- data/test/unit/task_test.rb +39 -8
- data/test/unit/triggering_test.rb +22 -0
- metadata +23 -26
- data/test/core/unit/dispatcher_test.rb +0 -43
- data/test/core/unit/runner_test.rb +0 -116
- data/test/core/unit/task_launcher_test.rb +0 -56
- data/test/foreman_tasks_core_test_helper.rb +0 -4
- data/test/unit/otp_manager_test.rb +0 -77
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'foreman_tasks_test_helper'
|
2
|
+
|
3
|
+
module Queries
|
4
|
+
class RecurringLogicTest < GraphQLQueryTestCase
|
5
|
+
let(:query) do
|
6
|
+
<<-GRAPHQL
|
7
|
+
query($id: String!) {
|
8
|
+
recurringLogic(id: $id) {
|
9
|
+
id
|
10
|
+
cronLine
|
11
|
+
}
|
12
|
+
}
|
13
|
+
GRAPHQL
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:cron_line) { '5 4 3 2 1' }
|
17
|
+
let(:recurring_logic) { FactoryBot.create(:recurring_logic, :cron_line => cron_line) }
|
18
|
+
let(:global_id) { Foreman::GlobalId.for(recurring_logic) }
|
19
|
+
let(:variables) { { id: global_id } }
|
20
|
+
let(:data) { result['data']['recurringLogic'] }
|
21
|
+
|
22
|
+
test "should fetch recurring logic" do
|
23
|
+
assert_empty result['errors']
|
24
|
+
assert_equal global_id, data['id']
|
25
|
+
assert_equal cron_line, data['cronLine']
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'foreman_tasks_test_helper'
|
2
|
+
|
3
|
+
module Queries
|
4
|
+
class RecurringLogicsTest < GraphQLQueryTestCase
|
5
|
+
let(:query) do
|
6
|
+
<<-GRAPHQL
|
7
|
+
query {
|
8
|
+
recurringLogics {
|
9
|
+
nodes {
|
10
|
+
id
|
11
|
+
cronLine
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
GRAPHQL
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:data) { result['data']['recurringLogics'] }
|
19
|
+
|
20
|
+
setup do
|
21
|
+
FactoryBot.create_list(:recurring_logic, 2)
|
22
|
+
end
|
23
|
+
|
24
|
+
test "should fetch recurring logics" do
|
25
|
+
assert_empty result['errors']
|
26
|
+
expected_count = ::ForemanTasks::RecurringLogic.count
|
27
|
+
assert_not_equal 0, expected_count
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'foreman_tasks_test_helper'
|
2
|
+
|
3
|
+
module Queries
|
4
|
+
class TaskQueryTest < GraphQLQueryTestCase
|
5
|
+
let(:query) do
|
6
|
+
<<-GRAPHQL
|
7
|
+
query (
|
8
|
+
$id: String!
|
9
|
+
) {
|
10
|
+
task(id: $id) {
|
11
|
+
id
|
12
|
+
action
|
13
|
+
result
|
14
|
+
}
|
15
|
+
}
|
16
|
+
GRAPHQL
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:res) { 'inconclusive' }
|
20
|
+
let(:task) { FactoryBot.create(:some_task, :result => res) }
|
21
|
+
|
22
|
+
let(:global_id) { Foreman::GlobalId.for(task) }
|
23
|
+
let(:variables) { { id: global_id } }
|
24
|
+
let(:data) { result['data']['task'] }
|
25
|
+
|
26
|
+
test 'should fetch task data' do
|
27
|
+
assert_empty result['errors']
|
28
|
+
|
29
|
+
assert_equal global_id, data['id']
|
30
|
+
assert_equal task.result, data['result']
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'foreman_tasks_test_helper'
|
2
|
+
|
3
|
+
module Queries
|
4
|
+
class TasksQueryTest < GraphQLQueryTestCase
|
5
|
+
let(:query) do
|
6
|
+
<<-GRAPHQL
|
7
|
+
query {
|
8
|
+
tasks {
|
9
|
+
nodes {
|
10
|
+
id
|
11
|
+
action
|
12
|
+
result
|
13
|
+
}
|
14
|
+
}
|
15
|
+
}
|
16
|
+
GRAPHQL
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:data) { result['data']['tasks'] }
|
20
|
+
|
21
|
+
setup do
|
22
|
+
FactoryBot.create_list(:some_task, 2)
|
23
|
+
end
|
24
|
+
|
25
|
+
test "should fetch recurring logics" do
|
26
|
+
assert_empty result['errors']
|
27
|
+
expected_count = ::ForemanTasks::Task.count
|
28
|
+
assert_not_equal 0, expected_count
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -36,6 +36,12 @@ module Support
|
|
36
36
|
def statuses
|
37
37
|
{ version: DummyProxyVersion.new('1.21.0') }
|
38
38
|
end
|
39
|
+
|
40
|
+
def launch_tasks(operation, args = {})
|
41
|
+
@log[:trigger_task] << [operation, args]
|
42
|
+
@task_triggered.fulfill(true)
|
43
|
+
{ 'task_id' => @uuid, 'result' => 'success' }
|
44
|
+
end
|
39
45
|
end
|
40
46
|
|
41
47
|
class ProxySelector < ::ForemanTasks::ProxySelector
|
@@ -11,12 +11,11 @@ module ForemanTasks
|
|
11
11
|
let(:batch_triggering) { false }
|
12
12
|
|
13
13
|
before do
|
14
|
-
Support::DummyProxyAction.any_instance.stubs(:with_batch_triggering?).returns(batch_triggering)
|
15
14
|
Support::DummyProxyAction.reset
|
16
15
|
RemoteTask.any_instance.stubs(:proxy).returns(Support::DummyProxyAction.proxy)
|
17
16
|
Setting.stubs(:[]).with('foreman_tasks_proxy_action_retry_interval')
|
18
17
|
Setting.stubs(:[]).with('foreman_tasks_proxy_action_retry_count')
|
19
|
-
Setting.stubs(:[]).with('foreman_tasks_proxy_batch_trigger')
|
18
|
+
Setting.stubs(:[]).with('foreman_tasks_proxy_batch_trigger').returns(batch_triggering)
|
20
19
|
@action = create_and_plan_action(Support::DummyProxyAction,
|
21
20
|
Support::DummyProxyAction.proxy,
|
22
21
|
'Proxy::DummyAction',
|
@@ -29,17 +28,18 @@ module ForemanTasks
|
|
29
28
|
describe 'first run' do
|
30
29
|
it 'triggers the corresponding action on the proxy' do
|
31
30
|
proxy_call = Support::DummyProxyAction.proxy.log[:trigger_task].first
|
32
|
-
expected_call = ['
|
33
|
-
{
|
34
|
-
|
35
|
-
'
|
31
|
+
expected_call = ['single',
|
32
|
+
{ :action_class => 'Proxy::DummyAction',
|
33
|
+
:action_input =>
|
34
|
+
{ 'foo' => 'bar',
|
35
|
+
'secrets' => secrets,
|
36
|
+
'connection_options' =>
|
36
37
|
{ 'retry_interval' => 15, 'retry_count' => 4,
|
37
38
|
'proxy_batch_triggering' => batch_triggering },
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
'callback' => { 'task_id' => Support::DummyProxyAction.proxy.uuid, 'step_id' => @action.run_step_id } }]
|
39
|
+
'use_batch_triggering' => batch_triggering,
|
40
|
+
'proxy_url' => 'proxy.example.com',
|
41
|
+
'proxy_action_name' => 'Proxy::DummyAction',
|
42
|
+
'callback' => { 'task_id' => Support::DummyProxyAction.proxy.uuid, 'step_id' => @action.run_step_id } } }]
|
43
43
|
_(proxy_call).must_equal(expected_call)
|
44
44
|
end
|
45
45
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'foreman_tasks_test_helper'
|
2
|
+
|
3
|
+
module ForemanTasks
|
4
|
+
class TriggerProxyBatchTest < ActiveSupport::TestCase
|
5
|
+
describe Actions::TriggerProxyBatch do
|
6
|
+
include ::Dynflow::Testing
|
7
|
+
|
8
|
+
let(:batch_size) { 20 }
|
9
|
+
let(:total_count) { 100 }
|
10
|
+
let(:action) { create_and_plan_action(Actions::TriggerProxyBatch, total_count: total_count, batch_size: batch_size) }
|
11
|
+
let(:triggered) { run_action(action) }
|
12
|
+
|
13
|
+
describe 'triggering' do
|
14
|
+
it 'doesnt run anything on trigger' do
|
15
|
+
Actions::TriggerProxyBatch.any_instance.expects(:trigger_remote_tasks_batch).never
|
16
|
+
_(triggered.state).must_equal :suspended
|
17
|
+
_(triggered.output[:planned_count]).must_equal 0
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'triggers remote tasks on TriggerNextBatch' do
|
21
|
+
Actions::TriggerProxyBatch.any_instance.expects(:trigger_remote_tasks_batch).once
|
22
|
+
run_action(triggered, Actions::TriggerProxyBatch::TriggerNextBatch[1])
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'triggers remote tasks on TriggerNextBatch defined number of times' do
|
26
|
+
Actions::TriggerProxyBatch.any_instance.expects(:trigger_remote_tasks_batch).twice
|
27
|
+
run_action(triggered, Actions::TriggerProxyBatch::TriggerNextBatch[2])
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'triggers the last batch on resume' do
|
31
|
+
Actions::TriggerProxyBatch.any_instance.expects(:trigger_remote_tasks_batch).once
|
32
|
+
triggered.output[:planned_count] = ((total_count - 1) / batch_size) * batch_size
|
33
|
+
run_action(triggered)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#trigger_remote_tasks_batch' do
|
38
|
+
let(:proxy_operation_name) { 'ansible_runner' }
|
39
|
+
let(:grouped_remote_batch) { Array.new(batch_size).map { |i| mock("RemoteTask#{i}") } }
|
40
|
+
let(:remote_tasks) do
|
41
|
+
m = mock('RemoteTaskARScope')
|
42
|
+
m.stubs(pending: m, order: m)
|
43
|
+
m.stubs(group_by: { proxy_operation_name => grouped_remote_batch })
|
44
|
+
m
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'fetches batch_size of tasks and triggers them' do
|
48
|
+
remote_tasks.expects(:first).with(batch_size).returns(remote_tasks)
|
49
|
+
remote_tasks.expects(:size).returns(batch_size)
|
50
|
+
triggered.expects(:remote_tasks).returns(remote_tasks)
|
51
|
+
ForemanTasks::RemoteTask.expects(:batch_trigger).with(proxy_operation_name, grouped_remote_batch)
|
52
|
+
|
53
|
+
triggered.trigger_remote_tasks_batch
|
54
|
+
_(triggered.output[:planned_count]).must_equal(batch_size)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -28,14 +28,6 @@ module ForemanTasks
|
|
28
28
|
_(remote_task.remote_task_id).must_equal((remote_task.id + 5).to_s)
|
29
29
|
end
|
30
30
|
end
|
31
|
-
|
32
|
-
it 'fallbacks to old way when batch trigger gets 404' do
|
33
|
-
fake_proxy = mock
|
34
|
-
fake_proxy.expects(:launch_tasks).raises(RestClient::NotFound.new)
|
35
|
-
remote_tasks.first.expects(:proxy).returns(fake_proxy)
|
36
|
-
remote_tasks.each { |task| task.expects(:trigger) }
|
37
|
-
RemoteTask.batch_trigger('a_operation', remote_tasks)
|
38
|
-
end
|
39
31
|
end
|
40
32
|
end
|
41
33
|
end
|
data/test/unit/task_test.rb
CHANGED
@@ -296,12 +296,12 @@ class TasksTest < ActiveSupport::TestCase
|
|
296
296
|
end
|
297
297
|
|
298
298
|
describe 'search for resource_ids' do
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
resource_type = 'restype1'
|
299
|
+
label = 'label1'
|
300
|
+
resource_ids = [1, 2]
|
301
|
+
resource_type = 'restype1'
|
303
302
|
|
304
|
-
|
303
|
+
let(:task1_old) do
|
304
|
+
FactoryBot.create(
|
305
305
|
:task_with_links,
|
306
306
|
started_at: '2019-10-01 11:15:55',
|
307
307
|
ended_at: '2019-10-01 11:15:57',
|
@@ -309,7 +309,9 @@ class TasksTest < ActiveSupport::TestCase
|
|
309
309
|
label: label,
|
310
310
|
resource_type: resource_type
|
311
311
|
)
|
312
|
-
|
312
|
+
end
|
313
|
+
let(:task1_new) do
|
314
|
+
FactoryBot.create(
|
313
315
|
:task_with_links,
|
314
316
|
started_at: '2019-10-02 11:15:55',
|
315
317
|
ended_at: '2019-10-02 11:15:57',
|
@@ -317,7 +319,9 @@ class TasksTest < ActiveSupport::TestCase
|
|
317
319
|
label: label,
|
318
320
|
resource_type: resource_type
|
319
321
|
)
|
320
|
-
|
322
|
+
end
|
323
|
+
let(:task2) do
|
324
|
+
FactoryBot.create(
|
321
325
|
:task_with_links,
|
322
326
|
started_at: '2019-10-03 11:15:55',
|
323
327
|
ended_at: '2019-10-03 11:15:57',
|
@@ -325,7 +329,9 @@ class TasksTest < ActiveSupport::TestCase
|
|
325
329
|
label: label,
|
326
330
|
resource_type: resource_type
|
327
331
|
)
|
328
|
-
|
332
|
+
end
|
333
|
+
let(:task3) do
|
334
|
+
FactoryBot.create(
|
329
335
|
:task_with_links,
|
330
336
|
started_at: '2019-10-03 11:15:55',
|
331
337
|
ended_at: '2019-10-03 11:15:57',
|
@@ -333,6 +339,13 @@ class TasksTest < ActiveSupport::TestCase
|
|
333
339
|
label: label,
|
334
340
|
resource_type: 'another_type'
|
335
341
|
)
|
342
|
+
end
|
343
|
+
|
344
|
+
it 'finds tasks' do
|
345
|
+
task1_old
|
346
|
+
task1_new
|
347
|
+
task2
|
348
|
+
task3
|
336
349
|
|
337
350
|
result = ForemanTasks::Task.search_for(
|
338
351
|
"resource_id ^ (#{resource_ids.join(',')}) and resource_type = #{resource_type}"
|
@@ -343,5 +356,23 @@ class TasksTest < ActiveSupport::TestCase
|
|
343
356
|
assert_includes result, task2
|
344
357
|
assert_not_includes result, task3
|
345
358
|
end
|
359
|
+
|
360
|
+
it 'finds latest task for each resource_id' do
|
361
|
+
task1_old
|
362
|
+
task1_new
|
363
|
+
task2
|
364
|
+
task3
|
365
|
+
|
366
|
+
result = ForemanTasks::Task.latest_tasks_by_resource_ids(
|
367
|
+
label,
|
368
|
+
resource_type,
|
369
|
+
resource_ids
|
370
|
+
)
|
371
|
+
assert_equal 2, result.length
|
372
|
+
assert_equal resource_ids, result.keys.sort
|
373
|
+
assert_equal task1_new, result[1]
|
374
|
+
assert_equal task2, result[2]
|
375
|
+
assert_not_includes result.values, task3
|
376
|
+
end
|
346
377
|
end
|
347
378
|
end
|
@@ -19,6 +19,28 @@ class TriggeringTest < ActiveSupport::TestCase
|
|
19
19
|
triggering.recurring_logic.stubs(:valid?).returns(false)
|
20
20
|
_(triggering).wont_be :valid?
|
21
21
|
end
|
22
|
+
|
23
|
+
it 'is valid when recurring logic has purpose' do
|
24
|
+
logic = FactoryBot.build(:recurring_logic, :purpose => 'test', :state => 'active')
|
25
|
+
triggering = FactoryBot.build(:triggering, :recurring_logic => logic, :mode => :recurring, :input_type => :cronline, :cronline => '* * * * *')
|
26
|
+
_(triggering).must_be :valid?
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'is invalid when recurring logic with given purpose exists' do
|
30
|
+
FactoryBot.create(:recurring_logic, :purpose => 'test', :state => 'active')
|
31
|
+
logic = FactoryBot.build(:recurring_logic, :purpose => 'test', :state => 'active')
|
32
|
+
triggering = FactoryBot.build(:triggering, :recurring_logic => logic, :mode => :recurring, :input_type => :cronline, :cronline => '* * * * *')
|
33
|
+
_(triggering).wont_be :valid?
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'is valid when recurring logic with given purpose exists and is not active or disabled' do
|
37
|
+
['finished', 'cancelled', 'failed'].each do |item|
|
38
|
+
FactoryBot.create(:recurring_logic, :purpose => 'test', :state => item)
|
39
|
+
end
|
40
|
+
logic = FactoryBot.build(:recurring_logic, :purpose => 'test')
|
41
|
+
triggering = FactoryBot.build(:triggering, :recurring_logic => logic, :mode => :recurring, :input_type => :cronline, :cronline => '* * * * *')
|
42
|
+
_(triggering).must_be :valid?
|
43
|
+
end
|
22
44
|
end
|
23
45
|
|
24
46
|
it 'cannot have mode set to arbitrary value' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman-tasks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.2.0
|
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: 2021-
|
11
|
+
date: 2021-11-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dynflow
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.2.3
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: foreman-tasks-core
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: get_process_mem
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -147,6 +133,10 @@ files:
|
|
147
133
|
- app/controllers/foreman_tasks/react_controller.rb
|
148
134
|
- app/controllers/foreman_tasks/recurring_logics_controller.rb
|
149
135
|
- app/controllers/foreman_tasks/tasks_controller.rb
|
136
|
+
- app/graphql/mutations/recurring_logics/cancel.rb
|
137
|
+
- app/graphql/types/recurring_logic.rb
|
138
|
+
- app/graphql/types/task.rb
|
139
|
+
- app/graphql/types/triggering.rb
|
150
140
|
- app/helpers/foreman_tasks/foreman_tasks_helper.rb
|
151
141
|
- app/helpers/foreman_tasks/tasks_helper.rb
|
152
142
|
- app/lib/actions/action_with_sub_plans.rb
|
@@ -176,6 +166,7 @@ files:
|
|
176
166
|
- app/lib/actions/proxy_action.rb
|
177
167
|
- app/lib/actions/recurring_action.rb
|
178
168
|
- app/lib/actions/serializers/active_record_serializer.rb
|
169
|
+
- app/lib/actions/trigger_proxy_batch.rb
|
179
170
|
- app/lib/foreman_tasks/concerns/polling_action_extensions.rb
|
180
171
|
- app/lib/proxy_api/foreman_dynflow/dynflow_proxy.rb
|
181
172
|
- app/models/foreman_tasks/concerns/action_subject.rb
|
@@ -259,6 +250,7 @@ files:
|
|
259
250
|
- db/migrate/20200517215015_rename_bookmarks_controller.rb
|
260
251
|
- db/migrate/20200519093217_drop_dynflow_allow_dangerous_actions_setting.foreman_tasks.rb
|
261
252
|
- db/migrate/20200611090846_add_task_lock_index_on_resource_type_and_task_id.rb
|
253
|
+
- db/migrate/20210720115251_add_purpose_to_recurring_logic.rb
|
262
254
|
- db/seeds.d/20-foreman_tasks_permissions.rb
|
263
255
|
- db/seeds.d/30-notification_blueprints.rb
|
264
256
|
- db/seeds.d/60-dynflow_proxy_feature.rb
|
@@ -267,12 +259,15 @@ files:
|
|
267
259
|
- deploy/foreman-tasks.sysconfig
|
268
260
|
- extra/dynflow-debug.sh
|
269
261
|
- extra/dynflow-executor.example
|
262
|
+
- extra/foreman-tasks-cleanup.sh
|
263
|
+
- extra/foreman-tasks-export.sh
|
270
264
|
- foreman-tasks.gemspec
|
271
265
|
- gemfile.d/foreman-tasks.rb
|
272
266
|
- lib/foreman-tasks.rb
|
273
267
|
- lib/foreman_tasks.rb
|
274
268
|
- lib/foreman_tasks/authorizer_ext.rb
|
275
269
|
- lib/foreman_tasks/cleaner.rb
|
270
|
+
- lib/foreman_tasks/continuous_output.rb
|
276
271
|
- lib/foreman_tasks/dynflow.rb
|
277
272
|
- lib/foreman_tasks/dynflow/configuration.rb
|
278
273
|
- lib/foreman_tasks/dynflow/console_authorizer.rb
|
@@ -306,14 +301,15 @@ files:
|
|
306
301
|
- test/controllers/api/tasks_controller_test.rb
|
307
302
|
- test/controllers/recurring_logics_controller_test.rb
|
308
303
|
- test/controllers/tasks_controller_test.rb
|
309
|
-
- test/core/unit/dispatcher_test.rb
|
310
|
-
- test/core/unit/runner_test.rb
|
311
|
-
- test/core/unit/task_launcher_test.rb
|
312
304
|
- test/factories/recurring_logic_factory.rb
|
313
305
|
- test/factories/task_factory.rb
|
314
306
|
- test/factories/triggering_factory.rb
|
315
|
-
- test/foreman_tasks_core_test_helper.rb
|
316
307
|
- test/foreman_tasks_test_helper.rb
|
308
|
+
- test/graphql/mutations/recurring_logics/cancel_mutation_test.rb
|
309
|
+
- test/graphql/queries/recurring_logic_test.rb
|
310
|
+
- test/graphql/queries/recurring_logics_query_test.rb
|
311
|
+
- test/graphql/queries/task_query_test.rb
|
312
|
+
- test/graphql/queries/tasks_query_test.rb
|
317
313
|
- test/helpers/foreman_tasks/foreman_tasks_helper_test.rb
|
318
314
|
- test/helpers/foreman_tasks/tasks_helper_test.rb
|
319
315
|
- test/lib/actions/middleware/keep_current_request_id_test.rb
|
@@ -332,11 +328,11 @@ files:
|
|
332
328
|
- test/unit/actions/bulk_action_test.rb
|
333
329
|
- test/unit/actions/proxy_action_test.rb
|
334
330
|
- test/unit/actions/recurring_action_test.rb
|
331
|
+
- test/unit/actions/trigger_proxy_batch_test.rb
|
335
332
|
- test/unit/cleaner_test.rb
|
336
333
|
- test/unit/config/environment.rb
|
337
334
|
- test/unit/dynflow_console_authorizer_test.rb
|
338
335
|
- test/unit/locking_test.rb
|
339
|
-
- test/unit/otp_manager_test.rb
|
340
336
|
- test/unit/proxy_selector_test.rb
|
341
337
|
- test/unit/recurring_logic_test.rb
|
342
338
|
- test/unit/remote_task_test.rb
|
@@ -620,14 +616,15 @@ test_files:
|
|
620
616
|
- test/controllers/api/tasks_controller_test.rb
|
621
617
|
- test/controllers/recurring_logics_controller_test.rb
|
622
618
|
- test/controllers/tasks_controller_test.rb
|
623
|
-
- test/core/unit/dispatcher_test.rb
|
624
|
-
- test/core/unit/runner_test.rb
|
625
|
-
- test/core/unit/task_launcher_test.rb
|
626
619
|
- test/factories/recurring_logic_factory.rb
|
627
620
|
- test/factories/task_factory.rb
|
628
621
|
- test/factories/triggering_factory.rb
|
629
|
-
- test/foreman_tasks_core_test_helper.rb
|
630
622
|
- test/foreman_tasks_test_helper.rb
|
623
|
+
- test/graphql/mutations/recurring_logics/cancel_mutation_test.rb
|
624
|
+
- test/graphql/queries/recurring_logic_test.rb
|
625
|
+
- test/graphql/queries/recurring_logics_query_test.rb
|
626
|
+
- test/graphql/queries/task_query_test.rb
|
627
|
+
- test/graphql/queries/tasks_query_test.rb
|
631
628
|
- test/helpers/foreman_tasks/foreman_tasks_helper_test.rb
|
632
629
|
- test/helpers/foreman_tasks/tasks_helper_test.rb
|
633
630
|
- test/lib/actions/middleware/keep_current_request_id_test.rb
|
@@ -646,11 +643,11 @@ test_files:
|
|
646
643
|
- test/unit/actions/bulk_action_test.rb
|
647
644
|
- test/unit/actions/proxy_action_test.rb
|
648
645
|
- test/unit/actions/recurring_action_test.rb
|
646
|
+
- test/unit/actions/trigger_proxy_batch_test.rb
|
649
647
|
- test/unit/cleaner_test.rb
|
650
648
|
- test/unit/config/environment.rb
|
651
649
|
- test/unit/dynflow_console_authorizer_test.rb
|
652
650
|
- test/unit/locking_test.rb
|
653
|
-
- test/unit/otp_manager_test.rb
|
654
651
|
- test/unit/proxy_selector_test.rb
|
655
652
|
- test/unit/recurring_logic_test.rb
|
656
653
|
- test/unit/remote_task_test.rb
|
@@ -1,43 +0,0 @@
|
|
1
|
-
require 'foreman_tasks_core_test_helper'
|
2
|
-
require 'foreman_tasks/test_helpers'
|
3
|
-
require 'foreman_tasks_core/runner'
|
4
|
-
|
5
|
-
module ForemanTasksCore
|
6
|
-
module Runner
|
7
|
-
describe Dispatcher::RunnerActor do
|
8
|
-
include ForemanTasks::TestHelpers::WithInThreadExecutor
|
9
|
-
|
10
|
-
let(:dispatcher) { Dispatcher.instance }
|
11
|
-
let(:suspended_action) { mock }
|
12
|
-
let(:runner) { mock.tap { |r| r.stubs(:id) } }
|
13
|
-
let(:clock) { ForemanTasks.dynflow.world.clock }
|
14
|
-
let(:logger) { mock.tap { |l| l.stubs(:debug) } }
|
15
|
-
let(:actor) do
|
16
|
-
Dispatcher::RunnerActor.new dispatcher, suspended_action, runner, clock, logger
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'delivers all updates to actions' do
|
20
|
-
targets = (0..2).map { mock }.each_with_index { |mock, index| mock.expects(:<<).with(index) }
|
21
|
-
updates = targets.each_with_index.reduce({}) { |acc, (cur, index)| acc.merge(cur => index) }
|
22
|
-
runner.expects(:run_refresh).returns(updates)
|
23
|
-
actor.expects(:plan_next_refresh)
|
24
|
-
actor.refresh_runner
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'plans next refresh' do
|
28
|
-
runner.expects(:run_refresh).returns({})
|
29
|
-
actor.expects(:plan_next_refresh)
|
30
|
-
actor.refresh_runner
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'does not plan next resfresh if done' do
|
34
|
-
update = Update.new(nil, 0)
|
35
|
-
suspended_action.expects(:<<).with(update)
|
36
|
-
runner.expects(:run_refresh).returns(suspended_action => update)
|
37
|
-
dispatcher.expects(:finish)
|
38
|
-
dispatcher.ticker.expects(:tell).never
|
39
|
-
actor.refresh_runner
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,116 +0,0 @@
|
|
1
|
-
require 'foreman_tasks_core_test_helper'
|
2
|
-
require 'foreman_tasks/test_helpers'
|
3
|
-
require 'foreman_tasks_core/runner'
|
4
|
-
require 'ostruct'
|
5
|
-
|
6
|
-
module ForemanTasksCore
|
7
|
-
module Runner
|
8
|
-
class RunnerTest < ActiveSupport::TestCase
|
9
|
-
include ForemanTasks::TestHelpers::WithInThreadExecutor
|
10
|
-
|
11
|
-
describe Base do
|
12
|
-
let(:suspended_action) { Class.new }
|
13
|
-
let(:runner) { Base.new suspended_action: suspended_action }
|
14
|
-
|
15
|
-
describe '#generate_updates' do
|
16
|
-
it 'returns empty hash when there are no outputs' do
|
17
|
-
_(runner.generate_updates).must_be :empty?
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'returns a hash with outputs' do
|
21
|
-
message = 'a message'
|
22
|
-
type = 'stdout'
|
23
|
-
runner.publish_data(message, type)
|
24
|
-
updates = runner.generate_updates
|
25
|
-
_(updates.keys).must_equal [suspended_action]
|
26
|
-
update = updates.values.first
|
27
|
-
_(update.exit_status).must_be :nil?
|
28
|
-
_(update.continuous_output.raw_outputs.count).must_equal 1
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'works in compatibility mode' do
|
32
|
-
runner = Base.new
|
33
|
-
message = 'a message'
|
34
|
-
type = 'stdout'
|
35
|
-
runner.publish_data(message, type)
|
36
|
-
updates = runner.generate_updates
|
37
|
-
_(updates.keys).must_equal [nil]
|
38
|
-
update = updates.values.first
|
39
|
-
_(update.exit_status).must_be :nil?
|
40
|
-
_(update.continuous_output.raw_outputs.count).must_equal 1
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
describe Parent do
|
46
|
-
let(:suspended_action) { ::Dynflow::Action::Suspended.allocate }
|
47
|
-
let(:runner) { Parent.new targets, suspended_action: suspended_action }
|
48
|
-
let(:targets) do
|
49
|
-
{ 'foo' => { 'execution_plan_id' => '123', 'run_step_id' => 2 },
|
50
|
-
'bar' => { 'execution_plan_id' => '456', 'run_step_id' => 2 } }
|
51
|
-
end
|
52
|
-
|
53
|
-
describe '#initialize_continuous_outputs' do
|
54
|
-
it 'initializes outputs for targets and parent' do
|
55
|
-
outputs = runner.initialize_continuous_outputs
|
56
|
-
_(outputs.keys.count).must_equal 2
|
57
|
-
outputs.values.each { |output| _(output).must_be_instance_of ContinuousOutput }
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
describe '#generate_updates' do
|
62
|
-
it 'returns only updates for hosts with pending outputs' do
|
63
|
-
_(runner.generate_updates).must_equal({})
|
64
|
-
runner.publish_data_for('foo', 'something', 'something')
|
65
|
-
updates = runner.generate_updates
|
66
|
-
_(updates.keys.count).must_equal 1
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'works without compatibility mode' do
|
70
|
-
runner.broadcast_data('something', 'stdout')
|
71
|
-
updates = runner.generate_updates
|
72
|
-
_(updates.keys.count).must_equal 2
|
73
|
-
updates.keys.each do |key|
|
74
|
-
_(key).must_be_instance_of ::Dynflow::Action::Suspended
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
describe '#publish_data_for' do
|
80
|
-
it 'publishes data for a single host' do
|
81
|
-
runner.publish_data_for('foo', 'message', 'stdout')
|
82
|
-
_(runner.generate_updates.keys.count).must_equal 1
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
describe '#broadcast_data' do
|
87
|
-
it 'publishes data for all hosts' do
|
88
|
-
runner.broadcast_data('message', 'stdout')
|
89
|
-
_(runner.generate_updates.keys.count).must_equal 2
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
describe '#publish_exception' do
|
94
|
-
let(:exception) do
|
95
|
-
exception = RuntimeError.new
|
96
|
-
exception.stubs(:backtrace).returns([])
|
97
|
-
exception
|
98
|
-
end
|
99
|
-
|
100
|
-
before { runner.logger.stubs(:error) }
|
101
|
-
|
102
|
-
it 'broadcasts the exception to all targets' do
|
103
|
-
runner.expects(:publish_exit_status).never
|
104
|
-
runner.publish_exception('general failure', exception, false)
|
105
|
-
_(runner.generate_updates.keys.count).must_equal 2
|
106
|
-
end
|
107
|
-
|
108
|
-
it 'publishes exit status if fatal' do
|
109
|
-
runner.expects(:publish_exit_status)
|
110
|
-
runner.publish_exception('general failure', exception, true)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|