foreman_remote_execution 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +7 -0
- data/.rubocop_todo.yml +16 -5
- data/.tx/config +1 -1
- data/app/assets/javascripts/template_invocation.js +14 -1
- data/app/assets/stylesheets/job_invocations.css.scss +0 -13
- data/app/assets/stylesheets/template_invocation.css.scss +7 -13
- data/app/controllers/api/v2/foreign_input_sets_controller.rb +1 -1
- data/app/controllers/api/v2/job_invocations_controller.rb +12 -18
- data/app/controllers/api/v2/remote_execution_features_controller.rb +38 -0
- data/app/controllers/api/v2/template_inputs_controller.rb +1 -0
- data/app/controllers/job_invocations_controller.rb +3 -13
- data/app/controllers/job_templates_controller.rb +1 -1
- data/app/controllers/remote_execution_features_controller.rb +19 -0
- data/app/helpers/concerns/foreman_remote_execution/hosts_helper_extensions.rb +1 -22
- data/app/helpers/remote_execution_helper.rb +30 -12
- data/app/lib/actions/remote_execution/helpers/live_output.rb +2 -2
- data/app/lib/actions/remote_execution/run_host_job.rb +7 -4
- data/app/lib/actions/remote_execution/run_hosts_job.rb +14 -0
- data/app/lib/actions/remote_execution/run_proxy_command.rb +2 -2
- data/app/models/concerns/foreman_remote_execution/host_extensions.rb +5 -4
- data/app/models/concerns/foreman_remote_execution/subnet_extensions.rb +1 -0
- data/app/models/input_template_renderer.rb +14 -3
- data/app/models/job_invocation.rb +6 -15
- data/app/models/job_invocation_composer.rb +131 -21
- data/app/models/job_template.rb +77 -22
- data/app/models/job_template_effective_user.rb +0 -2
- data/app/models/remote_execution_feature.rb +34 -0
- data/app/models/setting/remote_execution.rb +4 -1
- data/app/models/targeting.rb +2 -2
- data/app/models/template_input.rb +17 -13
- data/app/views/api/v2/remote_execution_features/base.json.rabl +3 -0
- data/app/views/api/v2/remote_execution_features/index.json.rabl +3 -0
- data/app/views/api/v2/remote_execution_features/main.json.rabl +3 -0
- data/app/views/api/v2/remote_execution_features/show.json.rabl +3 -0
- data/app/views/job_invocations/_form.html.erb +51 -40
- data/app/views/job_invocations/_preview_hosts_list.html.erb +1 -1
- data/app/views/job_invocations/_tab_hosts.html.erb +6 -3
- data/app/views/job_invocations/index.html.erb +11 -11
- data/app/views/job_templates/_custom_tabs.html.erb +4 -4
- data/app/views/job_templates/index.html.erb +5 -5
- data/app/views/overrides/nics/_execution_interface.html.erb +9 -1
- data/app/views/remote_execution_features/_form.html.erb +24 -0
- data/app/views/remote_execution_features/index.html.erb +21 -0
- data/app/views/remote_execution_features/show.html.erb +3 -0
- data/app/views/template_inputs/_form.html.erb +1 -0
- data/app/views/template_inputs/_invocation_form.html.erb +7 -0
- data/app/views/templates/package_action.erb +17 -5
- data/app/views/templates/power_action.erb +22 -0
- data/app/views/templates/puppet_run_once.erb +1 -1
- data/config/routes.rb +4 -0
- data/db/migrate/20160113162007_expand_all_template_invocations.rb +1 -1
- data/db/migrate/20160118124600_create_remote_execution_features.rb +14 -0
- data/db/migrate/20160125155108_make_job_template_name_unique.rb +12 -0
- data/db/migrate/20160127134031_add_advanced_to_template_input.rb +11 -0
- data/db/migrate/20160127162711_reword_puppet_template_description.rb +9 -0
- data/db/migrate/20160203104056_add_concurrency_options_to_job_invocation.rb +6 -0
- data/db/seeds.d/70-job_templates.rb +2 -1
- data/doc/plugins/div_tag.rb +1 -1
- data/doc/plugins/plantuml.rb +1 -1
- data/doc/plugins/tags.rb +7 -8
- data/doc/plugins/toc.rb +0 -1
- data/foreman_remote_execution.gemspec +1 -1
- data/lib/foreman_remote_execution/engine.rb +10 -2
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/locale/action_names.rb +8 -0
- data/locale/en/foreman_remote_execution.po +767 -11
- data/locale/foreman_remote_execution.pot +1026 -8
- data/test/functional/api/v2/foreign_input_sets_controller_test.rb +1 -1
- data/test/functional/api/v2/job_invocations_controller_test.rb +0 -9
- data/test/functional/api/v2/job_templates_controller_test.rb +11 -11
- data/test/functional/api/v2/remote_execution_features_controller_test.rb +35 -0
- data/test/functional/api/v2/template_inputs_controller_test.rb +1 -1
- data/test/unit/actions/run_hosts_job_test.rb +48 -7
- data/test/unit/actions/run_proxy_command_test.rb +1 -1
- data/test/unit/concerns/host_extensions_test.rb +11 -0
- data/test/unit/input_template_renderer_test.rb +4 -4
- data/test/unit/job_invocation_composer_test.rb +52 -2
- data/test/unit/job_invocation_test.rb +1 -1
- data/test/unit/job_template_test.rb +126 -3
- data/test/unit/remote_execution_feature_test.rb +42 -0
- data/test/unit/targeting_test.rb +4 -4
- metadata +26 -7
- data/app/views/job_invocation_task_groups/_job_invocation_task_group.html.erb +0 -31
- data/app/views/unattended/snippets/_remote_execution_ssh_keys.erb +0 -18
- data/db/seeds.d/80-provision_templates.rb +0 -21
@@ -18,7 +18,7 @@ module Api
|
|
18
18
|
end
|
19
19
|
|
20
20
|
test 'should get input set detail' do
|
21
|
-
get :show,
|
21
|
+
get :show, :template_id => @template.to_param, :id => @input_set.to_param
|
22
22
|
assert_response :success
|
23
23
|
input_set = ActiveSupport::JSON.decode(@response.body)
|
24
24
|
assert !input_set.empty?
|
@@ -23,15 +23,6 @@ module Api
|
|
23
23
|
assert_equal template['job_category'], @invocation.job_category
|
24
24
|
end
|
25
25
|
|
26
|
-
test 'should create valid without job_template_id' do
|
27
|
-
attrs = { :job_category => @template.job_category, :name => 'RandomName', :targeting_type => 'static_query', :search_query => 'foobar'}
|
28
|
-
post :create, :job_invocation => attrs
|
29
|
-
|
30
|
-
invocation = ActiveSupport::JSON.decode(@response.body)
|
31
|
-
assert_equal attrs[:job_category], invocation['job_category']
|
32
|
-
assert_response :success
|
33
|
-
end
|
34
|
-
|
35
26
|
test 'should create valid with job_template_id' do
|
36
27
|
attrs = { :job_category => @template.job_category, :name => 'RandomName', :job_template_id => @template.id,
|
37
28
|
:targeting_type => 'static_query', :search_query => 'foobar'}
|
@@ -15,7 +15,7 @@ module Api
|
|
15
15
|
end
|
16
16
|
|
17
17
|
test 'should get template detail' do
|
18
|
-
get :show,
|
18
|
+
get :show, :id => @template.to_param
|
19
19
|
assert_response :success
|
20
20
|
template = ActiveSupport::JSON.decode(@response.body)
|
21
21
|
assert !template.empty?
|
@@ -25,7 +25,7 @@ module Api
|
|
25
25
|
test 'should create valid' do
|
26
26
|
JobTemplate.any_instance.stubs(:valid?).returns(true)
|
27
27
|
valid_attrs = { :template => 'This is a test template', :name => 'RandomName', :provider_type => 'ssh' }
|
28
|
-
post :create,
|
28
|
+
post :create, :job_template => valid_attrs
|
29
29
|
template = ActiveSupport::JSON.decode(@response.body)
|
30
30
|
assert template['name'] == 'RandomName'
|
31
31
|
assert_response :success
|
@@ -38,26 +38,26 @@ module Api
|
|
38
38
|
|
39
39
|
test 'should update valid' do
|
40
40
|
JobTemplate.any_instance.stubs(:valid?).returns(true)
|
41
|
-
put :update,
|
42
|
-
|
41
|
+
put :update, :id => @template.to_param,
|
42
|
+
:job_template => { :template => 'blah' }
|
43
43
|
assert_response :ok
|
44
44
|
end
|
45
45
|
|
46
46
|
test 'should not update invalid' do
|
47
|
-
put :update,
|
48
|
-
|
47
|
+
put :update, :id => @template.to_param,
|
48
|
+
:job_template => { :name => '' }
|
49
49
|
assert_response :unprocessable_entity
|
50
50
|
end
|
51
51
|
|
52
52
|
test 'should destroy' do
|
53
|
-
delete :destroy,
|
53
|
+
delete :destroy, :id => @template.to_param
|
54
54
|
assert_response :ok
|
55
55
|
refute JobTemplate.exists?(@template.id)
|
56
56
|
end
|
57
57
|
|
58
58
|
test 'should clone template' do
|
59
|
-
post :clone,
|
60
|
-
|
59
|
+
post :clone, :id => @template.to_param,
|
60
|
+
:job_template => {:name => 'MyClone'}
|
61
61
|
assert_response :success
|
62
62
|
template = ActiveSupport::JSON.decode(@response.body)
|
63
63
|
assert_equal(template['name'], 'MyClone')
|
@@ -65,8 +65,8 @@ module Api
|
|
65
65
|
end
|
66
66
|
|
67
67
|
test 'clone name should not be blank' do
|
68
|
-
post :clone,
|
69
|
-
|
68
|
+
post :clone, :id => @template.to_param,
|
69
|
+
:job_template => {:name => ''}
|
70
70
|
assert_response :unprocessable_entity
|
71
71
|
end
|
72
72
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test_plugin_helper'
|
2
|
+
|
3
|
+
module Api
|
4
|
+
module V2
|
5
|
+
class RemoteExecutionFeaturesControllerTest < ActionController::TestCase
|
6
|
+
setup do
|
7
|
+
@remote_execution_feature = RemoteExecutionFeature.register(:my_awesome_feature, 'My awesome feature',
|
8
|
+
:description => 'You will not believe what it does',
|
9
|
+
:provided_inputs => ['awesomeness_level'])
|
10
|
+
@template = FactoryGirl.create(:job_template, :with_input)
|
11
|
+
end
|
12
|
+
|
13
|
+
test 'should get index' do
|
14
|
+
get :index
|
15
|
+
remote_execution_features = ActiveSupport::JSON.decode(@response.body)
|
16
|
+
refute remote_execution_features.empty?, 'Should respond with input sets'
|
17
|
+
assert_response :success
|
18
|
+
end
|
19
|
+
|
20
|
+
test 'should get input set detail' do
|
21
|
+
get :show, :id => @remote_execution_feature.to_param
|
22
|
+
assert_response :success
|
23
|
+
remote_execution_feature = ActiveSupport::JSON.decode(@response.body)
|
24
|
+
refute remote_execution_feature.empty?
|
25
|
+
assert_equal remote_execution_feature['name'], @remote_execution_feature.name
|
26
|
+
end
|
27
|
+
|
28
|
+
test 'should update valid' do
|
29
|
+
put :update, :id => @remote_execution_feature.to_param,
|
30
|
+
:job_template_id => @template.id
|
31
|
+
assert_response :ok
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -16,7 +16,7 @@ module Api
|
|
16
16
|
end
|
17
17
|
|
18
18
|
test 'should get input detail' do
|
19
|
-
get :show,
|
19
|
+
get :show, :template_id => @template.to_param, :id => @input.to_param
|
20
20
|
assert_response :success
|
21
21
|
input = ActiveSupport::JSON.decode(@response.body)
|
22
22
|
assert !input.empty?
|
@@ -22,10 +22,13 @@ module ForemanRemoteExecution
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
let(:action) do
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
create_action(Actions::RemoteExecution::RunHostsJob).tap do |action|
|
26
|
+
action.expects(:action_subject).with(job_invocation)
|
27
|
+
ForemanTasks::Task::DynflowTask.stubs(:where).returns(mock.tap { |m| m.stubs(:first! => task) })
|
28
|
+
end
|
29
|
+
end
|
30
|
+
let(:planned) do
|
31
|
+
plan_action action, job_invocation
|
29
32
|
end
|
30
33
|
|
31
34
|
before do
|
@@ -35,17 +38,55 @@ module ForemanRemoteExecution
|
|
35
38
|
end
|
36
39
|
|
37
40
|
it 'resolves the hosts on targeting in plan phase' do
|
41
|
+
planned
|
38
42
|
targeting.hosts.must_include(host)
|
39
43
|
end
|
40
44
|
|
41
45
|
it 'triggers the RunHostJob actions on the resolved hosts in run phase' do
|
42
|
-
|
43
|
-
|
46
|
+
planned.expects(:trigger).with() { |*args| args[0] == Actions::RemoteExecution::RunHostJob }
|
47
|
+
planned.create_sub_plans
|
44
48
|
end
|
45
49
|
|
46
50
|
it 'uses the BindJobInvocation middleware' do
|
47
|
-
|
51
|
+
planned
|
48
52
|
job_invocation.task_id.must_equal '123'
|
49
53
|
end
|
54
|
+
|
55
|
+
describe 'concurrency control' do
|
56
|
+
let(:level) { 5 }
|
57
|
+
let(:span) { 60 }
|
58
|
+
|
59
|
+
it 'can be disabled' do
|
60
|
+
job_invocation.expects(:concurrency_level)
|
61
|
+
job_invocation.expects(:time_span)
|
62
|
+
action.expects(:limit_concurrency_level).never
|
63
|
+
action.expects(:distribute_over_time).never
|
64
|
+
planned
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'can limit concurrency level' do
|
68
|
+
job_invocation.expects(:concurrency_level).returns(level).twice
|
69
|
+
job_invocation.expects(:time_span)
|
70
|
+
action.expects(:limit_concurrency_level).with(level)
|
71
|
+
action.expects(:distribute_over_time).never
|
72
|
+
planned
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'can distribute tasks over time' do
|
76
|
+
job_invocation.expects(:time_span).returns(span).twice
|
77
|
+
job_invocation.expects(:concurrency_level)
|
78
|
+
action.expects(:distribute_over_time).with(span)
|
79
|
+
action.expects(:distribute_over_time).never
|
80
|
+
planned
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'can use both' do
|
84
|
+
job_invocation.expects(:time_span).returns(span).twice
|
85
|
+
action.expects(:distribute_over_time).with(span)
|
86
|
+
job_invocation.expects(:concurrency_level).returns(level).twice
|
87
|
+
action.expects(:limit_concurrency_level).with(level)
|
88
|
+
planned
|
89
|
+
end
|
90
|
+
end
|
50
91
|
end
|
51
92
|
end
|
@@ -40,6 +40,17 @@ describe ForemanRemoteExecution::HostExtensions do
|
|
40
40
|
it 'has ssh keys in the parameters' do
|
41
41
|
host.remote_execution_ssh_keys.must_include sshkey
|
42
42
|
end
|
43
|
+
|
44
|
+
it 'has ssh keys in the parameters even when no user specified' do
|
45
|
+
# this is a case, when using the helper in provisioning templates
|
46
|
+
FactoryGirl.create(:smart_proxy, :ssh) do |proxy|
|
47
|
+
proxy.organizations << host.organization
|
48
|
+
proxy.locations << host.location
|
49
|
+
end
|
50
|
+
host.interfaces.first.subnet.remote_execution_proxies.clear
|
51
|
+
User.current = nil
|
52
|
+
host.remote_execution_ssh_keys.must_include sshkey
|
53
|
+
end
|
43
54
|
end
|
44
55
|
|
45
56
|
context 'host has multiple nics' do
|
@@ -2,14 +2,14 @@ require 'test_plugin_helper'
|
|
2
2
|
|
3
3
|
describe InputTemplateRenderer do
|
4
4
|
context 'renderer for simple template without inputs' do
|
5
|
-
let(:renderer) { InputTemplateRenderer.new(FactoryGirl.build(:job_template, :template => 'id')) }
|
5
|
+
let(:renderer) { InputTemplateRenderer.new(FactoryGirl.build(:job_template, :template => 'id <%= preview? %>')) }
|
6
6
|
|
7
7
|
it 'should render the content' do
|
8
|
-
renderer.render.must_equal 'id'
|
8
|
+
renderer.render.must_equal 'id false'
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'should render preview' do
|
12
|
-
renderer.preview.must_equal 'id'
|
12
|
+
renderer.preview.must_equal 'id true'
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -147,7 +147,7 @@ describe InputTemplateRenderer do
|
|
147
147
|
end
|
148
148
|
|
149
149
|
let(:package_template) do
|
150
|
-
FactoryGirl.build(:job_template, :name => 'package action', :template => <<TEMPLATE)
|
150
|
+
FactoryGirl.build(:job_template, :name => 'package action', :template => <<TEMPLATE) do |template|
|
151
151
|
<%= render_template("command action", "command" => "yum -y \#{ input("action") } \#{ input('package') }") -%>
|
152
152
|
TEMPLATE
|
153
153
|
template.template_inputs << FactoryGirl.build(:template_input, :name => 'package', :input_type => 'user')
|
@@ -210,7 +210,7 @@ describe JobInvocationComposer do
|
|
210
210
|
{ :job_template_id => trying_job_template_1.id.to_s,
|
211
211
|
:job_templates => {
|
212
212
|
trying_job_template_1.id.to_s => {
|
213
|
-
:input_values => { input1.id.to_s => { :value => 'value1' },
|
213
|
+
:input_values => { input1.id.to_s => { :value => 'value1' }, unauthorized_input1.id.to_s => { :value => 'dropped' } }
|
214
214
|
}
|
215
215
|
}
|
216
216
|
}
|
@@ -429,6 +429,25 @@ describe JobInvocationComposer do
|
|
429
429
|
end
|
430
430
|
end
|
431
431
|
|
432
|
+
describe 'concurrency control' do
|
433
|
+
|
434
|
+
describe 'with concurrency control set' do
|
435
|
+
let(:params) do
|
436
|
+
{ :job_invocation => { :providers => { :ssh => ssh_params }, :concurrency_level => "5", :time_span => "60" } }.with_indifferent_access
|
437
|
+
end
|
438
|
+
|
439
|
+
it 'accepts the concurrency options' do
|
440
|
+
composer.job_invocation.concurrency_level.must_equal 5
|
441
|
+
composer.job_invocation.time_span.must_equal 60
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
it 'can be disabled' do
|
446
|
+
composer.job_invocation.concurrency_level.must_be_nil
|
447
|
+
composer.job_invocation.time_span.must_be_nil
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
432
451
|
describe 'triggering' do
|
433
452
|
let(:params) do
|
434
453
|
{ :job_invocation => { :providers => { :ssh => ssh_params } }, :triggering => { :mode => 'future' }}.with_indifferent_access
|
@@ -481,7 +500,11 @@ describe JobInvocationComposer do
|
|
481
500
|
let(:params) do
|
482
501
|
{
|
483
502
|
:job_invocation => {
|
484
|
-
:providers => { :ssh => ssh_params }
|
503
|
+
:providers => { :ssh => ssh_params },
|
504
|
+
:concurrency_control => {
|
505
|
+
:level => 5,
|
506
|
+
:time_span => 60
|
507
|
+
}
|
485
508
|
},
|
486
509
|
:targeting => {
|
487
510
|
:search_query => "name = #{host.name}",
|
@@ -514,6 +537,11 @@ describe JobInvocationComposer do
|
|
514
537
|
new_composer.pattern_template_invocations.size.must_equal existing.pattern_template_invocations.size
|
515
538
|
end
|
516
539
|
|
540
|
+
it 'sets the same concurrency control options' do
|
541
|
+
new_composer.job_invocation.concurrency_level.must_equal existing.concurrency_level
|
542
|
+
new_composer.job_invocation.time_span.must_equal existing.time_span
|
543
|
+
end
|
544
|
+
|
517
545
|
end
|
518
546
|
end
|
519
547
|
end
|
@@ -591,6 +619,28 @@ describe JobInvocationComposer do
|
|
591
619
|
end
|
592
620
|
end
|
593
621
|
|
622
|
+
context 'with concurrency_control' do
|
623
|
+
let(:level) { 5 }
|
624
|
+
let(:time_span) { 60 }
|
625
|
+
let(:params) do
|
626
|
+
{ :job_category => trying_job_template_1.job_category,
|
627
|
+
:job_template_id => trying_job_template_1.id,
|
628
|
+
:concurrency_control => {
|
629
|
+
:concurrency_level => level,
|
630
|
+
:time_span => time_span
|
631
|
+
},
|
632
|
+
:targeting_type => 'static_query',
|
633
|
+
:search_query => 'some hosts',
|
634
|
+
:inputs => {input1.name => 'some_value'}}
|
635
|
+
end
|
636
|
+
|
637
|
+
it 'sets the concurrency level and time span based on the input' do
|
638
|
+
assert composer.save!
|
639
|
+
composer.job_invocation.time_span.must_equal time_span
|
640
|
+
composer.job_invocation.concurrency_level.must_equal level
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
594
644
|
context 'with invalid targeting' do
|
595
645
|
let(:params) do
|
596
646
|
{ :job_category => trying_job_template_1.job_category,
|
@@ -92,7 +92,7 @@ describe JobInvocation do
|
|
92
92
|
context 'future execution' do
|
93
93
|
it 'can report host count' do
|
94
94
|
job_invocation.total_hosts_count.must_equal 'N/A'
|
95
|
-
job_invocation.targeting.expects(:resolved_at).returns(Time.now)
|
95
|
+
job_invocation.targeting.expects(:resolved_at).returns(Time.now.getlocal)
|
96
96
|
job_invocation.total_hosts_count.must_equal 0
|
97
97
|
end
|
98
98
|
|
@@ -10,6 +10,12 @@ describe JobTemplate do
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
+
it 'has a unique name' do
|
14
|
+
template1 = FactoryGirl.create(:job_template)
|
15
|
+
template2 = FactoryGirl.build(:job_template, :name => template1.name)
|
16
|
+
refute template2.valid?
|
17
|
+
end
|
18
|
+
|
13
19
|
it 'needs a job_category' do
|
14
20
|
refute job_template.valid?
|
15
21
|
end
|
@@ -45,7 +51,7 @@ describe JobTemplate do
|
|
45
51
|
|
46
52
|
it 'generates the description_format if not set or blank and has inputs' do
|
47
53
|
input_name = template.template_inputs.first.name
|
48
|
-
expected_result = %
|
54
|
+
expected_result = %(%{job_category} with inputs #{input_name}="%{#{input_name}}")
|
49
55
|
template.generate_description_format.must_equal expected_result
|
50
56
|
template.description_format = ''
|
51
57
|
template.generate_description_format.must_equal expected_result
|
@@ -66,7 +72,7 @@ describe JobTemplate do
|
|
66
72
|
end
|
67
73
|
end
|
68
74
|
|
69
|
-
context 'importing a template' do
|
75
|
+
context 'importing a new template' do
|
70
76
|
let(:template) do
|
71
77
|
template = <<-END_TEMPLATE
|
72
78
|
<%#
|
@@ -78,12 +84,32 @@ describe JobTemplate do
|
|
78
84
|
- name: service_name
|
79
85
|
input_type: user
|
80
86
|
required: true
|
87
|
+
- name: verbose
|
88
|
+
input_type: user
|
81
89
|
%>
|
82
90
|
|
83
91
|
service <%= input("service_name") %> restart
|
84
92
|
END_TEMPLATE
|
85
93
|
|
86
|
-
JobTemplate.import(template, :default => true)
|
94
|
+
JobTemplate.import!(template, :default => true)
|
95
|
+
end
|
96
|
+
|
97
|
+
let(:template_with_input_sets) do
|
98
|
+
template_with_input_sets = <<-END_TEMPLATE
|
99
|
+
<%#
|
100
|
+
kind: job_template
|
101
|
+
name: Service Restart - Custom
|
102
|
+
job_category: Service Restart
|
103
|
+
provider_type: SSH
|
104
|
+
foreign_input_sets:
|
105
|
+
- template: #{template.name}
|
106
|
+
exclude: verbose
|
107
|
+
%>
|
108
|
+
|
109
|
+
service <%= input("service_name") %> restart
|
110
|
+
END_TEMPLATE
|
111
|
+
|
112
|
+
JobTemplate.import!(template_with_input_sets, :default => true)
|
87
113
|
end
|
88
114
|
|
89
115
|
it 'sets the name' do
|
@@ -98,11 +124,108 @@ describe JobTemplate do
|
|
98
124
|
template.template_inputs.first.name.must_equal 'service_name'
|
99
125
|
end
|
100
126
|
|
127
|
+
it 'imports input sets' do
|
128
|
+
template_with_input_sets.foreign_input_sets.first.target_template.must_equal template
|
129
|
+
template_with_input_sets.template_inputs_with_foreign.map(&:name).must_equal ['service_name']
|
130
|
+
end
|
131
|
+
|
101
132
|
it 'sets additional options' do
|
102
133
|
template.default.must_equal true
|
103
134
|
end
|
104
135
|
end
|
105
136
|
|
137
|
+
context 'importing an existing template' do
|
138
|
+
let(:included) do
|
139
|
+
template = <<-END_TEMPLATE
|
140
|
+
<%#
|
141
|
+
kind: job_template
|
142
|
+
name: Banner
|
143
|
+
job_category: Commands
|
144
|
+
provider_type: SSH
|
145
|
+
template_inputs:
|
146
|
+
- name: banner_message
|
147
|
+
input_type: user
|
148
|
+
required: true
|
149
|
+
%>
|
150
|
+
|
151
|
+
echo input(:banner_message)
|
152
|
+
END_TEMPLATE
|
153
|
+
|
154
|
+
JobTemplate.import!(template, :default => true)
|
155
|
+
end
|
156
|
+
|
157
|
+
let(:existing) do
|
158
|
+
template = <<-END_TEMPLATE
|
159
|
+
<%#
|
160
|
+
kind: job_template
|
161
|
+
name: Ping a Thing
|
162
|
+
job_category: Commands
|
163
|
+
provider_type: SSH
|
164
|
+
template_inputs:
|
165
|
+
- name: hostname
|
166
|
+
input_type: user
|
167
|
+
options: "www.google.com"
|
168
|
+
required: true
|
169
|
+
foreign_input_sets:
|
170
|
+
- template: #{included.name}
|
171
|
+
%>
|
172
|
+
|
173
|
+
ping -c 5 <%= input("hostname") %>
|
174
|
+
END_TEMPLATE
|
175
|
+
|
176
|
+
JobTemplate.import!(template, :default => true)
|
177
|
+
end
|
178
|
+
|
179
|
+
let(:updated) do
|
180
|
+
<<-END_TEMPLATE
|
181
|
+
<%#
|
182
|
+
kind: job_template
|
183
|
+
name: Ping a Thing
|
184
|
+
job_category: Commands
|
185
|
+
provider_type: SSH
|
186
|
+
template_inputs:
|
187
|
+
- name: hostname
|
188
|
+
input_type: user
|
189
|
+
options: 'www.redhat.com'
|
190
|
+
required: true
|
191
|
+
- name: count
|
192
|
+
input_type: user
|
193
|
+
required: true
|
194
|
+
foreign_input_sets:
|
195
|
+
- template: #{included.name}
|
196
|
+
exclude: banner_message
|
197
|
+
%>
|
198
|
+
|
199
|
+
ping -c <%= input('count') %> <%= input('hostname') %>
|
200
|
+
END_TEMPLATE
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'will not overwrite by default' do
|
204
|
+
existing
|
205
|
+
refute JobTemplate.import!(updated)
|
206
|
+
end
|
207
|
+
|
208
|
+
let(:synced_template) do
|
209
|
+
existing
|
210
|
+
JobTemplate.import!(updated, :update => true)
|
211
|
+
existing.reload
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'syncs inputs' do
|
215
|
+
hostname = synced_template.template_inputs.find { |input| input.name == 'hostname' }
|
216
|
+
hostname.options.must_equal 'www.redhat.com'
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'syncs content' do
|
220
|
+
synced_template.template.must_match(/\s+ping -c <%= input\('count'\) %> <%= input\('hostname'\) %>\s+/m)
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'syncs input sets' do
|
224
|
+
synced_template.foreign_input_sets.first.target_template.must_equal included
|
225
|
+
synced_template.template_inputs_with_foreign.map(&:name).must_equal ["hostname", "count"]
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
106
229
|
context 'there is existing template invocation of a job template' do
|
107
230
|
let(:job_invocation) { FactoryGirl.create(:job_invocation, :with_template) }
|
108
231
|
let(:job_template) { job_invocation.pattern_template_invocations.first.template }
|