foreman_remote_execution 14.0.2 → 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/controllers/api/v2/job_invocations_controller.rb +34 -17
- 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/views/api/v2/job_invocations/hosts.json.rabl +15 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20240312133027_extend_template_invocation_events.rb +19 -0
- data/lib/foreman_remote_execution/version.rb +1 -1
- 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 -94
- 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 -19
- 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/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,86 +0,0 @@
|
|
1
|
-
require 'test_plugin_helper'
|
2
|
-
|
3
|
-
class RemoteExecutionFeatureTest < ActiveSupport::TestCase
|
4
|
-
should validate_presence_of(:name)
|
5
|
-
should validate_presence_of(:label)
|
6
|
-
should validate_uniqueness_of(:name)
|
7
|
-
should validate_uniqueness_of(:label)
|
8
|
-
|
9
|
-
let(:install_feature) do
|
10
|
-
RemoteExecutionFeature.register(:katello_install_package, N_('Katello: Install package'),
|
11
|
-
:description => 'Install package via Katello user interface',
|
12
|
-
:provided_inputs => ['package'])
|
13
|
-
end
|
14
|
-
|
15
|
-
let(:package_template) do
|
16
|
-
FactoryBot.create(:job_template).tap do |job_template|
|
17
|
-
job_template.job_category = 'Package Action'
|
18
|
-
job_template.name = 'Package Action - SSH Default'
|
19
|
-
job_template.template_inputs.create(:name => 'package', :input_type => 'user')
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
let(:host) { FactoryBot.create(:host) }
|
24
|
-
|
25
|
-
before do
|
26
|
-
User.current = users :admin
|
27
|
-
install_feature.update!(:job_template_id => package_template.id)
|
28
|
-
end
|
29
|
-
|
30
|
-
describe 'composer' do
|
31
|
-
it 'prepares composer for given feature based on the mapping' do
|
32
|
-
composer = JobInvocationComposer.for_feature(:katello_install_package, host, :package => 'zsh')
|
33
|
-
assert composer.valid?
|
34
|
-
assert_equal 1, composer.pattern_template_invocations.size
|
35
|
-
template_invocation = composer.pattern_template_invocations.first
|
36
|
-
assert_equal package_template, template_invocation.template
|
37
|
-
assert_equal 1, template_invocation.input_values.size
|
38
|
-
|
39
|
-
input_value = template_invocation.input_values.first
|
40
|
-
assert_equal 'zsh', input_value.value
|
41
|
-
assert_equal 'package', input_value.template_input.name
|
42
|
-
|
43
|
-
assert_equal "name ^ (#{host.name})", composer.targeting.search_query
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'updates the feature when attributes change' do
|
47
|
-
updated_feature = RemoteExecutionFeature.register(install_feature.label, N_('Katello: Install package'),
|
48
|
-
:description => 'New description',
|
49
|
-
:provided_inputs => ['package', 'force'])
|
50
|
-
updated_feature.reload
|
51
|
-
assert_equal install_feature.id, updated_feature.id
|
52
|
-
assert_equal 'New description', updated_feature.description
|
53
|
-
assert_equal ['package', 'force'], updated_feature.provided_input_names
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe '.register' do
|
58
|
-
it "creates a feature if it's missing" do
|
59
|
-
feature = RemoteExecutionFeature.register('new_feature_that_does_not_exist', 'name')
|
60
|
-
assert_predicate feature, :persisted?
|
61
|
-
assert_equal 'new_feature_that_does_not_exist', feature.label
|
62
|
-
assert_equal 'name', feature.name
|
63
|
-
assert_not feature.host_action_button
|
64
|
-
end
|
65
|
-
|
66
|
-
it 'creates a feature with host action flag' do
|
67
|
-
feature = RemoteExecutionFeature.register('new_feature_that_does_not_exist_button', 'name', :host_action_button => true)
|
68
|
-
assert_predicate feature, :persisted?
|
69
|
-
assert feature.host_action_button
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'created feature with host action flag can be found using named scope' do
|
73
|
-
feature = RemoteExecutionFeature.register('new_feature_that_does_not_exist_button', 'name', :host_action_button => true)
|
74
|
-
assert_includes RemoteExecutionFeature.with_host_action_button, feature
|
75
|
-
end
|
76
|
-
|
77
|
-
|
78
|
-
it 'updates a feature if it exists' do
|
79
|
-
existing = FactoryBot.create(:remote_execution_feature, :name => 'existing_feature_withou_action_button')
|
80
|
-
feature = RemoteExecutionFeature.register(existing.label, existing.name, :host_action_button => true)
|
81
|
-
assert_predicate feature, :persisted?
|
82
|
-
existing.reload
|
83
|
-
assert existing.host_action_button
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
@@ -1,298 +0,0 @@
|
|
1
|
-
require 'test_plugin_helper'
|
2
|
-
|
3
|
-
class RemoteExecutionProviderTest < ActiveSupport::TestCase
|
4
|
-
describe '.providers' do
|
5
|
-
let(:providers) { RemoteExecutionProvider.providers }
|
6
|
-
it { assert_kind_of HashWithIndifferentAccess, providers }
|
7
|
-
it 'makes providers accessible using symbol' do
|
8
|
-
assert_equal SSHExecutionProvider, providers[:SSH]
|
9
|
-
assert_equal ScriptExecutionProvider, providers[:script]
|
10
|
-
end
|
11
|
-
it 'makes providers accessible using string' do
|
12
|
-
assert_equal SSHExecutionProvider, providers['SSH']
|
13
|
-
assert_equal ScriptExecutionProvider, providers['script']
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
describe '.register_provider' do
|
18
|
-
before { RemoteExecutionProvider.providers.delete(:new) }
|
19
|
-
let(:new_provider) { RemoteExecutionProvider.providers[:new] }
|
20
|
-
it { assert_nil new_provider }
|
21
|
-
|
22
|
-
context 'registers a provider under key :new' do
|
23
|
-
before { RemoteExecutionProvider.register(:new, String) }
|
24
|
-
it { assert_equal String, new_provider }
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
describe '.provider_for' do
|
29
|
-
it 'accepts symbols' do
|
30
|
-
assert_equal SSHExecutionProvider, RemoteExecutionProvider.provider_for(:SSH)
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'accepts strings' do
|
34
|
-
assert_equal SSHExecutionProvider, RemoteExecutionProvider.provider_for('SSH')
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'returns a default one if unknown value is provided' do
|
38
|
-
assert_equal ScriptExecutionProvider, RemoteExecutionProvider.provider_for('WinRM')
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe '.provider_names' do
|
43
|
-
let(:provider_names) { RemoteExecutionProvider.provider_names }
|
44
|
-
|
45
|
-
it 'returns only strings' do
|
46
|
-
provider_names.each do |name|
|
47
|
-
assert_kind_of String, name
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
context 'provider is registetered under :custom symbol' do
|
52
|
-
before { RemoteExecutionProvider.register(:Custom, String) }
|
53
|
-
|
54
|
-
it { assert_includes provider_names, 'SSH' }
|
55
|
-
it { assert_includes provider_names, 'Custom' }
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
describe '.proxy_feature' do
|
60
|
-
# rubocop:disable Naming/ConstantName
|
61
|
-
it 'handles provider subclasses properly' do
|
62
|
-
old = ::RemoteExecutionProvider
|
63
|
-
|
64
|
-
class P2 < old
|
65
|
-
end
|
66
|
-
::RemoteExecutionProvider = P2
|
67
|
-
|
68
|
-
class CustomProvider < ::RemoteExecutionProvider
|
69
|
-
end
|
70
|
-
|
71
|
-
::RemoteExecutionProvider.register('custom', CustomProvider)
|
72
|
-
|
73
|
-
feature = CustomProvider.proxy_feature
|
74
|
-
assert_equal 'custom', feature
|
75
|
-
ensure
|
76
|
-
::RemoteExecutionProvider = old
|
77
|
-
end
|
78
|
-
# rubocop:enable Naming/ConstantName
|
79
|
-
end
|
80
|
-
|
81
|
-
describe '.provider_proxy_features' do
|
82
|
-
it 'returns correct values' do
|
83
|
-
RemoteExecutionProvider.stubs(:providers).returns(
|
84
|
-
:SSH => SSHExecutionProvider,
|
85
|
-
:script => ScriptExecutionProvider
|
86
|
-
)
|
87
|
-
|
88
|
-
features = RemoteExecutionProvider.provider_proxy_features
|
89
|
-
assert_includes features, 'SSH'
|
90
|
-
assert_includes features, 'Script'
|
91
|
-
RemoteExecutionProvider.unstub(:providers)
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'can deal with non-arrays' do
|
95
|
-
provider = OpenStruct.new(proxy_feature: 'Testing')
|
96
|
-
RemoteExecutionProvider.stubs(:providers).returns(:testing => provider)
|
97
|
-
features = RemoteExecutionProvider.provider_proxy_features
|
98
|
-
assert_includes features, 'Testing'
|
99
|
-
RemoteExecutionProvider.unstub(:providers)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
describe '.host_setting' do
|
104
|
-
let(:host) { FactoryBot.create(:host) }
|
105
|
-
|
106
|
-
it 'honors falsey values set as a host parameter' do
|
107
|
-
key = 'remote_execution_connect_by_ip'
|
108
|
-
Setting[key] = true
|
109
|
-
host.parameters << HostParameter.new(name: key, value: false)
|
110
|
-
|
111
|
-
refute RemoteExecutionProvider.host_setting(host, key)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
describe SSHExecutionProvider do
|
116
|
-
before { User.current = FactoryBot.build(:user, :admin) }
|
117
|
-
after { User.current = nil }
|
118
|
-
|
119
|
-
let(:job_invocation) { FactoryBot.create(:job_invocation, :with_template) }
|
120
|
-
let(:template_invocation) { job_invocation.pattern_template_invocations.first }
|
121
|
-
let(:host) { FactoryBot.create(:host) }
|
122
|
-
let(:proxy_options) { SSHExecutionProvider.proxy_command_options(template_invocation, host) }
|
123
|
-
let(:secrets) { SSHExecutionProvider.secrets(host) }
|
124
|
-
|
125
|
-
describe 'effective user' do
|
126
|
-
it 'takes the effective user from value from the template invocation' do
|
127
|
-
template_invocation.effective_user = 'my user'
|
128
|
-
assert_equal 'my user', proxy_options[:effective_user]
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
describe 'ssh user' do
|
133
|
-
it 'uses the remote_execution_ssh_user on the host param' do
|
134
|
-
host.host_parameters << FactoryBot.create(:host_parameter, :host => host, :name => 'remote_execution_ssh_user', :value => 'my user')
|
135
|
-
assert_equal 'my user', proxy_options[:ssh_user]
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
describe 'effective user password' do
|
140
|
-
it 'uses the remote_execution_effective_user_password on the host param' do
|
141
|
-
host.params['remote_execution_effective_user_password'] = 'mypassword'
|
142
|
-
host.host_parameters << FactoryBot.create(:host_parameter, :host => host, :name => 'remote_execution_effective_user_password', :value => 'mypassword')
|
143
|
-
assert_nil proxy_options[:effective_user_password]
|
144
|
-
assert_equal 'mypassword', secrets[:effective_user_password]
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
describe 'sudo' do
|
149
|
-
it 'uses the remote_execution_effective_user_method on the host param' do
|
150
|
-
host.params['remote_execution_effective_user_method'] = 'sudo'
|
151
|
-
method_param = FactoryBot.create(:host_parameter, :host => host, :name => 'remote_execution_effective_user_method', :value => 'sudo')
|
152
|
-
host.host_parameters << method_param
|
153
|
-
assert_equal 'sudo', proxy_options[:effective_user_method]
|
154
|
-
method_param.update!(:value => 'su')
|
155
|
-
host.clear_host_parameters_cache!
|
156
|
-
proxy_options = SSHExecutionProvider.proxy_command_options(template_invocation, host)
|
157
|
-
assert_equal 'su', proxy_options[:effective_user_method]
|
158
|
-
method_param.update!(:value => 'dzdo')
|
159
|
-
host.clear_host_parameters_cache!
|
160
|
-
proxy_options = SSHExecutionProvider.proxy_command_options(template_invocation, host)
|
161
|
-
assert_equal 'dzdo', proxy_options[:effective_user_method]
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
describe 'ssh port from settings' do
|
166
|
-
before do
|
167
|
-
Setting[:remote_execution_ssh_port] = '66'
|
168
|
-
end
|
169
|
-
|
170
|
-
it 'has ssh port changed in settings and check return type' do
|
171
|
-
assert_kind_of Integer, proxy_options[:ssh_port]
|
172
|
-
assert_equal 66, proxy_options[:ssh_port]
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
describe 'ssh port from params' do
|
177
|
-
it 'takes ssh port number from params and check return type' do
|
178
|
-
host.params['remote_execution_ssh_port'] = '30'
|
179
|
-
host.host_parameters << FactoryBot.build(:host_parameter, :name => 'remote_execution_ssh_port', :value => '30')
|
180
|
-
host.clear_host_parameters_cache!
|
181
|
-
assert_kind_of Integer, proxy_options[:ssh_port]
|
182
|
-
assert_equal 30, proxy_options[:ssh_port]
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
describe 'cleanup working directories setting' do
|
187
|
-
before do
|
188
|
-
Setting[:remote_execution_cleanup_working_dirs] = false
|
189
|
-
end
|
190
|
-
|
191
|
-
it 'updates the value via settings' do
|
192
|
-
refute proxy_options[:cleanup_working_dirs]
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
describe 'cleanup working directories from parameters' do
|
197
|
-
it 'takes the value from host parameters' do
|
198
|
-
host.params['remote_execution_cleanup_working_dirs'] = 'false'
|
199
|
-
host.host_parameters << FactoryBot.build(:host_parameter, :name => 'remote_execution_cleanup_working_dirs', :value => 'false')
|
200
|
-
host.clear_host_parameters_cache!
|
201
|
-
refute proxy_options[:cleanup_working_dirs]
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
describe '#find_ip_or_hostname' do
|
206
|
-
let(:host) do
|
207
|
-
FactoryBot.create(:host) do |host|
|
208
|
-
host.interfaces = [FactoryBot.build(:nic_managed, flags.merge(:ip => nil, :name => 'somehost.somedomain.org', :primary => true)),
|
209
|
-
FactoryBot.build(:nic_managed, flags.merge(:ip => '127.0.0.1'))]
|
210
|
-
end.reload
|
211
|
-
# Reassigning the interfaces triggers the on-deletion ssh key removal for the interface which is being replaced
|
212
|
-
# This has an undesired side effect of caching the original interface as execution one which made the tests
|
213
|
-
# give wrong results. Reloading the host wipes the cache
|
214
|
-
end
|
215
|
-
|
216
|
-
let(:flags) do
|
217
|
-
{ :primary => false, :provision => false, :execution => false }
|
218
|
-
end
|
219
|
-
|
220
|
-
it 'gets fqdn from flagged interfaces if not preferring ips' do
|
221
|
-
# falling to primary interface
|
222
|
-
assert_equal 'somehost.somedomain.org', SSHExecutionProvider.find_ip_or_hostname(host)
|
223
|
-
|
224
|
-
# execution wins if present
|
225
|
-
execution_interface = FactoryBot.build(:nic_managed,
|
226
|
-
flags.merge(:execution => true, :name => 'special.somedomain.org'))
|
227
|
-
host.interfaces << execution_interface
|
228
|
-
host.primary_interface.update(:execution => false)
|
229
|
-
host.interfaces.each(&:save)
|
230
|
-
host.reload
|
231
|
-
assert_equal execution_interface.fqdn, SSHExecutionProvider.find_ip_or_hostname(host)
|
232
|
-
end
|
233
|
-
|
234
|
-
it 'gets ip from flagged interfaces' do
|
235
|
-
host.host_params['remote_execution_connect_by_ip'] = true
|
236
|
-
# no ip address set on relevant interface - fallback to fqdn
|
237
|
-
assert_equal 'somehost.somedomain.org', SSHExecutionProvider.find_ip_or_hostname(host)
|
238
|
-
|
239
|
-
# provision interface with ip while primary without
|
240
|
-
provision_interface = FactoryBot.build(:nic_managed,
|
241
|
-
flags.merge(:provision => true, :ip => '10.0.0.1'))
|
242
|
-
host.interfaces << provision_interface
|
243
|
-
host.primary_interface.update(:provision => false)
|
244
|
-
host.interfaces.each(&:save)
|
245
|
-
host.reload
|
246
|
-
assert_equal provision_interface.ip, SSHExecutionProvider.find_ip_or_hostname(host)
|
247
|
-
|
248
|
-
# both primary and provision interface have IPs: the primary wins
|
249
|
-
host.primary_interface.update(:ip => '10.0.0.2', :execution => false)
|
250
|
-
host.reload
|
251
|
-
assert_equal host.primary_interface.ip, SSHExecutionProvider.find_ip_or_hostname(host)
|
252
|
-
|
253
|
-
# there is an execution interface with IP: it wins
|
254
|
-
execution_interface = FactoryBot.build(:nic_managed,
|
255
|
-
flags.merge(:execution => true, :ip => '10.0.0.3'))
|
256
|
-
host.interfaces << execution_interface
|
257
|
-
host.primary_interface.update(:execution => false)
|
258
|
-
host.interfaces.each(&:save)
|
259
|
-
host.reload
|
260
|
-
assert_equal execution_interface.ip, SSHExecutionProvider.find_ip_or_hostname(host)
|
261
|
-
|
262
|
-
# there is an execution interface with both IPv6 and IPv4: IPv4 is being preferred over IPv6 by default
|
263
|
-
execution_interface = FactoryBot.build(:nic_managed,
|
264
|
-
flags.merge(:execution => true, :ip => '10.0.0.4', :ip6 => 'fd00::4'))
|
265
|
-
host.interfaces = [execution_interface]
|
266
|
-
host.interfaces.each(&:save)
|
267
|
-
host.reload
|
268
|
-
assert_equal execution_interface.ip, SSHExecutionProvider.find_ip_or_hostname(host)
|
269
|
-
end
|
270
|
-
|
271
|
-
it 'gets ipv6 from flagged interfaces with IPv6 preference' do
|
272
|
-
host.host_params['remote_execution_connect_by_ip_prefer_ipv6'] = true
|
273
|
-
host.host_params['remote_execution_connect_by_ip'] = true
|
274
|
-
|
275
|
-
# there is an execution interface with both IPv6 and IPv4: IPv6 is being preferred over IPv4 by host parameter configuration
|
276
|
-
execution_interface = FactoryBot.build(:nic_managed,
|
277
|
-
flags.merge(:execution => true, :ip => '10.0.0.4', :ip6 => 'fd00::4'))
|
278
|
-
host.interfaces = [execution_interface]
|
279
|
-
host.interfaces.each(&:save)
|
280
|
-
host.reload
|
281
|
-
assert_equal execution_interface.ip6, SSHExecutionProvider.find_ip_or_hostname(host)
|
282
|
-
end
|
283
|
-
|
284
|
-
it 'gets ipv6 from flagged interfaces with IPv4 preference but without IPv4 address' do
|
285
|
-
host.host_params['remote_execution_connect_by_ip_prefer_ipv6'] = false
|
286
|
-
host.host_params['remote_execution_connect_by_ip'] = true
|
287
|
-
|
288
|
-
# there is an execution interface with both IPv6 and IPv4: IPv6 is being preferred over IPv4 by host parameter configuration
|
289
|
-
execution_interface = FactoryBot.build(:nic_managed,
|
290
|
-
flags.merge(:execution => true, :ip => nil, :ip6 => 'fd00::4'))
|
291
|
-
host.interfaces = [execution_interface]
|
292
|
-
host.interfaces.each(&:save)
|
293
|
-
host.reload
|
294
|
-
assert_equal execution_interface.ip6, SSHExecutionProvider.find_ip_or_hostname(host)
|
295
|
-
end
|
296
|
-
end
|
297
|
-
end
|
298
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'test_plugin_helper'
|
2
|
-
|
3
|
-
class RendererScopeInputTest < ActiveSupport::TestCase
|
4
|
-
let(:source) { Foreman::Renderer::Source::String.new(content: '') }
|
5
|
-
|
6
|
-
describe 'caching helper in real mode' do
|
7
|
-
let(:input) do
|
8
|
-
input = ForemanRemoteExecution::Renderer::Scope::Input.new(source: source)
|
9
|
-
input.stubs(:invocation => OpenStruct.new(:job_invocation_id => 1))
|
10
|
-
input
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'caches the value under given key' do
|
14
|
-
i = 1
|
15
|
-
result = input.cached('some_key') { i }
|
16
|
-
assert_equal 1, result
|
17
|
-
|
18
|
-
i += 1
|
19
|
-
result = input.cached('some_key') { i }
|
20
|
-
assert_equal 1, result
|
21
|
-
|
22
|
-
i += 1
|
23
|
-
result = input.cached('different_key') { i }
|
24
|
-
assert_equal 3, result
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
describe 'caching helper in preview mode' do
|
29
|
-
let(:input) do
|
30
|
-
input = ForemanRemoteExecution::Renderer::Scope::Input.new(source: source)
|
31
|
-
input.stubs(:invocation => OpenStruct.new(:job_invocation_id => 1), :preview? => true)
|
32
|
-
input
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'does not cache the value' do
|
36
|
-
i = 1
|
37
|
-
result = input.cached('some_key') { i }
|
38
|
-
assert_equal 1, result
|
39
|
-
|
40
|
-
i += 1
|
41
|
-
result = input.cached('some_key') { i }
|
42
|
-
assert_equal 2, result
|
43
|
-
|
44
|
-
i += 1
|
45
|
-
result = input.cached('different_key') { i }
|
46
|
-
assert_equal 3, result
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
data/test/unit/targeting_test.rb
DELETED
@@ -1,206 +0,0 @@
|
|
1
|
-
require 'test_plugin_helper'
|
2
|
-
|
3
|
-
class TargetingTest < ActiveSupport::TestCase
|
4
|
-
let(:targeting) { FactoryBot.build(:targeting) }
|
5
|
-
let(:bookmark) { bookmarks(:one) }
|
6
|
-
let(:host) { FactoryBot.create(:host) }
|
7
|
-
|
8
|
-
before do
|
9
|
-
bookmark.query = 'name = bar'
|
10
|
-
end
|
11
|
-
|
12
|
-
describe '#resolved?' do
|
13
|
-
context 'resolved_at is nil' do
|
14
|
-
before { targeting.resolved_at = nil }
|
15
|
-
it { assert_not targeting.resolved? }
|
16
|
-
end
|
17
|
-
|
18
|
-
context 'resolved_at is set' do
|
19
|
-
before { targeting.resolved_at = Time.now.getlocal }
|
20
|
-
it { assert targeting.resolved? }
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
context 'able to be created with search term' do
|
26
|
-
before { targeting.search_query = 'name = foo' }
|
27
|
-
it { assert targeting.save }
|
28
|
-
end
|
29
|
-
|
30
|
-
context 'able to be created with a bookmark' do
|
31
|
-
before do
|
32
|
-
targeting.search_query = nil
|
33
|
-
targeting.bookmark = bookmark
|
34
|
-
end
|
35
|
-
it { assert_valid targeting }
|
36
|
-
end
|
37
|
-
|
38
|
-
context 'cannot create without search term or bookmark' do
|
39
|
-
before do
|
40
|
-
targeting.targeting_type = Targeting::DYNAMIC_TYPE
|
41
|
-
targeting.search_query = ''
|
42
|
-
targeting.bookmark = nil
|
43
|
-
end
|
44
|
-
it { refute_valid targeting }
|
45
|
-
end
|
46
|
-
|
47
|
-
context 'can resolve hosts via query' do
|
48
|
-
before do
|
49
|
-
targeting.user = users(:admin)
|
50
|
-
targeting.search_query = "name = #{host.name}"
|
51
|
-
targeting.resolve_hosts!
|
52
|
-
end
|
53
|
-
|
54
|
-
it { assert_includes targeting.hosts, host }
|
55
|
-
end
|
56
|
-
|
57
|
-
context 'can delete a user' do
|
58
|
-
before do
|
59
|
-
targeting.user = users(:one)
|
60
|
-
targeting.save!
|
61
|
-
users(:one).destroy
|
62
|
-
end
|
63
|
-
|
64
|
-
it { assert_nil targeting.reload.user }
|
65
|
-
it do
|
66
|
-
assert_raises(Foreman::Exception) { targeting.resolve_hosts! }
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
context 'can delete a host' do
|
71
|
-
before do
|
72
|
-
targeting.hosts << host
|
73
|
-
targeting.save!
|
74
|
-
host.destroy
|
75
|
-
end
|
76
|
-
|
77
|
-
it { assert_empty targeting.reload.hosts }
|
78
|
-
end
|
79
|
-
|
80
|
-
describe '#resolve_hosts!' do
|
81
|
-
let(:second_host) { FactoryBot.create(:host) }
|
82
|
-
let(:infra_host) { FactoryBot.create(:host, :with_infrastructure_facet) }
|
83
|
-
let(:targeting) { FactoryBot.build(:targeting) }
|
84
|
-
|
85
|
-
before do
|
86
|
-
host
|
87
|
-
second_host
|
88
|
-
infra_host
|
89
|
-
end
|
90
|
-
|
91
|
-
context 'with infrastructure host permission' do
|
92
|
-
before do
|
93
|
-
setup_user('view', 'hosts')
|
94
|
-
setup_user('execute_jobs_on', 'infrastructure_hosts')
|
95
|
-
end
|
96
|
-
|
97
|
-
it 'resolves all hosts' do
|
98
|
-
hosts = [host, second_host, infra_host]
|
99
|
-
targeting.search_query = "name ^ (#{hosts.map(&:name).join(',')})"
|
100
|
-
targeting.user = User.current
|
101
|
-
targeting.resolve_hosts!
|
102
|
-
|
103
|
-
assert_includes targeting.hosts, host
|
104
|
-
assert_includes targeting.hosts, second_host
|
105
|
-
assert_includes targeting.hosts, infra_host
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
context 'without infrastructure host permission' do
|
110
|
-
before { setup_user('view', 'hosts') }
|
111
|
-
|
112
|
-
it 'ignores infrastructure hosts' do
|
113
|
-
hosts = [host, second_host, infra_host]
|
114
|
-
targeting.search_query = "name ^ (#{hosts.map(&:name).join(',')})"
|
115
|
-
targeting.user = User.current
|
116
|
-
targeting.resolve_hosts!
|
117
|
-
|
118
|
-
assert_includes targeting.hosts, host
|
119
|
-
assert_includes targeting.hosts, second_host
|
120
|
-
refute_includes targeting.hosts, infra_host
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
describe '#build_query_from_hosts(ids)' do
|
126
|
-
let(:second_host) { FactoryBot.create(:host) }
|
127
|
-
let(:infra_host) { FactoryBot.create(:host, :with_infrastructure_facet) }
|
128
|
-
|
129
|
-
before do
|
130
|
-
host
|
131
|
-
second_host
|
132
|
-
infra_host
|
133
|
-
end
|
134
|
-
|
135
|
-
context 'for two hosts' do
|
136
|
-
let(:query) { Targeting.build_query_from_hosts([ host.id, second_host.id, infra_host.id ]) }
|
137
|
-
|
138
|
-
it 'builds query using host names joining inside ^' do
|
139
|
-
assert_includes query, host.name
|
140
|
-
assert_includes query, second_host.name
|
141
|
-
assert_includes query, infra_host.name
|
142
|
-
assert_includes query, 'name ^'
|
143
|
-
|
144
|
-
assert_includes Host.search_for(query), host
|
145
|
-
assert_includes Host.search_for(query), second_host
|
146
|
-
assert_includes Host.search_for(query), infra_host
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
context 'for one host' do
|
151
|
-
let(:query) { Targeting.build_query_from_hosts([ host.id ]) }
|
152
|
-
|
153
|
-
it 'builds query using host name' do
|
154
|
-
assert_equal "name ^ (#{host.name})", query
|
155
|
-
assert_includes Host.search_for(query), host
|
156
|
-
refute_includes Host.search_for(query), second_host
|
157
|
-
refute_includes Host.search_for(query), infra_host
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
context 'for no id' do
|
162
|
-
let(:query) { Targeting.build_query_from_hosts([]) }
|
163
|
-
|
164
|
-
it 'builds query to find all hosts' do
|
165
|
-
assert_includes Host.search_for(query), host
|
166
|
-
assert_includes Host.search_for(query), second_host
|
167
|
-
assert_includes Host.search_for(query), infra_host
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
context 'without infrastructure host permission' do
|
172
|
-
before { User.current = nil }
|
173
|
-
|
174
|
-
it 'ignores the infrastructure host' do
|
175
|
-
query = Targeting.build_query_from_hosts([host.id, second_host.id, infra_host.id])
|
176
|
-
assert_includes query, host.name
|
177
|
-
assert_includes query, second_host.name
|
178
|
-
refute_includes query, infra_host.name
|
179
|
-
assert_includes query, 'name ^'
|
180
|
-
|
181
|
-
assert_includes Host.search_for(query), host
|
182
|
-
assert_includes Host.search_for(query), second_host
|
183
|
-
refute_includes Host.search_for(query), infra_host
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
context 'randomized ordering' do
|
189
|
-
let(:targeting) { FactoryBot.build(:targeting, :with_randomized_ordering) }
|
190
|
-
let(:hosts) { (0..4).map { FactoryBot.create(:host) } }
|
191
|
-
|
192
|
-
it 'loads the hosts in random order' do
|
193
|
-
rng = Random.new(4) # Chosen by a fair dice roll
|
194
|
-
Random.stubs(:new).returns(rng)
|
195
|
-
hosts
|
196
|
-
targeting.search_query = 'name ~ host*'
|
197
|
-
targeting.user = users(:admin)
|
198
|
-
targeting.resolve_hosts!
|
199
|
-
randomized_host_ids = targeting.hosts.map(&:id)
|
200
|
-
host_ids = hosts.map(&:id)
|
201
|
-
|
202
|
-
assert_not_equal host_ids, randomized_host_ids
|
203
|
-
assert_equal host_ids, randomized_host_ids.sort
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'test_plugin_helper'
|
2
|
-
|
3
|
-
class TemplateInvocationInputTest < ActiveSupport::TestCase
|
4
|
-
let(:template) { FactoryBot.build(:job_template, :template => 'service restart <%= input("service_name") -%>') }
|
5
|
-
let(:renderer) { InputTemplateRenderer.new(template) }
|
6
|
-
let(:job_invocation) { FactoryBot.create(:job_invocation) }
|
7
|
-
let(:template_invocation) { FactoryBot.build(:template_invocation, :template => template) }
|
8
|
-
let(:result) { renderer.render }
|
9
|
-
|
10
|
-
context 'with selectable options' do
|
11
|
-
before do
|
12
|
-
result # let is lazy
|
13
|
-
template.template_inputs << FactoryBot.build(:template_input, :name => 'service_name', :input_type => 'user',
|
14
|
-
:required => true, :options => "foreman\nhttpd")
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'fails with an invalid option' do
|
18
|
-
refute_valid FactoryBot.build(:template_invocation_input_value, :template_invocation => template_invocation,
|
19
|
-
:template_input => template.template_inputs.first,
|
20
|
-
:value => 'sendmail')
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'succeeds with valid option' do
|
24
|
-
assert_valid FactoryBot.build(:template_invocation_input_value, :template_invocation => template_invocation,
|
25
|
-
:template_input => template.template_inputs.first,
|
26
|
-
:value => 'foreman')
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'supports large inputs' do
|
31
|
-
template.template_inputs << FactoryBot.build(:template_input, :name => 'service_name',
|
32
|
-
:input_type => 'user', :required => true)
|
33
|
-
assert_valid FactoryBot.create(:template_invocation_input_value,
|
34
|
-
:template_invocation => template_invocation,
|
35
|
-
:template_input => template.template_inputs.first,
|
36
|
-
:value => 'foreman' * 1_000_000)
|
37
|
-
end
|
38
|
-
end
|