foreman_remote_execution 14.0.2 → 14.1.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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/api/v2/job_invocations_controller.rb +34 -17
  3. data/app/helpers/remote_execution_helper.rb +2 -2
  4. data/app/lib/actions/remote_execution/proxy_action.rb +10 -5
  5. data/app/lib/actions/remote_execution/run_host_job.rb +1 -1
  6. data/app/lib/actions/remote_execution/template_invocation_progress_logging.rb +2 -3
  7. data/app/views/api/v2/job_invocations/hosts.json.rabl +15 -0
  8. data/config/routes.rb +1 -0
  9. data/db/migrate/20240312133027_extend_template_invocation_events.rb +19 -0
  10. data/lib/foreman_remote_execution/version.rb +1 -1
  11. data/webpack/JobInvocationDetail/JobInvocationActions.js +1 -1
  12. data/webpack/JobInvocationDetail/JobInvocationConstants.js +84 -0
  13. data/webpack/JobInvocationDetail/JobInvocationDetail.scss +0 -1
  14. data/webpack/JobInvocationDetail/JobInvocationHostTable.js +210 -0
  15. data/webpack/JobInvocationDetail/JobInvocationSelectors.js +2 -2
  16. data/webpack/JobInvocationDetail/__tests__/MainInformation.test.js +5 -1
  17. data/webpack/JobInvocationDetail/__tests__/fixtures.js +9 -0
  18. data/webpack/JobInvocationDetail/index.js +56 -34
  19. data/webpack/__mocks__/foremanReact/components/HostDetails/DetailsCard/DefaultLoaderEmptyState.js +1 -2
  20. data/webpack/react_app/components/RecentJobsCard/JobStatusIcon.js +38 -7
  21. data/webpack/react_app/components/RecentJobsCard/constants.js +4 -0
  22. data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostStatus.test.js.snap +1 -1
  23. data/webpack/react_app/components/TargetingHosts/components/HostStatus.js +6 -6
  24. metadata +6 -94
  25. data/.babelrc.js +0 -3
  26. data/.eslintignore +0 -3
  27. data/.eslintrc +0 -13
  28. data/.github/workflows/js_ci.yml +0 -32
  29. data/.github/workflows/release.yml +0 -16
  30. data/.github/workflows/ruby_ci.yml +0 -19
  31. data/.gitignore +0 -19
  32. data/.packit.yaml +0 -45
  33. data/.prettierrc +0 -4
  34. data/.rubocop.yml +0 -105
  35. data/.rubocop_todo.yml +0 -516
  36. data/.tx/config +0 -10
  37. data/Gemfile +0 -5
  38. data/app/mailers/.gitkeep +0 -0
  39. data/app/views/dashboard/.gitkeep +0 -0
  40. data/foreman_remote_execution.gemspec +0 -33
  41. data/jsconfig.json +0 -8
  42. data/test/benchmark/run_hosts_job_benchmark.rb +0 -70
  43. data/test/benchmark/targeting_benchmark.rb +0 -31
  44. data/test/factories/foreman_remote_execution_factories.rb +0 -147
  45. data/test/functional/api/v2/foreign_input_sets_controller_test.rb +0 -58
  46. data/test/functional/api/v2/job_invocations_controller_test.rb +0 -446
  47. data/test/functional/api/v2/job_templates_controller_test.rb +0 -110
  48. data/test/functional/api/v2/registration_controller_test.rb +0 -73
  49. data/test/functional/api/v2/remote_execution_features_controller_test.rb +0 -34
  50. data/test/functional/api/v2/template_invocations_controller_test.rb +0 -33
  51. data/test/functional/cockpit_controller_test.rb +0 -16
  52. data/test/functional/job_invocations_controller_test.rb +0 -132
  53. data/test/functional/job_templates_controller_test.rb +0 -31
  54. data/test/functional/ui_job_wizard_controller_test.rb +0 -16
  55. data/test/graphql/mutations/job_invocations/create_test.rb +0 -58
  56. data/test/graphql/queries/job_invocation_query_test.rb +0 -31
  57. data/test/graphql/queries/job_invocations_query_test.rb +0 -35
  58. data/test/helpers/remote_execution_helper_test.rb +0 -46
  59. data/test/support/remote_execution_helper.rb +0 -5
  60. data/test/test_plugin_helper.rb +0 -9
  61. data/test/unit/actions/run_host_job_test.rb +0 -115
  62. data/test/unit/actions/run_hosts_job_test.rb +0 -214
  63. data/test/unit/api_params_test.rb +0 -25
  64. data/test/unit/concerns/foreman_tasks_cleaner_extensions_test.rb +0 -29
  65. data/test/unit/concerns/host_extensions_test.rb +0 -219
  66. data/test/unit/concerns/nic_extensions_test.rb +0 -9
  67. data/test/unit/execution_task_status_mapper_test.rb +0 -92
  68. data/test/unit/input_template_renderer_test.rb +0 -503
  69. data/test/unit/job_invocation_composer_test.rb +0 -974
  70. data/test/unit/job_invocation_report_template_test.rb +0 -60
  71. data/test/unit/job_invocation_test.rb +0 -232
  72. data/test/unit/job_template_effective_user_test.rb +0 -37
  73. data/test/unit/job_template_test.rb +0 -316
  74. data/test/unit/remote_execution_feature_test.rb +0 -86
  75. data/test/unit/remote_execution_provider_test.rb +0 -298
  76. data/test/unit/renderer_scope_input_test.rb +0 -49
  77. data/test/unit/targeting_test.rb +0 -206
  78. data/test/unit/template_invocation_input_value_test.rb +0 -38
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_plugin_helper'
4
-
5
- module Api
6
- module V2
7
- class TemplateInvocationsControllerTest < ActionController::TestCase
8
- setup do
9
- @job = FactoryBot.create(:job_invocation, :with_template, :with_task)
10
- @template_invocation = @job.template_invocations.first
11
- end
12
-
13
- test 'should get template invocations belonging to job invocation' do
14
- get :template_invocations, params: { :id => @job.id }
15
- invocations = ActiveSupport::JSON.decode(@response.body)
16
- assert_equal @job.template_invocations.count, invocations['results'].count
17
- assert_equal @job.template_invocations.count, invocations['total']
18
-
19
- expected_result = {
20
- 'id' => @template_invocation.id,
21
- 'host_id' => @template_invocation.host_id,
22
- 'host_name' => @template_invocation.host.name,
23
- 'template_id' => @template_invocation.template_id,
24
- 'effective_user' => @template_invocation.effective_user,
25
- 'job_invocation_id' => @job.id,
26
- 'run_host_job_task_id' => @template_invocation.run_host_job_task_id,
27
- }
28
- assert_equal [expected_result], invocations['results']
29
- assert_response :success
30
- end
31
- end
32
- end
33
- end
@@ -1,16 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class CockpitControllerTest < ActionController::TestCase
4
- def setup
5
- as_admin do
6
- @host = FactoryBot.create(:host)
7
- end
8
- end
9
-
10
- test "should get host_ssh_params" do
11
- get :host_ssh_params, params: { id: @host.id }, session: set_session_user
12
- assert_response :success
13
- response = ActiveSupport::JSON.decode(@response.body)
14
- assert response.key?('ssh_user'), 'ssh_params response must include ssh_user'
15
- end
16
- end
@@ -1,132 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_plugin_helper'
4
- require_relative '../support/remote_execution_helper'
5
-
6
- class JobInvocationsControllerTest < ActionController::TestCase
7
- test 'should parse inputs coming from the URL params' do
8
- template = FactoryBot.create(:job_template, :with_input)
9
- feature = FactoryBot.create(:remote_execution_feature,
10
- :job_template => template)
11
- params = {
12
- feature: feature.label,
13
- inputs: { template.template_inputs.first.name => 'foobar' },
14
- }
15
-
16
- get :new, params: params, session: set_session_user
17
- template_invocation_params = [
18
- {
19
- 'input_values' =>
20
- [
21
- {
22
- 'value' => 'foobar',
23
- 'template_input_id' => template.template_inputs.first.id,
24
- },
25
- ],
26
- 'template_id' => template.id,
27
- },
28
- ]
29
- assert_equal(template_invocation_params,
30
- assigns(:composer).params['template_invocations'])
31
- end
32
-
33
- test 'should allow no inputs' do
34
- template = FactoryBot.create(:job_template)
35
- feature = FactoryBot.create(:remote_execution_feature,
36
- :job_template => template)
37
- params = {
38
- feature: feature.label,
39
- }
40
- get :new, params: params, session: set_session_user
41
- template_invocation_params = [
42
- {
43
- 'template_id' => template.id,
44
- 'input_values' => {},
45
- },
46
- ]
47
- assert_equal(template_invocation_params,
48
- assigns(:composer).params['template_invocations'])
49
- end
50
-
51
- test 'new via GET and POST' do
52
- template = FactoryBot.create(:job_template, :with_input)
53
- feature = FactoryBot.create(:remote_execution_feature, job_template: template)
54
- params = { feature: feature.label, inputs: { template.template_inputs.first.name => 'foobar' } }
55
-
56
- get :new, params: params, session: set_session_user
57
- assert_response :success
58
-
59
- post :new, params: params, session: set_session_user
60
- assert_response :success
61
- end
62
-
63
- context 'restricted access' do
64
- setup do
65
- @admin = users(:admin)
66
- @user = FactoryBot.create(:user, mail: 'test23@test.foreman.com', admin: false)
67
- @invocation = FactoryBot.create(:job_invocation, :with_template, :with_task)
68
- @invocation2 = FactoryBot.create(:job_invocation, :with_template, :with_task)
69
-
70
- @invocation.task.update(user: @admin)
71
- @invocation2.task.update(user: @user)
72
-
73
- setup_user 'view', 'hosts', nil, @user
74
- setup_user 'view', 'job_invocations', 'user = current_user', @user
75
- setup_user 'create', 'job_invocations', 'user = current_user', @user
76
- setup_user 'cancel', 'job_invocations', 'user = current_user', @user
77
- end
78
-
79
- context 'without user filter' do
80
- test '#index' do
81
- get :index, session: prepare_user(@admin)
82
- assert_response :success
83
- assert 2, assigns(:job_invocations).size
84
- end
85
-
86
- test '#show' do
87
- get :show, params: { id: @invocation2.id }, session: prepare_user(@admin)
88
- assert_response :success
89
- end
90
-
91
- test '#rerun' do
92
- get :rerun, params: { id: @invocation2.id }, session: prepare_user(@admin)
93
- assert_response :success
94
- end
95
-
96
- test '#cancel' do
97
- ForemanTasks::Task.any_instance.expects(:cancel).returns(true)
98
- post :cancel, params: { id: @invocation2.id }, session: prepare_user(@admin)
99
- assert_response :redirect
100
- end
101
- end
102
-
103
- context 'with user filter' do
104
- test '#index' do
105
- get :index, session: prepare_user(@user)
106
- assert_response :success
107
- assert_equal 1, assigns(:job_invocations).size
108
- assert_equal @invocation2, assigns(:job_invocations)[0]
109
- end
110
-
111
- test '#show' do
112
- get :show, params: { id: @invocation.id }, session: prepare_user(@user)
113
- assert_response :not_found
114
- end
115
-
116
- test '#rerun' do
117
- get :rerun, params: { id: @invocation.id }, session: prepare_user(@user)
118
- assert_response :not_found
119
- end
120
-
121
- test 'cancel' do
122
- post :cancel, params: { id: @invocation.id }, session: prepare_user(@user)
123
- assert_response :not_found
124
- end
125
- end
126
- end
127
-
128
- def prepare_user(user)
129
- User.current = user
130
- set_session_user(user)
131
- end
132
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_plugin_helper'
4
-
5
- class JobTemplatesControllerTest < ActionController::TestCase
6
- context '#preview' do
7
- let(:template) { FactoryBot.create(:job_template) }
8
- let(:host) { FactoryBot.create(:host, :managed) }
9
-
10
- test 'should render a preview version of a template' do
11
- post :preview, params: { job_template: template.to_param, template: 'uptime' }, session: set_session_user
12
- assert_response :success
13
- end
14
-
15
- test 'should render a preview version of a template for a specific host' do
16
- post :preview, params: {
17
- job_template: template.to_param,
18
- template: '<%= @host.name %>',
19
- preview_host_id: host.id,
20
- }, session: set_session_user
21
- assert_response :success
22
- assert_equal host.name, @response.body
23
- end
24
-
25
- test 'should render a error message when template has errors' do
26
- InputTemplateRenderer.any_instance.stubs(:render).returns(false)
27
- post :preview, params: { job_template: template.to_param }, session: set_session_user
28
- assert_response :not_acceptable
29
- end
30
- end
31
- end
@@ -1,16 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class UIJobWizardControllerTest < ActionController::TestCase
4
- def setup
5
- FactoryBot.create(:job_template, :job_category => 'cat1')
6
- FactoryBot.create(:job_template, :job_category => 'cat2')
7
- FactoryBot.create(:job_template, :job_category => 'cat2')
8
- end
9
-
10
- test 'should respond with categories' do
11
- get :categories, :params => {}, :session => set_session_user
12
- assert_response :success
13
- res = JSON.parse @response.body
14
- assert_equal ['cat1','cat2'], res['job_categories']
15
- end
16
- end
@@ -1,58 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- module Mutations
4
- module JobInvocations
5
- class CreateMutationTest < ActiveSupport::TestCase
6
- let(:host) { FactoryBot.create(:host) }
7
- let(:job_template) { FactoryBot.create(:job_template, :with_input) }
8
- let(:cron_line) { '5 * * * *' }
9
- let(:purpose) { 'test' }
10
- let(:variables) do
11
- {
12
- jobInvocation: {
13
- hostIds: [host.id],
14
- jobTemplateId: job_template.id,
15
- targetingType: 'static_query',
16
- inputs: { job_template.template_inputs.first.name => "bar" },
17
- recurrence: {
18
- cronLine: cron_line,
19
- purpose: purpose,
20
- },
21
- },
22
- }
23
- end
24
-
25
- let(:query) do
26
- <<-GRAPHQL
27
- mutation CreateJobInvocation($jobInvocation: JobInvocationInput!) {
28
- createJobInvocation(input: { jobInvocation: $jobInvocation }) {
29
- jobInvocation {
30
- id
31
- description
32
- recurringLogic {
33
- cronLine
34
- purpose
35
- }
36
- }
37
- }
38
- }
39
- GRAPHQL
40
- end
41
-
42
- context 'with admin user' do
43
- let(:user) { FactoryBot.create(:user, :admin) }
44
- let(:context) { { current_user: user } }
45
-
46
- test 'create a job invocation' do
47
- assert_difference('JobInvocation.count', +1) do
48
- result = ForemanGraphqlSchema.execute(query, variables: variables, context: context)
49
- assert_empty result['errors']
50
- assert_empty result['data']['createJobInvocation']['jobInvocation']['errors']
51
- assert_equal cron_line, result['data']['createJobInvocation']['jobInvocation']['recurringLogic']['cronLine']
52
- assert_equal purpose, result['data']['createJobInvocation']['jobInvocation']['recurringLogic']['purpose']
53
- end
54
- end
55
- end
56
- end
57
- end
58
- end
@@ -1,31 +0,0 @@
1
- require 'test_helper'
2
-
3
- module Queries
4
- class JobInvocationQueryTest < GraphQLQueryTestCase
5
- let(:query) do
6
- <<-GRAPHQL
7
- query (
8
- $id: String!
9
- ) {
10
- jobInvocation(id: $id) {
11
- id
12
- jobCategory
13
- }
14
- }
15
- GRAPHQL
16
- end
17
-
18
- let(:job_invocation) { FactoryBot.create(:job_invocation) }
19
-
20
- let(:global_id) { Foreman::GlobalId.for(job_invocation) }
21
- let(:variables) { { id: global_id } }
22
- let(:data) { result['data']['jobInvocation'] }
23
-
24
- test 'fetching job invocation attributes' do
25
- assert_empty result['errors']
26
-
27
- assert_equal global_id, data['id']
28
- assert_equal job_invocation.job_category, data['jobCategory']
29
- end
30
- end
31
- end
@@ -1,35 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- module Queries
4
- class JobInvocationsQueryTest < GraphQLQueryTestCase
5
- let(:query) do
6
- <<-GRAPHQL
7
- query {
8
- jobInvocations {
9
- totalCount
10
- nodes {
11
- id
12
- jobCategory
13
- }
14
- }
15
- }
16
- GRAPHQL
17
- end
18
-
19
- let(:data) { result['data']['jobInvocations'] }
20
-
21
- setup do
22
- FactoryBot.create_list(:job_invocation, 2)
23
- end
24
-
25
- test 'should fetch job invocations' do
26
- assert_empty result['errors']
27
-
28
- expected_count = JobInvocation.count
29
-
30
- assert_not_equal 0, expected_count
31
- assert_equal expected_count, data['totalCount']
32
- assert_equal expected_count, data['nodes'].count
33
- end
34
- end
35
- end
@@ -1,46 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class RemoteExecutionHelperTest < ActionView::TestCase
4
- describe '#normalize_line_sets' do
5
- let :line_sets do
6
- [{"output_type"=>"stdout", "output"=>"one", "timestamp"=>1},
7
- {"output_type"=>"stdout", "output"=>"\r\ntwo\r\n", "timestamp"=>2},
8
- {"output_type"=>"stdout", "output"=>"\r\nthr", "timestamp"=>3},
9
- {"output_type"=>"stdout", "output"=>"ee\r\nfour\r\n", "timestamp"=>4},
10
- {"output_type"=>"stdout", "output"=>"\r\n\r\n", "timestamp"=>5},
11
- {"output_type"=>"stdout", "output"=>"five\r\n", "timestamp"=>6},
12
- {"output_type"=>"stdout", "output"=>"Exit status: 0", "timestamp"=>7}]
13
- end
14
-
15
- it 'ensures the line sets end with new line' do
16
- new_line_sets = normalize_line_sets(line_sets)
17
- expected_output = ["one\r\n",
18
- "two\r\n",
19
- "\r\nthree\r\n",
20
- "four\r\n",
21
- "\r\n\r\n",
22
- "five\r\n",
23
- "Exit status: 0"]
24
- assert_equal(expected_output, new_line_sets.map { |s| s['output'] })
25
- end
26
- end
27
-
28
- describe 'test correct setting' do
29
- it 'should found correct template from setting' do
30
- template_name = 'Job Invocation Report Template'
31
- setting_key = 'remote_execution_job_invocation_report_template'
32
- template = FactoryBot.create(:report_template, name: template_name)
33
- input = FactoryBot.create(:template_input, name: 'job_id', input_type: 'user')
34
- template.template_inputs << input
35
- Setting.expects(:[]).with(setting_key).returns(template_name)
36
-
37
- found_template = job_report_template
38
-
39
- assert_equal template.id, found_template.id
40
- end
41
-
42
- it 'should not crash if the template cannot be found' do
43
- assert_nil job_report_template
44
- end
45
- end
46
- end
@@ -1,5 +0,0 @@
1
- module RemoteExecutionHelper
2
- def job_invocation_task_buttons(task)
3
- return []
4
- end
5
- end
@@ -1,9 +0,0 @@
1
- # This calls the main test_helper in Foreman-core
2
- require 'test_helper'
3
- require 'dynflow/testing'
4
-
5
- # Add plugin to FactoryBot's paths
6
- FactoryBot.definition_file_paths << File.join(File.dirname(__FILE__), 'factories')
7
- # Add foreman tasks factories too
8
- FactoryBot.definition_file_paths << "#{ForemanTasks::Engine.root}/test/factories"
9
- FactoryBot.reload
@@ -1,115 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- module ForemanRemoteExecution
4
- class RunHostJobTest < ActiveSupport::TestCase
5
- include Dynflow::Testing
6
-
7
- subject { create_action(Actions::RemoteExecution::RunHostJob) }
8
-
9
- describe '#secrets' do
10
- let(:job_invocation) { FactoryBot.create(:job_invocation, :with_task) }
11
- let(:host) { job_invocation.template_invocations.first.host }
12
- let(:provider) do
13
- provider = ::SSHExecutionProvider
14
- provider.expects(:ssh_password).with(host).returns('sshpass')
15
- provider.expects(:effective_user_password).with(host).returns('sudopass')
16
- provider.expects(:ssh_key_passphrase).with(host).returns('keypass')
17
- provider
18
- end
19
-
20
- it 'uses provider secrets' do
21
- secrets = subject.secrets(host, job_invocation, provider)
22
-
23
- assert_equal 'sshpass', secrets[:ssh_password]
24
- assert_equal 'sudopass', secrets[:effective_user_password]
25
- assert_equal 'keypass', secrets[:key_passphrase]
26
- end
27
-
28
- it 'prefers job secrets over provider secrets' do
29
- job_invocation.password = 'jobsshpass'
30
- job_invocation.key_passphrase = 'jobkeypass'
31
- secrets = subject.secrets(host, job_invocation, provider)
32
-
33
- assert_equal 'jobsshpass', secrets[:ssh_password]
34
- assert_equal 'sudopass', secrets[:effective_user_password]
35
- assert_equal 'jobkeypass', secrets[:key_passphrase]
36
- end
37
- end
38
-
39
- describe '#verify_permission' do
40
- let(:job_invocation) { FactoryBot.create(:job_invocation, :with_task) }
41
- let(:template_invocation) { job_invocation.template_invocations.first }
42
-
43
- before { job_invocation }
44
-
45
- it 'raises an exception when run against an infrastructure host' do
46
- template_invocation.host = FactoryBot.create(:host, :with_infrastructure_facet)
47
-
48
- setup_user('view', 'hosts')
49
- setup_user('view', 'job_templates')
50
- setup_user('create', 'template_invocations')
51
-
52
- action = Actions::RemoteExecution::RunHostJob.allocate
53
- exception = assert_raises do
54
- action.send(:verify_permissions, template_invocation.host, template_invocation)
55
- end
56
- assert_includes exception.message, "infrastructure host #{template_invocation.host.name}"
57
- end
58
- end
59
-
60
- describe '#finalize' do
61
- let(:host) { FactoryBot.create(:host, :with_execution) }
62
-
63
- before do
64
- subject.stubs(:input).returns({ host: { id: host.id } })
65
- Host.expects(:find).with(host.id).returns(host)
66
- end
67
-
68
- describe 'updates the host status' do
69
- before do
70
- subject.expects(:check_exit_status).returns(nil)
71
- end
72
-
73
- context 'with stubbed status' do
74
- let(:stub_status) do
75
- status = HostStatus::ExecutionStatus.new
76
- status.stubs(:save!).returns(true)
77
- status
78
- end
79
-
80
- before do
81
- host.expects(:execution_status_object).returns(stub_status)
82
- end
83
-
84
- context 'exit_status is 0' do
85
- it 'updates the host status to OK' do
86
- subject.stubs(:exit_status).returns(0)
87
- stub_status.expects(:"status=").with(HostStatus::ExecutionStatus::OK)
88
- subject.finalize
89
- end
90
- end
91
-
92
- context 'exit_status is NOT 0' do
93
- it 'updates the host status to ERROR' do
94
- subject.stubs(:exit_status).returns(1)
95
- stub_status.expects(:"status=").with(HostStatus::ExecutionStatus::ERROR)
96
- subject.finalize
97
- end
98
- end
99
- end
100
-
101
- context 'host has no execution status yet' do
102
- before do
103
- assert_nil host.execution_status_object
104
- subject.stubs(:exit_status).returns(0)
105
- end
106
-
107
- it 'creates a new status' do
108
- subject.finalize
109
- assert_not_nil host.execution_status_object
110
- end
111
- end
112
- end
113
- end
114
- end
115
- end