foreman_remote_execution 14.0.0 → 14.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/foreman_remote_execution/locale/de/foreman_remote_execution.js +77 -77
  3. data/app/assets/javascripts/foreman_remote_execution/locale/en/foreman_remote_execution.js +2 -1667
  4. data/app/assets/javascripts/foreman_remote_execution/locale/en_GB/foreman_remote_execution.js +7 -7
  5. data/app/assets/javascripts/foreman_remote_execution/locale/es/foreman_remote_execution.js +33 -33
  6. data/app/assets/javascripts/foreman_remote_execution/locale/fr/foreman_remote_execution.js +131 -131
  7. data/app/assets/javascripts/foreman_remote_execution/locale/ja/foreman_remote_execution.js +131 -131
  8. data/app/assets/javascripts/foreman_remote_execution/locale/ka/foreman_remote_execution.js +38 -38
  9. data/app/assets/javascripts/foreman_remote_execution/locale/ko/foreman_remote_execution.js +16 -16
  10. data/app/assets/javascripts/foreman_remote_execution/locale/pt_BR/foreman_remote_execution.js +33 -33
  11. data/app/assets/javascripts/foreman_remote_execution/locale/ru/foreman_remote_execution.js +7 -7
  12. data/app/assets/javascripts/foreman_remote_execution/locale/zh_CN/foreman_remote_execution.js +134 -134
  13. data/app/assets/javascripts/foreman_remote_execution/locale/zh_TW/foreman_remote_execution.js +6 -6
  14. data/app/controllers/api/v2/job_invocations_controller.rb +34 -17
  15. data/app/helpers/job_invocations_helper.rb +1 -1
  16. data/app/helpers/remote_execution_helper.rb +2 -2
  17. data/app/lib/actions/remote_execution/proxy_action.rb +10 -5
  18. data/app/lib/actions/remote_execution/run_host_job.rb +1 -1
  19. data/app/lib/actions/remote_execution/template_invocation_progress_logging.rb +2 -3
  20. data/app/models/concerns/foreman_remote_execution/errors_flattener.rb +2 -2
  21. data/app/views/api/v2/job_invocations/hosts.json.rabl +15 -0
  22. data/app/views/template_invocations/show.html.erb +1 -1
  23. data/app/views/templates/script/package_action.erb +1 -1
  24. data/config/routes.rb +1 -0
  25. data/db/migrate/20240312133027_extend_template_invocation_events.rb +19 -0
  26. data/db/migrate/20240522093413_migrate_smart_proxy_ids_to_template_invocations.rb +3 -0
  27. data/lib/foreman_remote_execution/engine.rb +0 -4
  28. data/lib/foreman_remote_execution/version.rb +1 -1
  29. data/locale/Makefile +12 -2
  30. data/locale/de/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  31. data/locale/de/foreman_remote_execution.po +81 -80
  32. data/locale/en/foreman_remote_execution.po +0 -1675
  33. data/locale/en_GB/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  34. data/locale/en_GB/foreman_remote_execution.po +7 -7
  35. data/locale/es/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  36. data/locale/es/foreman_remote_execution.po +33 -33
  37. data/locale/fr/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  38. data/locale/fr/foreman_remote_execution.po +132 -132
  39. data/locale/ja/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  40. data/locale/ja/foreman_remote_execution.po +131 -131
  41. data/locale/ka/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  42. data/locale/ka/foreman_remote_execution.po +38 -38
  43. data/locale/ko/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  44. data/locale/ko/foreman_remote_execution.po +16 -16
  45. data/locale/pt_BR/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  46. data/locale/pt_BR/foreman_remote_execution.po +33 -33
  47. data/locale/ru/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  48. data/locale/ru/foreman_remote_execution.po +7 -7
  49. data/locale/zh_CN/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  50. data/locale/zh_CN/foreman_remote_execution.po +136 -134
  51. data/locale/zh_TW/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  52. data/locale/zh_TW/foreman_remote_execution.po +6 -6
  53. data/webpack/JobInvocationDetail/JobInvocationActions.js +1 -1
  54. data/webpack/JobInvocationDetail/JobInvocationConstants.js +84 -0
  55. data/webpack/JobInvocationDetail/JobInvocationDetail.scss +0 -1
  56. data/webpack/JobInvocationDetail/JobInvocationHostTable.js +210 -0
  57. data/webpack/JobInvocationDetail/JobInvocationSelectors.js +2 -2
  58. data/webpack/JobInvocationDetail/__tests__/MainInformation.test.js +5 -1
  59. data/webpack/JobInvocationDetail/__tests__/fixtures.js +9 -0
  60. data/webpack/JobInvocationDetail/index.js +56 -34
  61. data/webpack/__mocks__/foremanReact/components/HostDetails/DetailsCard/DefaultLoaderEmptyState.js +1 -2
  62. data/webpack/react_app/components/RecentJobsCard/JobStatusIcon.js +38 -7
  63. data/webpack/react_app/components/RecentJobsCard/constants.js +4 -0
  64. data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostStatus.test.js.snap +1 -1
  65. data/webpack/react_app/components/TargetingHosts/components/HostStatus.js +6 -6
  66. metadata +6 -95
  67. data/.babelrc.js +0 -3
  68. data/.eslintignore +0 -3
  69. data/.eslintrc +0 -13
  70. data/.github/workflows/js_ci.yml +0 -32
  71. data/.github/workflows/release.yml +0 -16
  72. data/.github/workflows/ruby_ci.yml +0 -19
  73. data/.gitignore +0 -18
  74. data/.packit.yaml +0 -45
  75. data/.prettierrc +0 -4
  76. data/.rubocop.yml +0 -105
  77. data/.rubocop_todo.yml +0 -516
  78. data/.tx/config +0 -10
  79. data/Gemfile +0 -5
  80. data/app/mailers/.gitkeep +0 -0
  81. data/app/views/dashboard/.gitkeep +0 -0
  82. data/foreman_remote_execution.gemspec +0 -33
  83. data/jsconfig.json +0 -8
  84. data/locale/action_names.rb +0 -2
  85. data/test/benchmark/run_hosts_job_benchmark.rb +0 -70
  86. data/test/benchmark/targeting_benchmark.rb +0 -31
  87. data/test/factories/foreman_remote_execution_factories.rb +0 -147
  88. data/test/functional/api/v2/foreign_input_sets_controller_test.rb +0 -58
  89. data/test/functional/api/v2/job_invocations_controller_test.rb +0 -446
  90. data/test/functional/api/v2/job_templates_controller_test.rb +0 -110
  91. data/test/functional/api/v2/registration_controller_test.rb +0 -73
  92. data/test/functional/api/v2/remote_execution_features_controller_test.rb +0 -34
  93. data/test/functional/api/v2/template_invocations_controller_test.rb +0 -33
  94. data/test/functional/cockpit_controller_test.rb +0 -16
  95. data/test/functional/job_invocations_controller_test.rb +0 -132
  96. data/test/functional/job_templates_controller_test.rb +0 -31
  97. data/test/functional/ui_job_wizard_controller_test.rb +0 -16
  98. data/test/graphql/mutations/job_invocations/create_test.rb +0 -58
  99. data/test/graphql/queries/job_invocation_query_test.rb +0 -31
  100. data/test/graphql/queries/job_invocations_query_test.rb +0 -35
  101. data/test/helpers/remote_execution_helper_test.rb +0 -46
  102. data/test/support/remote_execution_helper.rb +0 -5
  103. data/test/test_plugin_helper.rb +0 -9
  104. data/test/unit/actions/run_host_job_test.rb +0 -115
  105. data/test/unit/actions/run_hosts_job_test.rb +0 -214
  106. data/test/unit/api_params_test.rb +0 -25
  107. data/test/unit/concerns/foreman_tasks_cleaner_extensions_test.rb +0 -29
  108. data/test/unit/concerns/host_extensions_test.rb +0 -219
  109. data/test/unit/concerns/nic_extensions_test.rb +0 -9
  110. data/test/unit/execution_task_status_mapper_test.rb +0 -92
  111. data/test/unit/input_template_renderer_test.rb +0 -503
  112. data/test/unit/job_invocation_composer_test.rb +0 -974
  113. data/test/unit/job_invocation_report_template_test.rb +0 -60
  114. data/test/unit/job_invocation_test.rb +0 -232
  115. data/test/unit/job_template_effective_user_test.rb +0 -37
  116. data/test/unit/job_template_test.rb +0 -316
  117. data/test/unit/remote_execution_feature_test.rb +0 -86
  118. data/test/unit/remote_execution_provider_test.rb +0 -298
  119. data/test/unit/renderer_scope_input_test.rb +0 -49
  120. data/test/unit/targeting_test.rb +0 -206
  121. data/test/unit/template_invocation_input_value_test.rb +0 -38
