foreman_remote_execution 14.0.2 → 14.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|