foreman_remote_execution 1.4.5 → 1.4.6
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 +5 -5
- data/.hound.yml +13 -0
- data/.rubocop.yml +9 -0
- data/app/controllers/api/v2/job_invocations_controller.rb +49 -6
- data/app/controllers/job_invocations_controller.rb +29 -1
- data/app/helpers/remote_execution_helper.rb +5 -5
- data/app/lib/actions/remote_execution/run_host_job.rb +32 -20
- data/app/lib/actions/remote_execution/run_hosts_job.rb +13 -8
- data/app/models/foreign_input_set.rb +1 -1
- data/app/models/job_invocation.rb +23 -1
- data/app/models/job_invocation_composer.rb +25 -3
- data/app/models/job_template.rb +2 -2
- data/app/models/remote_execution_feature.rb +22 -10
- data/app/models/setting/remote_execution.rb +34 -10
- data/app/models/ssh_execution_provider.rb +8 -0
- data/app/models/template_input.rb +1 -1
- data/app/views/api/v2/job_templates/base.json.rabl +1 -1
- data/app/views/job_invocations/_form.html.erb +11 -5
- data/app/views/job_invocations/_tab_hosts.html.erb +1 -1
- data/app/views/job_invocations/index.html.erb +1 -1
- data/app/views/job_templates/index.html.erb +1 -1
- data/app/views/remote_execution_features/index.html.erb +1 -1
- data/app/views/template_inputs/_invocation_form.html.erb +2 -2
- data/app/views/template_invocations/show.html.erb +1 -1
- data/config/routes.rb +5 -0
- data/db/migrate/20160113162007_expand_all_template_invocations.rb +1 -1
- data/db/migrate/20171129103615_add_secrets_to_job_invocations.rb +6 -0
- data/db/migrate/20180202072115_add_notification_builder_to_remote_execution_feature.rb +5 -0
- data/db/migrate/20180202123215_add_feature_id_to_job_invocation.rb +6 -0
- data/db/migrate/20180226095631_change_task_id_to_uuid.rb +31 -0
- data/foreman_remote_execution.gemspec +1 -1
- data/lib/foreman_remote_execution/engine.rb +3 -1
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/test/factories/foreman_remote_execution_factories.rb +6 -0
- data/test/functional/api/v2/job_invocations_controller_test.rb +139 -32
- data/test/functional/job_invocations_controller_test.rb +49 -0
- data/test/unit/actions/run_hosts_job_test.rb +10 -6
- data/test/unit/concerns/foreman_tasks_cleaner_extensions_test.rb +1 -1
- data/test/unit/job_invocation_composer_test.rb +43 -1
- metadata +14 -10
- data/app/models/concerns/foreman_remote_execution/exportable.rb +0 -71
- data/test/unit/concerns/exportable_test.rb +0 -88
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_plugin_helper'
|
4
|
+
|
5
|
+
class JobInvocationsControllerTest < ActionController::TestCase
|
6
|
+
test 'should parse inputs coming from the URL params' do
|
7
|
+
template = FactoryBot.create(:job_template, :with_input)
|
8
|
+
feature = FactoryBot.create(:remote_execution_feature,
|
9
|
+
:job_template => template)
|
10
|
+
params = {
|
11
|
+
feature: feature.label,
|
12
|
+
inputs: { template.template_inputs.first.name => 'foobar' }
|
13
|
+
}
|
14
|
+
|
15
|
+
get :new, params: params, session: set_session_user
|
16
|
+
template_invocation_params = [
|
17
|
+
{
|
18
|
+
'input_values' =>
|
19
|
+
[
|
20
|
+
{
|
21
|
+
'value' => 'foobar',
|
22
|
+
'template_input_id' => template.template_inputs.first.id
|
23
|
+
}
|
24
|
+
],
|
25
|
+
'template_id' => template.id
|
26
|
+
}
|
27
|
+
]
|
28
|
+
assert_equal(template_invocation_params,
|
29
|
+
assigns(:composer).params['template_invocations'])
|
30
|
+
end
|
31
|
+
|
32
|
+
test 'should allow no inputs' do
|
33
|
+
template = FactoryBot.create(:job_template)
|
34
|
+
feature = FactoryBot.create(:remote_execution_feature,
|
35
|
+
:job_template => template)
|
36
|
+
params = {
|
37
|
+
feature: feature.label,
|
38
|
+
}
|
39
|
+
get :new, params: params, session: set_session_user
|
40
|
+
template_invocation_params = [
|
41
|
+
{
|
42
|
+
'template_id' => template.id,
|
43
|
+
'input_values' => {}
|
44
|
+
}
|
45
|
+
]
|
46
|
+
assert_equal(template_invocation_params,
|
47
|
+
assigns(:composer).params['template_invocations'])
|
48
|
+
end
|
49
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
1
|
require 'test_plugin_helper'
|
2
|
+
require 'securerandom'
|
3
3
|
|
4
4
|
module ForemanRemoteExecution
|
5
5
|
class RunHostsJobTest < ActiveSupport::TestCase
|
@@ -12,12 +12,15 @@ module ForemanRemoteExecution
|
|
12
12
|
FactoryBot.build(:job_invocation, :with_template).tap do |invocation|
|
13
13
|
invocation.targeting = targeting
|
14
14
|
invocation.description = 'Some short description'
|
15
|
+
invocation.password = 'changeme'
|
16
|
+
invocation.key_passphrase = 'changemetoo'
|
15
17
|
invocation.save
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
21
|
+
let(:uuid) { SecureRandom.uuid }
|
19
22
|
let(:task) do
|
20
|
-
OpenStruct.new(:id =>
|
23
|
+
OpenStruct.new(:id => uuid).tap do |o|
|
21
24
|
o.stubs(:add_missing_task_groups)
|
22
25
|
o.stubs(:task_groups).returns([])
|
23
26
|
end
|
@@ -76,15 +79,16 @@ module ForemanRemoteExecution
|
|
76
79
|
|
77
80
|
it 'uses the BindJobInvocation middleware' do
|
78
81
|
planned
|
79
|
-
job_invocation.task_id.must_equal
|
82
|
+
job_invocation.task_id.must_equal uuid
|
80
83
|
end
|
81
84
|
|
82
85
|
# In plan phase this is handled by #action_subject
|
83
86
|
# which is expected in tests
|
84
87
|
it 'sets input in delay phase when delayed' do
|
85
|
-
delayed.input[:job_invocation]
|
86
|
-
|
87
|
-
|
88
|
+
job_invocation_hash = delayed.input[:job_invocation]
|
89
|
+
job_invocation_hash['id'].must_equal job_invocation.id
|
90
|
+
job_invocation_hash['name'].must_equal job_invocation.job_category
|
91
|
+
job_invocation_hash['description'].must_equal job_invocation.description
|
88
92
|
planned # To make the expectations happy
|
89
93
|
end
|
90
94
|
|
@@ -14,7 +14,7 @@ class ForemanRemoteExecutionForemanTasksCleanerExtensionsTest < ActiveSupport::T
|
|
14
14
|
job.reload
|
15
15
|
job.task.must_be :nil?
|
16
16
|
job.task_id.wont_be :nil?
|
17
|
-
ForemanTasks::Cleaner.new(:filter => '
|
17
|
+
ForemanTasks::Cleaner.new(:filter => '').delete
|
18
18
|
JobInvocation.where(:id => job.id).must_be :empty?
|
19
19
|
end
|
20
20
|
end
|
@@ -412,6 +412,7 @@ class JobInvocationComposerTest < ActiveSupport::TestCase
|
|
412
412
|
}
|
413
413
|
} }
|
414
414
|
end
|
415
|
+
|
415
416
|
let(:params) do
|
416
417
|
{ :job_invocation => { :providers => { :ssh => ssh_params } }, :targeting => { :search_query => "name = #{host.name}" } }.with_indifferent_access
|
417
418
|
end
|
@@ -476,6 +477,30 @@ class JobInvocationComposerTest < ActiveSupport::TestCase
|
|
476
477
|
end
|
477
478
|
end
|
478
479
|
|
480
|
+
describe '#password' do
|
481
|
+
let(:password) { 'changeme' }
|
482
|
+
let(:params) do
|
483
|
+
{ :job_invocation => { :password => password }}.with_indifferent_access
|
484
|
+
end
|
485
|
+
|
486
|
+
it 'sets the password properly' do
|
487
|
+
composer
|
488
|
+
composer.job_invocation.password.must_equal password
|
489
|
+
end
|
490
|
+
end
|
491
|
+
|
492
|
+
describe '#key_passphrase' do
|
493
|
+
let(:key_passphrase) { 'changeme' }
|
494
|
+
let(:params) do
|
495
|
+
{ :job_invocation => { :key_passphrase => key_passphrase }}
|
496
|
+
end
|
497
|
+
|
498
|
+
it 'sets the key passphrase properly' do
|
499
|
+
composer
|
500
|
+
composer.job_invocation.key_passphrase.must_equal key_passphrase
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
479
504
|
describe '#targeting' do
|
480
505
|
it 'triggers targeting on job_invocation' do
|
481
506
|
composer
|
@@ -630,7 +655,7 @@ class JobInvocationComposerTest < ActiveSupport::TestCase
|
|
630
655
|
},
|
631
656
|
:targeting_type => 'static_query',
|
632
657
|
:search_query => 'some hosts',
|
633
|
-
:inputs => {input1.name => 'some_value'}}
|
658
|
+
:inputs => { input1.name => 'some_value' } }
|
634
659
|
end
|
635
660
|
|
636
661
|
it 'sets the concurrency level and time span based on the input' do
|
@@ -640,6 +665,23 @@ class JobInvocationComposerTest < ActiveSupport::TestCase
|
|
640
665
|
end
|
641
666
|
end
|
642
667
|
|
668
|
+
context 'with rex feature defined' do
|
669
|
+
let(:feature) { FactoryBot.create(:remote_execution_feature) }
|
670
|
+
let(:params) do
|
671
|
+
{ :job_category => trying_job_template_1.job_category,
|
672
|
+
:job_template_id => trying_job_template_1.id,
|
673
|
+
:remote_execution_feature_id => feature.id,
|
674
|
+
:targeting_type => 'static_query',
|
675
|
+
:search_query => 'some hosts',
|
676
|
+
:inputs => { input1.name => 'some_value' } }
|
677
|
+
end
|
678
|
+
|
679
|
+
it 'sets the remote execution feature based on the input' do
|
680
|
+
assert composer.save!
|
681
|
+
composer.job_invocation.remote_execution_feature.must_equal feature
|
682
|
+
end
|
683
|
+
end
|
684
|
+
|
643
685
|
context 'with invalid targeting' do
|
644
686
|
let(:params) do
|
645
687
|
{ :job_category => trying_job_template_1.job_category,
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_remote_execution
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Foreman Remote Execution team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: deface
|
@@ -56,16 +56,16 @@ dependencies:
|
|
56
56
|
name: foreman-tasks
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0.
|
61
|
+
version: '0.12'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 0.
|
68
|
+
version: '0.12'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: factory_bot_rails
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -119,6 +119,7 @@ extra_rdoc_files:
|
|
119
119
|
- LICENSE
|
120
120
|
files:
|
121
121
|
- ".gitignore"
|
122
|
+
- ".hound.yml"
|
122
123
|
- ".rubocop.yml"
|
123
124
|
- ".rubocop_todo.yml"
|
124
125
|
- ".tx/config"
|
@@ -158,7 +159,6 @@ files:
|
|
158
159
|
- app/mailers/.gitkeep
|
159
160
|
- app/models/concerns/foreman_remote_execution/bookmark_extensions.rb
|
160
161
|
- app/models/concerns/foreman_remote_execution/errors_flattener.rb
|
161
|
-
- app/models/concerns/foreman_remote_execution/exportable.rb
|
162
162
|
- app/models/concerns/foreman_remote_execution/foreman_tasks_cleaner_extensions.rb
|
163
163
|
- app/models/concerns/foreman_remote_execution/foreman_tasks_task_extensions.rb
|
164
164
|
- app/models/concerns/foreman_remote_execution/foreman_tasks_triggering_extensions.rb
|
@@ -294,8 +294,12 @@ files:
|
|
294
294
|
- db/migrate/20160926225841_update_template_input_value.rb
|
295
295
|
- db/migrate/20170110145641_add_host_action_button_to_remote_execution_feature.rb
|
296
296
|
- db/migrate/20170613101039_add_timeout_to_job_templates_and_job_invocations.rb
|
297
|
+
- db/migrate/20171129103615_add_secrets_to_job_invocations.rb
|
297
298
|
- db/migrate/20180110104432_rename_template_invocation_permission.rb
|
298
299
|
- db/migrate/20180112125015_fix_taxable_taxonomies_job_template.rb
|
300
|
+
- db/migrate/20180202072115_add_notification_builder_to_remote_execution_feature.rb
|
301
|
+
- db/migrate/20180202123215_add_feature_id_to_job_invocation.rb
|
302
|
+
- db/migrate/20180226095631_change_task_id_to_uuid.rb
|
299
303
|
- db/seeds.d/50-notification_blueprints.rb
|
300
304
|
- db/seeds.d/60-ssh_proxy_feature.rb
|
301
305
|
- db/seeds.d/70-job_templates.rb
|
@@ -339,9 +343,9 @@ files:
|
|
339
343
|
- test/functional/api/v2/job_templates_controller_test.rb
|
340
344
|
- test/functional/api/v2/remote_execution_features_controller_test.rb
|
341
345
|
- test/functional/api/v2/template_inputs_controller_test.rb
|
346
|
+
- test/functional/job_invocations_controller_test.rb
|
342
347
|
- test/test_plugin_helper.rb
|
343
348
|
- test/unit/actions/run_hosts_job_test.rb
|
344
|
-
- test/unit/concerns/exportable_test.rb
|
345
349
|
- test/unit/concerns/foreman_tasks_cleaner_extensions_test.rb
|
346
350
|
- test/unit/concerns/host_extensions_test.rb
|
347
351
|
- test/unit/concerns/nic_extensions_test.rb
|
@@ -376,7 +380,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
376
380
|
version: '0'
|
377
381
|
requirements: []
|
378
382
|
rubyforge_project:
|
379
|
-
rubygems_version: 2.
|
383
|
+
rubygems_version: 2.7.3
|
380
384
|
signing_key:
|
381
385
|
specification_version: 4
|
382
386
|
summary: A plugin bringing remote execution to the Foreman, completing the config
|
@@ -390,9 +394,9 @@ test_files:
|
|
390
394
|
- test/functional/api/v2/job_templates_controller_test.rb
|
391
395
|
- test/functional/api/v2/remote_execution_features_controller_test.rb
|
392
396
|
- test/functional/api/v2/template_inputs_controller_test.rb
|
397
|
+
- test/functional/job_invocations_controller_test.rb
|
393
398
|
- test/test_plugin_helper.rb
|
394
399
|
- test/unit/actions/run_hosts_job_test.rb
|
395
|
-
- test/unit/concerns/exportable_test.rb
|
396
400
|
- test/unit/concerns/foreman_tasks_cleaner_extensions_test.rb
|
397
401
|
- test/unit/concerns/host_extensions_test.rb
|
398
402
|
- test/unit/concerns/nic_extensions_test.rb
|
@@ -1,71 +0,0 @@
|
|
1
|
-
# This concern makes it easy to export an ActiveRecord object with specified
|
2
|
-
# attributes and associations in a particular format. If a specified
|
3
|
-
# assocation also includes this concern, then it will likewise be exported.
|
4
|
-
#
|
5
|
-
# Custom attributes can be specified with a custom export lambda in an options
|
6
|
-
# hash.
|
7
|
-
#
|
8
|
-
# Example:
|
9
|
-
# attr_exportable :name, :address, :company => ->(user) { user.company.name }
|
10
|
-
#
|
11
|
-
module ForemanRemoteExecution
|
12
|
-
module Exportable
|
13
|
-
extend ActiveSupport::Concern
|
14
|
-
|
15
|
-
def to_export(include_blank = true)
|
16
|
-
self.class.exportable_attributes.keys.inject({}) do |hash, attribute|
|
17
|
-
value = export_attr(attribute, self.class.exportable_attributes[attribute], include_blank)
|
18
|
-
|
19
|
-
# Rails considers false blank, but if a boolean value is explicitly set false, we want to ensure we export it.
|
20
|
-
if include_blank || value.present? || value == false
|
21
|
-
hash.update(attribute => value)
|
22
|
-
else
|
23
|
-
hash
|
24
|
-
end
|
25
|
-
end.stringify_keys
|
26
|
-
end
|
27
|
-
|
28
|
-
# Export a particular attribute or association.
|
29
|
-
# - If our exportable_attributes value is callable, we call it with self as an argument
|
30
|
-
# - If our object is iterable, then we export each item
|
31
|
-
# - If the attribute or association also includes this concern, call to_export on it
|
32
|
-
def export_attr(attribute, exporter, include_blank)
|
33
|
-
value = if exporter.respond_to?(:call)
|
34
|
-
exporter.call(self)
|
35
|
-
elsif self.respond_to?(exporter)
|
36
|
-
self.send(exporter)
|
37
|
-
end
|
38
|
-
|
39
|
-
value = value.respond_to?(:map) ? export_iterable(value, include_blank) : value
|
40
|
-
value.respond_to?(:to_export) ? value.to_export(include_blank) : value
|
41
|
-
end
|
42
|
-
|
43
|
-
# Exports each item in an iterable. If it's a hash, then export each value.
|
44
|
-
def export_iterable(items, include_blank)
|
45
|
-
if items.is_a?(Hash)
|
46
|
-
items.each { |key, value| items[key] = value.respond_to?(:to_export) ? value.to_export(include_blank) : value }
|
47
|
-
items.to_hash.stringify_keys
|
48
|
-
else
|
49
|
-
items.map { |item| item.respond_to?(:to_export) ? item.to_export(include_blank) : item }
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
module ClassMethods
|
54
|
-
attr_reader :exportable_attributes
|
55
|
-
|
56
|
-
# Takes an array of exportable attributes, and a custom exports hash. The
|
57
|
-
# custom exports hash should be a key/lambda pair used to export the
|
58
|
-
# particular attribute.
|
59
|
-
def attr_exportable(*args)
|
60
|
-
@exportable_attributes ||= {}
|
61
|
-
args.each do |arg|
|
62
|
-
if arg.is_a?(Hash)
|
63
|
-
@exportable_attributes.merge!(arg)
|
64
|
-
else
|
65
|
-
@exportable_attributes.merge!(arg => arg)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
@@ -1,88 +0,0 @@
|
|
1
|
-
require 'test_plugin_helper'
|
2
|
-
|
3
|
-
module ForemanRemoteExecution
|
4
|
-
class ExportableTest < ActiveSupport::TestCase
|
5
|
-
class SampleModel
|
6
|
-
include ::ForemanRemoteExecution::Exportable
|
7
|
-
|
8
|
-
attr_accessor :name, :attrs, :subnet, :mac, :password
|
9
|
-
attr_exportable :name, :attrs, :mac, :subnet, :mac => ->(m) { m.mac.upcase if m.mac },
|
10
|
-
:custom_attr => ->(m) { 'hello world' }
|
11
|
-
|
12
|
-
def attributes
|
13
|
-
{
|
14
|
-
'name' => name,
|
15
|
-
'attrs' => attrs,
|
16
|
-
'mac' => mac,
|
17
|
-
'password' => password,
|
18
|
-
'subnet' => subnet
|
19
|
-
}
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class SampleSubnet
|
24
|
-
include ::ForemanRemoteExecution::Exportable
|
25
|
-
|
26
|
-
attr_accessor :name, :network
|
27
|
-
attr_exportable :name, :network
|
28
|
-
|
29
|
-
def attributes
|
30
|
-
{
|
31
|
-
'name' => name,
|
32
|
-
'network' => network
|
33
|
-
}
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def setup
|
38
|
-
@subnet = SampleSubnet.new
|
39
|
-
@subnet.name = 'pxe'
|
40
|
-
@subnet.network = '192.168.122.0'
|
41
|
-
|
42
|
-
@sample = SampleModel.new
|
43
|
-
@sample.name = 'name'
|
44
|
-
@sample.attrs = {'nested' => 'hash'}
|
45
|
-
@sample.subnet = @subnet
|
46
|
-
@sample.mac = 'aa:bb:cc:dd:ee:ff'
|
47
|
-
@sample.password = 'password'
|
48
|
-
end
|
49
|
-
|
50
|
-
test '#to_export includes all specified attributes' do
|
51
|
-
assert_equal %w(name attrs mac subnet custom_attr), @sample.to_export.keys
|
52
|
-
end
|
53
|
-
|
54
|
-
test '#to_export does not include all attributes' do
|
55
|
-
assert_not_include @sample.to_export.keys, 'password'
|
56
|
-
end
|
57
|
-
|
58
|
-
test '#to_export calls the lambda' do
|
59
|
-
export = @sample.to_export
|
60
|
-
assert_equal('AA:BB:CC:DD:EE:FF', export['mac'])
|
61
|
-
assert_equal(export['custom_attr'], 'hello world')
|
62
|
-
end
|
63
|
-
|
64
|
-
test '#to_export values are exported recursively' do
|
65
|
-
export = @sample.to_export
|
66
|
-
assert_equal('pxe', export['subnet']['name'])
|
67
|
-
assert_equal('192.168.122.0', export['subnet']['network'])
|
68
|
-
end
|
69
|
-
|
70
|
-
test '#to_export nested hashes are primitive' do
|
71
|
-
@sample.attrs = {:foo => 'bar', :baz => 'qux'}.with_indifferent_access
|
72
|
-
export = @sample.to_export
|
73
|
-
assert_instance_of Hash, export['attrs']
|
74
|
-
end
|
75
|
-
|
76
|
-
test '#to_export includes blank values' do
|
77
|
-
@sample.attrs = {}
|
78
|
-
export = @sample.to_export
|
79
|
-
assert_instance_of Hash, export['attrs']
|
80
|
-
end
|
81
|
-
|
82
|
-
test '#to_export(false) does not include blank values' do
|
83
|
-
@sample.attrs = {}
|
84
|
-
export = @sample.to_export(false)
|
85
|
-
assert_nil export['attrs']
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|