@@ -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
@@ -1,214 +0,0 @@
1
- require 'test_plugin_helper'
2
- require 'securerandom'
3
-
4
- module ForemanRemoteExecution
5
- class RunHostsJobTest < ActiveSupport::TestCase
6
- include Dynflow::Testing
7
-
8
- # Adding run_step_id wich is needed in RunHostsJob as a quick fix
9
- # it will be added to dynflow in the future see https://github.com/Dynflow/dynflow/pull/391
10
- # rubocop:disable Style/ClassAndModuleChildren
11
- class Dynflow::Testing::DummyPlannedAction
12
- def run_step_id
13
- Dynflow::Testing.get_id
14
- end
15
- end
16
- # rubocop:enable Style/ClassAndModuleChildren
17
-
18
- let(:host) { FactoryBot.create(:host, :with_execution) }
19
- let(:proxy) { host.remote_execution_proxies('SSH')[:subnet].first }
20
- let(:targeting) { FactoryBot.create(:targeting, :search_query => "name = #{host.name}", :user => User.current) }
21
- let(:job_invocation) do
22
- FactoryBot.build(:job_invocation, :with_template).tap do |invocation|
23
- invocation.targeting = targeting
24
- invocation.description = 'Some short description'
25
- invocation.password = 'changeme'
26
- invocation.key_passphrase = 'changemetoo'
27
- invocation.effective_user_password = 'sudopassword'
28
- invocation.save
29
- end
30
- end
31
-
32
- let(:uuid) { SecureRandom.uuid }
33
- let(:task) do
34
- OpenStruct.new(:id => uuid).tap do |o|
35
- o.stubs(:add_missing_task_groups)
36
- o.stubs(:task_groups).returns([])
37
- o.stubs(:pending?).returns(true)
38
- end
39
- end
40
- let(:action) do
41
- create_action(Actions::RemoteExecution::RunHostsJob).tap do |action|
42
- action.expects(:action_subject).with(job_invocation, job_features: [])
43
- ForemanTasks::Task::DynflowTask.stubs(:where).returns(mock.tap { |m| m.stubs(:first! => task) })
44
- end
45
- end
46
- let(:planned) do
47
- plan_action action, job_invocation
48
- end
49
-
50
- let(:delayed) do
51
- action.delay({ :start_at => Time.now.getlocal }, job_invocation)
52
- action
53
- end
54
-
55
- before do
56
- ProxyAPI::ForemanDynflow::DynflowProxy.any_instance.stubs(:tasks_count).returns(0)
57
- User.current = users :admin
58
- action
59
- end
60
-
61
- context 'targeting resolving' do
62
- it 'resolves dynamic targeting in plan' do
63
- targeting.targeting_type = 'dynamic_query'
64
- assert_not targeting.resolved?
65
- delayed
66
- assert_not targeting.resolved?
67
- planned
68
- assert_includes targeting.hosts, host
69
- end
70
-
71
- it 'resolves the hosts on static targeting in delay' do
72
- assert_not targeting.resolved?
73
- delayed
74
- assert_includes targeting.hosts, host
75
- # Verify Targeting#resolve_hosts! won't be hit again
76
- targeting.expects(:resolve_hosts!).never
77
- planned
78
- end
79
-
80
- it 'resolves the hosts on static targeting in plan phase if not resolved yet' do
81
- planned
82
- assert_includes targeting.hosts, host
83
- end
84
- end
85
-
86
- it 'triggers the RunHostJob actions on the resolved hosts in run phase' do
87
- planned.expects(:output).at_most(5).returns(:planned_count => 0)
88
- planned.expects(:trigger).with { |*args| args[0] == Actions::RemoteExecution::RunHostJob }
89
- planned.create_sub_plans
90
- end
91
-
92
- it 'uses the BindJobInvocation middleware' do
93
- planned
94
- assert_equal job_invocation.task_id, uuid
95
- end
96
-
97
- # In plan phase this is handled by #action_subject
98
- # which is expected in tests
99
- it 'sets input in delay phase when delayed' do
100
- job_invocation_hash = delayed.input[:job_invocation]
101
- assert_equal job_invocation_hash['id'], job_invocation.id
102
- assert_equal job_invocation_hash['name'], job_invocation.job_category
103
- assert_equal job_invocation_hash['description'], job_invocation.description
104
- planned # To make the expectations happy
105
- end
106
-
107
- describe '#proxy_batch_size' do
108
- it 'defaults to Setting[foreman_tasks_proxy_batch_size]' do
109
- Setting.expects(:[]).with('foreman_tasks_proxy_batch_size').returns(14)
110
- planned
111
- assert_equal 14, planned.proxy_batch_size
112
- end
113
-
114
- it 'gets the provider value' do
115
- provider = mock('provider')
116
- provider.expects(:proxy_batch_size).returns(15)
117
- JobTemplate.any_instance.expects(:provider).returns(provider)
118
-
119
- assert_equal 15, planned.proxy_batch_size
120
- end
121
- end
122
-
123
- describe 'concurrency control' do
124
- let(:level) { 5 }
125
-
126
- it 'can be disabled' do
127
- assert_nil planned.concurrency_limit
128
- end
129
-
130
- it 'can limit concurrency level' do
131
- job_invocation.expects(:concurrency_level).twice.returns(level)
132
- assert_equal level, planned.concurrency_limit
133
- end
134
- end
135
-
136
- describe 'notifications' do
137
- it 'creates drawer notification on succeess' do
138
- blueprint = planned.job_invocation.build_notification
139
- blueprint.expects(:deliver!)
140
- planned.job_invocation.expects(:build_notification).returns(blueprint)
141
- planned.notify_on_success(nil)
142
- end
143
-
144
- it 'creates drawer notification on failure' do
145
- blueprint = planned.job_invocation.build_notification
146
- blueprint.expects(:deliver!)
147
- planned.job_invocation.expects(:build_notification).returns(blueprint)
148
- planned.notify_on_failure(nil)
149
- end
150
-
151
- describe 'ignoring drawer notification' do
152
- before do
153
- blueprint = planned.job_invocation.build_notification
154
- blueprint.expects(:deliver!)
155
- planned.job_invocation.expects(:build_notification).returns(blueprint)
156
- end
157
-
158
- let(:mail) do
159
- object = mock
160
- object.stubs(:deliver_now)
161
- object
162
- end
163
-
164
- describe 'for user subscribed to all' do
165
- before do
166
- planned.expects(:mail_notification_preference).returns(UserMailNotification.new(:interval => RexMailNotification::ALL_JOBS))
167
- end
168
-
169
- it 'sends the mail notification on success' do
170
- RexJobMailer.expects(:job_finished).returns(mail)
171
- planned.notify_on_success(nil)
172
- end
173
-
174
- it 'sends the mail notification on failure' do
175
- RexJobMailer.expects(:job_finished).returns(mail)
176
- planned.notify_on_failure(nil)
177
- end
178
- end
179
-
180
- describe 'for user subscribed to failures' do
181
- before do
182
- planned.expects(:mail_notification_preference).returns(UserMailNotification.new(:interval => RexMailNotification::FAILED_JOBS))
183
- end
184
-
185
- it 'it does not send the mail notification on success' do
186
- RexJobMailer.expects(:job_finished).never
187
- planned.notify_on_success(nil)
188
- end
189
-
190
- it 'sends the mail notification on failure' do
191
- RexJobMailer.expects(:job_finished).returns(mail)
192
- planned.notify_on_failure(nil)
193
- end
194
- end
195
-
196
- describe 'for user subscribed to successful jobs' do
197
- before do
198
- planned.expects(:mail_notification_preference).returns(UserMailNotification.new(:interval => RexMailNotification::SUCCEEDED_JOBS))
199
- end
200
-
201
- it 'sends the mail notification on success' do
202
- RexJobMailer.expects(:job_finished).returns(mail)
203
- planned.notify_on_success(nil)
204
- end
205
-
206
- it 'does not send the mail notification on failure' do
207
- RexJobMailer.expects(:job_finished).never
208
- planned.notify_on_failure(nil)
209
- end
210
- end
211
- end
212
- end
213
- end
214
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_plugin_helper'
4
-
5
- class ApiParamsTest < ActiveSupport::TestCase
6
- describe '#format_datetime' do
7
- let(:params) { JobInvocationComposer::ApiParams.allocate }
8
-
9
- it 'leaves empty string as is' do
10
- assert_equal params.send(:format_datetime, ''), ''
11
- end
12
-
13
- it 'honors explicitly supplied time zone' do
14
- Time.use_zone(ActiveSupport::TimeZone['America/New_York']) do
15
- assert_equal '2022-07-08 08:53', params.send(:format_datetime, '2022-07-08 12:53:20 UTC')
16
- end
17
- end
18
-
19
- it 'implicitly honors current user\'s time zone' do
20
- Time.use_zone(ActiveSupport::TimeZone['America/New_York']) do
21
- assert_equal '2022-07-08 12:53', params.send(:format_datetime, '2022-07-08 12:53:20')
22
- end
23
- end
24
- end
25
- end
@@ -1,29 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class ForemanRemoteExecutionForemanTasksCleanerExtensionsTest < ActiveSupport::TestCase
4
- # Apply the same stubbing as in foreman-tasks
5
- before do
6
- # To stop dynflow from backing up actions, execution_plans and steps
7
- ForemanTasks.dynflow.world.persistence.adapter.stubs(:backup_to_csv)
8
- ForemanTasks::Cleaner.any_instance.stubs(:say) # Make the tests silent
9
- # Hack to make the tests pass due to ActiveRecord shenanigans
10
- ForemanTasks::Cleaner.any_instance.stubs(:delete_orphaned_dynflow_tasks)
11
- end
12
-
13
- it 'tries to delete associated job invocations' do
14
- job = FactoryBot.create(:job_invocation, :with_task)
15
- ForemanTasks::Cleaner.new(:filter => "id = #{job.task.id}").delete
16
- assert_empty JobInvocation.where(:id => job.id)
17
- end
18
-
19
- it 'removes orphaned job invocations' do
20
- job = FactoryBot.create(:job_invocation, :with_task)
21
- assert_equal 1, JobInvocation.where(:id => job.id).count
22
- job.task.delete
23
- job.reload
24
- assert_nil job.task
25
- refute_nil job.task_id
26
- ForemanTasks::Cleaner.new(:filter => '').delete
27
- assert_empty JobInvocation.where(:id => job.id)
28
- end
29
- end
@@ -1,219 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class ForemanRemoteExecutionHostExtensionsTest < ActiveSupport::TestCase
4
- let(:provider) { 'SSH' }
5
-
6
- before { User.current = FactoryBot.build(:user, :admin) }
7
- after { User.current = nil }
8
-
9
- describe 'ssh specific params' do
10
- let(:host) { FactoryBot.create(:host, :with_execution) }
11
- let(:sshkey) { 'ssh-rsa AAAAB3NzaC1yc2EAAAABJQ foo@example.com' }
12
-
13
- before do
14
- SmartProxy.any_instance.stubs(:pubkey).returns(sshkey)
15
- Setting[:remote_execution_ssh_user] = 'root'
16
- Setting[:remote_execution_effective_user_method] = 'sudo'
17
- end
18
-
19
- it 'has ssh user in the parameters' do
20
- assert_equal Setting[:remote_execution_ssh_user], host.host_param('remote_execution_ssh_user')
21
- end
22
-
23
- it 'can override ssh user' do
24
- host.host_parameters << FactoryBot.create(:host_parameter, :host => host, :name => 'remote_execution_ssh_user', :value => 'amy')
25
- assert_equal 'amy', host.host_param('remote_execution_ssh_user')
26
- end
27
-
28
- it 'has effective user method in the parameters' do
29
- assert_equal Setting[:remote_execution_effective_user_method], host.host_param('remote_execution_effective_user_method')
30
- end
31
-
32
- it 'can override effective user method' do
33
- host.host_parameters << FactoryBot.create(:host_parameter, :host => host, :name => 'remote_execution_effective_user_method', :value => 'su')
34
- assert_equal 'su', host.host_param('remote_execution_effective_user_method')
35
- end
36
-
37
- it 'has ssh keys in the parameters' do
38
- assert_includes host.remote_execution_ssh_keys, sshkey
39
- end
40
-
41
- it 'merges ssh keys from host parameters and proxies' do
42
- key = 'ssh-rsa not-even-a-key something@somewhere.com'
43
- host.host_parameters << FactoryBot.create(:host_parameter, :host => host, :name => 'remote_execution_ssh_keys', :value => [key])
44
- assert_includes host.host_param('remote_execution_ssh_keys'), key
45
- assert_includes host.host_param('remote_execution_ssh_keys'), sshkey
46
- end
47
-
48
- it 'merges ssh key as a string from host parameters and proxies' do
49
- key = 'ssh-rsa not-even-a-key something@somewhere.com'
50
- host.host_parameters << FactoryBot.create(:host_parameter, :host => host, :name => 'remote_execution_ssh_keys', :value => key)
51
- assert_includes host.host_param('remote_execution_ssh_keys'), key
52
- assert_includes host.host_param('remote_execution_ssh_keys'), sshkey
53
- end
54
-
55
- it 'has ssh keys in the parameters even when no user specified' do
56
- # this is a case, when using the helper in provisioning templates
57
- FactoryBot.create(:smart_proxy, :ssh)
58
- host.interfaces.first.subnet.remote_execution_proxies.clear
59
- User.current = nil
60
- assert_includes host.remote_execution_ssh_keys, sshkey
61
- end
62
- end
63
-
64
- context 'host has multiple nics' do
65
- let(:host) { FactoryBot.build(:host, :with_execution) }
66
-
67
- it 'should only have one execution interface' do
68
- host.interfaces << FactoryBot.build(:nic_managed)
69
- host.interfaces.each { |interface| interface.execution = true }
70
- assert_predicate host, :valid?
71
- assert_equal 1, host.interfaces.count(&:execution?)
72
- end
73
-
74
- it 'returns the execution interface' do
75
- assert_kind_of Nic::Managed, host.execution_interface
76
- end
77
- end
78
-
79
- context 'scoped search' do
80
- let(:job) do
81
- job = FactoryBot.create(:job_invocation, :with_task)
82
- job.template_invocations << FactoryBot.create(:template_invocation, :with_host, :with_failed_task)
83
- job
84
- end
85
-
86
- let(:job2) do
87
- job = FactoryBot.create(:job_invocation, :with_task)
88
- job.template_invocations << FactoryBot.create(:template_invocation, :with_host, :with_failed_task)
89
- job
90
- end
91
-
92
- it 'finds hosts for job_invocation.id' do
93
- found_ids = Host.search_for("job_invocation.id = #{job.id}").map(&:id).sort
94
- assert_equal job.template_invocations_host_ids.sort, found_ids
95
- end
96
-
97
- it 'finds hosts by job_invocation.result' do
98
- success, failed = job.template_invocations
99
- .partition { |template| template.run_host_job_task.result == 'success' }
100
- found_ids = Host.search_for('job_invocation.result = success').map(&:id)
101
- assert_equal success.map(&:host_id), found_ids
102
- found_ids = Host.search_for('job_invocation.result = failed').map(&:id)
103
- assert_equal failed.map(&:host_id), found_ids
104
- end
105
-
106
- it 'finds hosts by job_invocation.id and job_invocation.result' do
107
- # Force evaluation of the jobs
108
- job
109
- job2
110
-
111
- assert_equal 2, Host.search_for("job_invocation.id = #{job.id}").count
112
- assert_equal 2, Host.search_for("job_invocation.id = #{job2.id}").count
113
- assert_equal 2, Host.search_for('job_invocation.result = success').count
114
- assert_equal 2, Host.search_for('job_invocation.result = failed').count
115
-
116
- success, failed = job.template_invocations
117
- .partition { |template| template.run_host_job_task.result == 'success' }
118
- found_ids = Host.search_for("job_invocation.id = #{job.id} AND job_invocation.result = success").map(&:id)
119
- assert_equal success.map(&:host_id), found_ids
120
- found_ids = Host.search_for("job_invocation.id = #{job.id} AND job_invocation.result = failed").map(&:id)
121
- assert_equal failed.map(&:host_id), found_ids
122
- end
123
- end
124
-
125
- describe 'proxy determination strategies' do
126
- context 'subnet strategy' do
127
- let(:host) { FactoryBot.build(:host, :with_execution) }
128
- it { assert_includes host.remote_execution_proxies(provider)[:subnet], host.subnet.remote_execution_proxies.first }
129
- end
130
-
131
- context 'fallback strategy' do
132
- let(:host) { FactoryBot.build(:host, :with_tftp_subnet) }
133
-
134
- context 'enabled' do
135
- before do
136
- Setting[:remote_execution_fallback_proxy] = true
137
- host.subnet.tftp.features << FactoryBot.create(:feature, :ssh)
138
- end
139
-
140
- it 'returns a fallback proxy' do
141
- assert_includes host.remote_execution_proxies(provider)[:fallback], host.subnet.tftp
142
- end
143
- end
144
-
145
- context 'disabled' do
146
- before do
147
- Setting[:remote_execution_fallback_proxy] = false
148
- host.subnet.tftp.features << FactoryBot.create(:feature, :ssh)
149
- end
150
-
151
- it 'returns no proxy' do
152
- assert_empty host.remote_execution_proxies(provider)[:fallback]
153
- end
154
- end
155
- end
156
-
157
- context 'global strategy' do
158
- let(:tax_organization) { FactoryBot.build(:organization) }
159
- let(:tax_location) { FactoryBot.build(:location) }
160
- let(:host) { FactoryBot.build(:host, :organization => tax_organization, :location => tax_location) }
161
- let(:proxy_in_taxonomies) { FactoryBot.create(:smart_proxy, :ssh, :organizations => [tax_organization], :locations => [tax_location]) }
162
- let(:proxy_no_taxonomies) { FactoryBot.create(:smart_proxy, :ssh) }
163
-
164
- context 'enabled' do
165
- before { Setting[:remote_execution_global_proxy] = true }
166
-
167
- it 'returns correct proxies confined by taxonomies' do
168
- proxy_in_taxonomies
169
- proxy_no_taxonomies
170
- assert_includes host.remote_execution_proxies(provider)[:global], proxy_in_taxonomies
171
- refute_includes host.remote_execution_proxies(provider)[:global], proxy_no_taxonomies
172
- end
173
- end
174
-
175
- context 'disabled' do
176
- before { Setting[:remote_execution_global_proxy] = false }
177
- it 'returns no proxy' do
178
- assert_empty host.remote_execution_proxies(provider)[:global]
179
- end
180
- end
181
- end
182
- end
183
-
184
- describe '#execution_scope' do
185
- let(:host) { FactoryBot.create(:host) }
186
- let(:infra_host) { FactoryBot.create(:host, :with_infrastructure_facet) }
187
-
188
- before do
189
- host
190
- infra_host
191
- end
192
-
193
- context 'without infrastructure host permission' do
194
- it 'omits the infrastructure host' do
195
- setup_user('view', 'hosts')
196
-
197
- hosts = ::Host::Managed.execution_scope
198
- assert_includes hosts, host
199
- refute_includes hosts, infra_host
200
- end
201
- end
202
-
203
- context 'with infrastructure host permission' do
204
- it 'finds the host as admin' do
205
- assert User.current.admin?
206
- hosts = ::Host::Managed.execution_scope
207
- assert_includes hosts, host
208
- assert_includes hosts, infra_host
209
- end
210
-
211
- it 'finds the host as user with needed permissions' do
212
- setup_user('execute_jobs_on', 'infrastructure_hosts')
213
- hosts = ::Host::Managed.execution_scope
214
- assert_includes hosts, host
215
- assert_includes hosts, infra_host
216
- end
217
- end
218
- end
219
- end
@@ -1,9 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class ForemanRemoteExecutionNicExtensionsTest < ActiveSupport::TestCase
4
- let(:host) { FactoryBot.create(:host) }
5
-
6
- it 'sets the first primary interface as the execution interface' do
7
- assert_equal host.interfaces.first, host.execution_interface
8
- end
9
- end