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.
Files changed (42) hide show
  1. checksums.yaml +5 -5
  2. data/.hound.yml +13 -0
  3. data/.rubocop.yml +9 -0
  4. data/app/controllers/api/v2/job_invocations_controller.rb +49 -6
  5. data/app/controllers/job_invocations_controller.rb +29 -1
  6. data/app/helpers/remote_execution_helper.rb +5 -5
  7. data/app/lib/actions/remote_execution/run_host_job.rb +32 -20
  8. data/app/lib/actions/remote_execution/run_hosts_job.rb +13 -8
  9. data/app/models/foreign_input_set.rb +1 -1
  10. data/app/models/job_invocation.rb +23 -1
  11. data/app/models/job_invocation_composer.rb +25 -3
  12. data/app/models/job_template.rb +2 -2
  13. data/app/models/remote_execution_feature.rb +22 -10
  14. data/app/models/setting/remote_execution.rb +34 -10
  15. data/app/models/ssh_execution_provider.rb +8 -0
  16. data/app/models/template_input.rb +1 -1
  17. data/app/views/api/v2/job_templates/base.json.rabl +1 -1
  18. data/app/views/job_invocations/_form.html.erb +11 -5
  19. data/app/views/job_invocations/_tab_hosts.html.erb +1 -1
  20. data/app/views/job_invocations/index.html.erb +1 -1
  21. data/app/views/job_templates/index.html.erb +1 -1
  22. data/app/views/remote_execution_features/index.html.erb +1 -1
  23. data/app/views/template_inputs/_invocation_form.html.erb +2 -2
  24. data/app/views/template_invocations/show.html.erb +1 -1
  25. data/config/routes.rb +5 -0
  26. data/db/migrate/20160113162007_expand_all_template_invocations.rb +1 -1
  27. data/db/migrate/20171129103615_add_secrets_to_job_invocations.rb +6 -0
  28. data/db/migrate/20180202072115_add_notification_builder_to_remote_execution_feature.rb +5 -0
  29. data/db/migrate/20180202123215_add_feature_id_to_job_invocation.rb +6 -0
  30. data/db/migrate/20180226095631_change_task_id_to_uuid.rb +31 -0
  31. data/foreman_remote_execution.gemspec +1 -1
  32. data/lib/foreman_remote_execution/engine.rb +3 -1
  33. data/lib/foreman_remote_execution/version.rb +1 -1
  34. data/test/factories/foreman_remote_execution_factories.rb +6 -0
  35. data/test/functional/api/v2/job_invocations_controller_test.rb +139 -32
  36. data/test/functional/job_invocations_controller_test.rb +49 -0
  37. data/test/unit/actions/run_hosts_job_test.rb +10 -6
  38. data/test/unit/concerns/foreman_tasks_cleaner_extensions_test.rb +1 -1
  39. data/test/unit/job_invocation_composer_test.rb +43 -1
  40. metadata +14 -10
  41. data/app/models/concerns/foreman_remote_execution/exportable.rb +0 -71
  42. 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 => '123').tap do |o|
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 '123'
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]['id'].must_equal job_invocation.id
86
- delayed.input[:job_invocation]['name'].must_equal job_invocation.job_category
87
- delayed.input[:job_invocation]['description'].must_equal job_invocation.description
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 => 'id = 1').delete
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.5
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-02-02 00:00:00.000000000 Z
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.9.5
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.9.5
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.6.8
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