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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/foreman_remote_execution/locale/de/foreman_remote_execution.js +77 -77
- data/app/assets/javascripts/foreman_remote_execution/locale/en/foreman_remote_execution.js +2 -1667
- data/app/assets/javascripts/foreman_remote_execution/locale/en_GB/foreman_remote_execution.js +7 -7
- data/app/assets/javascripts/foreman_remote_execution/locale/es/foreman_remote_execution.js +33 -33
- data/app/assets/javascripts/foreman_remote_execution/locale/fr/foreman_remote_execution.js +131 -131
- data/app/assets/javascripts/foreman_remote_execution/locale/ja/foreman_remote_execution.js +131 -131
- data/app/assets/javascripts/foreman_remote_execution/locale/ka/foreman_remote_execution.js +38 -38
- data/app/assets/javascripts/foreman_remote_execution/locale/ko/foreman_remote_execution.js +16 -16
- data/app/assets/javascripts/foreman_remote_execution/locale/pt_BR/foreman_remote_execution.js +33 -33
- data/app/assets/javascripts/foreman_remote_execution/locale/ru/foreman_remote_execution.js +7 -7
- data/app/assets/javascripts/foreman_remote_execution/locale/zh_CN/foreman_remote_execution.js +134 -134
- data/app/assets/javascripts/foreman_remote_execution/locale/zh_TW/foreman_remote_execution.js +6 -6
- data/app/controllers/api/v2/job_invocations_controller.rb +34 -17
- data/app/helpers/job_invocations_helper.rb +1 -1
- data/app/helpers/remote_execution_helper.rb +2 -2
- data/app/lib/actions/remote_execution/proxy_action.rb +10 -5
- data/app/lib/actions/remote_execution/run_host_job.rb +1 -1
- data/app/lib/actions/remote_execution/template_invocation_progress_logging.rb +2 -3
- data/app/models/concerns/foreman_remote_execution/errors_flattener.rb +2 -2
- data/app/views/api/v2/job_invocations/hosts.json.rabl +15 -0
- data/app/views/template_invocations/show.html.erb +1 -1
- data/app/views/templates/script/package_action.erb +1 -1
- data/config/routes.rb +1 -0
- data/db/migrate/20240312133027_extend_template_invocation_events.rb +19 -0
- data/db/migrate/20240522093413_migrate_smart_proxy_ids_to_template_invocations.rb +3 -0
- data/lib/foreman_remote_execution/engine.rb +0 -4
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/locale/Makefile +12 -2
- data/locale/de/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/de/foreman_remote_execution.po +81 -80
- data/locale/en/foreman_remote_execution.po +0 -1675
- data/locale/en_GB/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/en_GB/foreman_remote_execution.po +7 -7
- data/locale/es/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/es/foreman_remote_execution.po +33 -33
- data/locale/fr/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/fr/foreman_remote_execution.po +132 -132
- data/locale/ja/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ja/foreman_remote_execution.po +131 -131
- data/locale/ka/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ka/foreman_remote_execution.po +38 -38
- data/locale/ko/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ko/foreman_remote_execution.po +16 -16
- data/locale/pt_BR/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/pt_BR/foreman_remote_execution.po +33 -33
- data/locale/ru/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ru/foreman_remote_execution.po +7 -7
- data/locale/zh_CN/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/zh_CN/foreman_remote_execution.po +136 -134
- data/locale/zh_TW/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/zh_TW/foreman_remote_execution.po +6 -6
- data/webpack/JobInvocationDetail/JobInvocationActions.js +1 -1
- data/webpack/JobInvocationDetail/JobInvocationConstants.js +84 -0
- data/webpack/JobInvocationDetail/JobInvocationDetail.scss +0 -1
- data/webpack/JobInvocationDetail/JobInvocationHostTable.js +210 -0
- data/webpack/JobInvocationDetail/JobInvocationSelectors.js +2 -2
- data/webpack/JobInvocationDetail/__tests__/MainInformation.test.js +5 -1
- data/webpack/JobInvocationDetail/__tests__/fixtures.js +9 -0
- data/webpack/JobInvocationDetail/index.js +56 -34
- data/webpack/__mocks__/foremanReact/components/HostDetails/DetailsCard/DefaultLoaderEmptyState.js +1 -2
- data/webpack/react_app/components/RecentJobsCard/JobStatusIcon.js +38 -7
- data/webpack/react_app/components/RecentJobsCard/constants.js +4 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostStatus.test.js.snap +1 -1
- data/webpack/react_app/components/TargetingHosts/components/HostStatus.js +6 -6
- metadata +6 -95
- data/.babelrc.js +0 -3
- data/.eslintignore +0 -3
- data/.eslintrc +0 -13
- data/.github/workflows/js_ci.yml +0 -32
- data/.github/workflows/release.yml +0 -16
- data/.github/workflows/ruby_ci.yml +0 -19
- data/.gitignore +0 -18
- data/.packit.yaml +0 -45
- data/.prettierrc +0 -4
- data/.rubocop.yml +0 -105
- data/.rubocop_todo.yml +0 -516
- data/.tx/config +0 -10
- data/Gemfile +0 -5
- data/app/mailers/.gitkeep +0 -0
- data/app/views/dashboard/.gitkeep +0 -0
- data/foreman_remote_execution.gemspec +0 -33
- data/jsconfig.json +0 -8
- data/locale/action_names.rb +0 -2
- data/test/benchmark/run_hosts_job_benchmark.rb +0 -70
- data/test/benchmark/targeting_benchmark.rb +0 -31
- data/test/factories/foreman_remote_execution_factories.rb +0 -147
- data/test/functional/api/v2/foreign_input_sets_controller_test.rb +0 -58
- data/test/functional/api/v2/job_invocations_controller_test.rb +0 -446
- data/test/functional/api/v2/job_templates_controller_test.rb +0 -110
- data/test/functional/api/v2/registration_controller_test.rb +0 -73
- data/test/functional/api/v2/remote_execution_features_controller_test.rb +0 -34
- data/test/functional/api/v2/template_invocations_controller_test.rb +0 -33
- data/test/functional/cockpit_controller_test.rb +0 -16
- data/test/functional/job_invocations_controller_test.rb +0 -132
- data/test/functional/job_templates_controller_test.rb +0 -31
- data/test/functional/ui_job_wizard_controller_test.rb +0 -16
- data/test/graphql/mutations/job_invocations/create_test.rb +0 -58
- data/test/graphql/queries/job_invocation_query_test.rb +0 -31
- data/test/graphql/queries/job_invocations_query_test.rb +0 -35
- data/test/helpers/remote_execution_helper_test.rb +0 -46
- data/test/support/remote_execution_helper.rb +0 -5
- data/test/test_plugin_helper.rb +0 -9
- data/test/unit/actions/run_host_job_test.rb +0 -115
- data/test/unit/actions/run_hosts_job_test.rb +0 -214
- data/test/unit/api_params_test.rb +0 -25
- data/test/unit/concerns/foreman_tasks_cleaner_extensions_test.rb +0 -29
- data/test/unit/concerns/host_extensions_test.rb +0 -219
- data/test/unit/concerns/nic_extensions_test.rb +0 -9
- data/test/unit/execution_task_status_mapper_test.rb +0 -92
- data/test/unit/input_template_renderer_test.rb +0 -503
- data/test/unit/job_invocation_composer_test.rb +0 -974
- data/test/unit/job_invocation_report_template_test.rb +0 -60
- data/test/unit/job_invocation_test.rb +0 -232
- data/test/unit/job_template_effective_user_test.rb +0 -37
- data/test/unit/job_template_test.rb +0 -316
- data/test/unit/remote_execution_feature_test.rb +0 -86
- data/test/unit/remote_execution_provider_test.rb +0 -298
- data/test/unit/renderer_scope_input_test.rb +0 -49
- data/test/unit/targeting_test.rb +0 -206
- 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
|