foreman-tasks 4.1.5 → 5.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|