foreman_remote_execution 0.1.2 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/.rubocop_todo.yml +0 -6
  4. data/app/assets/javascripts/template_input.js +5 -0
  5. data/app/assets/javascripts/template_invocation.js +44 -12
  6. data/app/controllers/api/v2/foreign_input_sets_controller.rb +80 -0
  7. data/app/controllers/api/v2/job_invocations_controller.rb +28 -14
  8. data/app/controllers/api/v2/job_templates_controller.rb +24 -20
  9. data/app/controllers/api/v2/template_inputs_controller.rb +10 -7
  10. data/app/controllers/job_invocations_controller.rb +18 -6
  11. data/app/controllers/job_templates_controller.rb +14 -4
  12. data/app/controllers/template_invocations_controller.rb +5 -3
  13. data/app/helpers/concerns/foreman_remote_execution/hosts_helper_extensions.rb +1 -1
  14. data/app/helpers/concerns/foreman_remote_execution/job_templates_extensions.rb +19 -0
  15. data/app/helpers/remote_execution_helper.rb +88 -39
  16. data/app/lib/actions/remote_execution/run_host_job.rb +11 -8
  17. data/app/lib/actions/remote_execution/run_hosts_job.rb +5 -2
  18. data/app/lib/actions/remote_execution/run_proxy_command.rb +9 -4
  19. data/app/models/concerns/foreman_remote_execution/errors_flattener.rb +2 -2
  20. data/app/models/concerns/foreman_remote_execution/host_extensions.rb +2 -2
  21. data/app/models/concerns/foreman_remote_execution/smart_proxy_extensions.rb +1 -1
  22. data/app/models/concerns/foreman_remote_execution/template_extensions.rb +9 -1
  23. data/app/models/foreign_input_set.rb +49 -0
  24. data/app/models/host_status/execution_status.rb +50 -5
  25. data/app/models/input_template_renderer.rb +52 -7
  26. data/app/models/job_invocation.rb +89 -32
  27. data/app/models/job_invocation_composer.rb +71 -55
  28. data/app/models/job_template.rb +43 -7
  29. data/app/models/remote_execution_provider.rb +1 -1
  30. data/app/models/setting/remote_execution.rb +7 -7
  31. data/app/models/ssh_execution_provider.rb +1 -1
  32. data/app/models/targeting.rb +1 -1
  33. data/app/models/template_invocation.rb +9 -4
  34. data/app/views/api/v2/foreign_input_sets/base.json.rabl +3 -0
  35. data/app/views/api/v2/foreign_input_sets/create.json.rabl +3 -0
  36. data/app/views/api/v2/foreign_input_sets/index.json.rabl +3 -0
  37. data/app/views/api/v2/foreign_input_sets/main.json.rabl +5 -0
  38. data/app/views/api/v2/foreign_input_sets/show.json.rabl +3 -0
  39. data/app/views/api/v2/job_invocations/base.json.rabl +10 -1
  40. data/app/views/api/v2/job_invocations/main.json.rabl +14 -1
  41. data/app/views/api/v2/job_templates/base.json.rabl +1 -1
  42. data/app/views/api/v2/job_templates/main.json.rabl +9 -1
  43. data/app/views/api/v2/job_templates/show.json.rabl +0 -10
  44. data/app/views/api/v2/template_inputs/main.json.rabl +2 -1
  45. data/app/views/job_invocation_task_groups/_job_invocation_task_group.html.erb +1 -1
  46. data/app/views/job_invocations/_description_fields.html.erb +4 -0
  47. data/app/views/job_invocations/_form.html.erb +73 -91
  48. data/app/views/job_invocations/_host_actions_td.html.erb +2 -2
  49. data/app/views/job_invocations/_host_name_td.html.erb +7 -0
  50. data/app/views/job_invocations/_tab_hosts.html.erb +6 -6
  51. data/app/views/job_invocations/_tab_overview.html.erb +3 -3
  52. data/app/views/job_invocations/index.html.erb +6 -4
  53. data/app/views/job_invocations/refresh.js.erb +1 -0
  54. data/app/views/job_invocations/show.html.erb +1 -1
  55. data/app/views/job_invocations/show.js.erb +6 -3
  56. data/app/views/job_templates/_custom_tabs.html.erb +24 -14
  57. data/app/views/job_templates/index.html.erb +3 -1
  58. data/app/views/template_inputs/_foreign_input_set_form.html.erb +12 -0
  59. data/app/views/template_inputs/_form.html.erb +11 -12
  60. data/app/views/template_invocations/show.html.erb +2 -2
  61. data/app/views/templates/package_action.erb +2 -2
  62. data/app/views/templates/puppet_run_once.erb +3 -3
  63. data/app/views/templates/run_command.erb +3 -3
  64. data/app/views/templates/service_action.erb +2 -2
  65. data/app/views/unattended/snippets/_remote_execution_ssh_keys.erb +1 -1
  66. data/config/routes.rb +5 -3
  67. data/db/migrate/20150616080015_create_template_input.rb +1 -1
  68. data/db/migrate/20150708133241_add_targeting.rb +7 -7
  69. data/db/migrate/20150708133242_add_invocation.rb +2 -2
  70. data/db/migrate/20150708133305_add_template_invocation.rb +6 -6
  71. data/db/migrate/20151215114631_add_host_id_to_template_invocation.rb +3 -3
  72. data/db/migrate/20151217092555_migrate_to_task_groups.rb +1 -1
  73. data/db/migrate/20160108134600_create_template_input_sets.rb +16 -0
  74. data/db/migrate/20160108141144_make_job_name_default_to_something.rb +9 -0
  75. data/db/migrate/20160111113032_upcase_ssh_feature.rb +19 -0
  76. data/db/migrate/20160113161916_add_run_host_job_task_id_to_template_invocation.rb +6 -0
  77. data/db/migrate/20160113162007_expand_all_template_invocations.rb +45 -0
  78. data/db/migrate/20160114120200_rename_job_categories.rb +20 -0
  79. data/db/migrate/20160114125628_rename_job_name_to_job_category.rb +19 -0
  80. data/db/seeds.d/60-ssh_proxy_feature.rb +1 -1
  81. data/db/seeds.d/80-provision_templates.rb +2 -2
  82. data/db/seeds.d/90-bookmarks.rb +19 -0
  83. data/doc/plugins/graphviz.rb +5 -5
  84. data/doc/plugins/plantuml.rb +6 -6
  85. data/doc/plugins/tags.rb +4 -4
  86. data/foreman_remote_execution.gemspec +3 -4
  87. data/lib/foreman_remote_execution/engine.rb +12 -9
  88. data/lib/foreman_remote_execution/version.rb +1 -1
  89. data/test/factories/foreman_remote_execution_factories.rb +11 -9
  90. data/test/functional/api/v2/foreign_input_sets_controller_test.rb +63 -0
  91. data/test/functional/api/v2/job_invocations_controller_test.rb +45 -13
  92. data/test/functional/api/v2/job_templates_controller_test.rb +6 -6
  93. data/test/functional/api/v2/template_inputs_controller_test.rb +3 -3
  94. data/test/unit/actions/run_hosts_job_test.rb +3 -4
  95. data/test/unit/actions/run_proxy_command_test.rb +7 -7
  96. data/test/unit/concerns/host_extensions_test.rb +1 -1
  97. data/test/unit/execution_task_status_mapper_test.rb +93 -0
  98. data/test/unit/input_template_renderer_test.rb +182 -9
  99. data/test/unit/job_invocation_composer_test.rb +144 -168
  100. data/test/unit/job_invocation_test.rb +67 -15
  101. data/test/unit/job_template_effective_user_test.rb +2 -2
  102. data/test/unit/job_template_test.rb +36 -12
  103. data/test/unit/remote_execution_provider_test.rb +6 -6
  104. data/test/unit/targeting_test.rb +2 -2
  105. metadata +27 -21
  106. data/app/models/concerns/foreman_remote_execution/template_relations.rb +0 -10
  107. data/app/views/job_invocations/_host_provider_td.html.erb +0 -3
  108. data/app/views/job_templates/auto_complete_job_name.json.erb +0 -3
@@ -10,7 +10,7 @@ module Api
10
10
  test 'should get index' do
11
11
  get :index
12
12
  templates = ActiveSupport::JSON.decode(@response.body)
13
- assert !templates.empty?, "Should response with template"
13
+ assert !templates.empty?, 'Should response with template'
14
14
  assert_response :success
15
15
  end
16
16
 
@@ -19,15 +19,15 @@ module Api
19
19
  assert_response :success
20
20
  template = ActiveSupport::JSON.decode(@response.body)
21
21
  assert !template.empty?
22
- assert_equal template["name"], @template.name
22
+ assert_equal template['name'], @template.name
23
23
  end
24
24
 
25
25
  test 'should create valid' do
26
26
  JobTemplate.any_instance.stubs(:valid?).returns(true)
27
- valid_attrs = { :template => "This is a test template", :name => "RandomName", :provider_type => 'ssh' }
27
+ valid_attrs = { :template => 'This is a test template', :name => 'RandomName', :provider_type => 'ssh' }
28
28
  post :create, :job_template => valid_attrs
29
29
  template = ActiveSupport::JSON.decode(@response.body)
30
- assert template["name"] == "RandomName"
30
+ assert template['name'] == 'RandomName'
31
31
  assert_response :success
32
32
  end
33
33
 
@@ -39,13 +39,13 @@ module Api
39
39
  test 'should update valid' do
40
40
  JobTemplate.any_instance.stubs(:valid?).returns(true)
41
41
  put :update, :id => @template.to_param,
42
- :job_template => { :template => "blah" }
42
+ :job_template => { :template => 'blah' }
43
43
  assert_response :ok
44
44
  end
45
45
 
46
46
  test 'should not update invalid' do
47
47
  put :update, :id => @template.to_param,
48
- :job_template => { :name => "" }
48
+ :job_template => { :name => '' }
49
49
  assert_response :unprocessable_entity
50
50
  end
51
51
 
@@ -11,7 +11,7 @@ module Api
11
11
  test 'should get index' do
12
12
  get :index, :template_id => @template.id
13
13
  inputs = ActiveSupport::JSON.decode(@response.body)
14
- assert !inputs.empty?, "Should respond with inputs"
14
+ assert !inputs.empty?, 'Should respond with inputs'
15
15
  assert_response :success
16
16
  end
17
17
 
@@ -20,7 +20,7 @@ module Api
20
20
  assert_response :success
21
21
  input = ActiveSupport::JSON.decode(@response.body)
22
22
  assert !input.empty?
23
- assert_equal input["name"], @input.name
23
+ assert_equal input['name'], @input.name
24
24
  end
25
25
 
26
26
  test 'should create valid' do
@@ -39,7 +39,7 @@ module Api
39
39
  test 'should update valid' do
40
40
  put :update, :template_id => @template.to_param,
41
41
  :id => @input.to_param,
42
- :template_input => { :name => "blah" }
42
+ :template_input => { :name => 'blah' }
43
43
  assert_response :ok
44
44
  end
45
45
 
@@ -1,12 +1,12 @@
1
1
 
2
- require "test_plugin_helper"
2
+ require 'test_plugin_helper'
3
3
 
4
4
  module ForemanRemoteExecution
5
5
  class RunHostsJobTest < ActiveSupport::TestCase
6
6
  include Dynflow::Testing
7
7
 
8
8
  let(:host) { FactoryGirl.create(:host, :with_execution) }
9
- let(:proxy) { host.remote_execution_proxies('Ssh')[:subnet].first }
9
+ let(:proxy) { host.remote_execution_proxies('SSH')[:subnet].first }
10
10
  let(:targeting) { FactoryGirl.create(:targeting, :search_query => "name = #{host.name}", :user => User.current) }
11
11
  let(:job_invocation) do
12
12
  FactoryGirl.build(:job_invocation, :with_template).tap do |invocation|
@@ -39,8 +39,7 @@ module ForemanRemoteExecution
39
39
  end
40
40
 
41
41
  it 'triggers the RunHostJob actions on the resolved hosts in run phase' do
42
- template_invocation = job_invocation.template_invocation_for_host(host)
43
- action.expects(:trigger).with(Actions::RemoteExecution::RunHostJob, job_invocation, host, template_invocation, proxy)
42
+ action.expects(:trigger).with() { |*args| args[0] == Actions::RemoteExecution::RunHostJob }
44
43
  action.create_sub_plans
45
44
  end
46
45
 
@@ -1,11 +1,11 @@
1
- require "test_plugin_helper"
1
+ require 'test_plugin_helper'
2
2
 
3
3
  module ForemanRemoteExecution
4
4
  class RunProxyCommandTest < ActiveSupport::TestCase
5
5
  include Dynflow::Testing
6
6
 
7
7
  let(:host) { FactoryGirl.build(:host, :with_execution) }
8
- let(:proxy) { host.remote_execution_proxies('Ssh')[:subnet].first }
8
+ let(:proxy) { host.remote_execution_proxies('SSH')[:subnet].first }
9
9
  let(:hostname) { 'myhost.example.com' }
10
10
  let(:script) { 'ping -c 5 redhat.com' }
11
11
  let(:connection_options) { { 'retry_interval' => 15, 'retry_count' => 4, 'timeout' => 60 } }
@@ -50,7 +50,7 @@ module ForemanRemoteExecution
50
50
  describe 'when the task is finished' do
51
51
  before do
52
52
  task.state = 'stopped'
53
- task.ended_at = timestamp + 1
53
+ task.ended_at = Time.at(timestamp + 1)
54
54
  end
55
55
 
56
56
  describe 'the task finished sucessfully' do
@@ -88,10 +88,10 @@ module ForemanRemoteExecution
88
88
 
89
89
  describe 'when something went wrong while fetching the data' do
90
90
  before do
91
- action.proxy.expects(:status_of_task).raises("Something went wrong")
91
+ action.proxy.expects(:status_of_task).raises('Something went wrong')
92
92
  end
93
93
 
94
- it "reports the failure as part of the live output" do
94
+ it 'reports the failure as part of the live output' do
95
95
  live_output.size.must_equal 1
96
96
  live_output.first['output_type'].must_equal 'debug'
97
97
  live_output.first['output'].must_equal 'Error loading data from proxy: RuntimeError - Something went wrong'
@@ -105,7 +105,7 @@ module ForemanRemoteExecution
105
105
  :metadata => { :failed_proxy_tasks => [action.send(:format_exception, RuntimeError.new('Connection error'))]})
106
106
  end
107
107
 
108
- it "reports the failure as part of the live output" do
108
+ it 'reports the failure as part of the live output' do
109
109
  live_output.size.must_equal 1
110
110
  live_output.first['output_type'].must_equal 'debug'
111
111
  live_output.first['output'].must_equal 'Initialization error: RuntimeError - Connection error'
@@ -122,7 +122,7 @@ module ForemanRemoteExecution
122
122
  'timestamp' => timestamp }]}}])
123
123
  end
124
124
 
125
- it "reports the failure as part of the live output" do
125
+ it 'reports the failure as part of the live output' do
126
126
  live_output.size.must_equal 1
127
127
  live_output.first['output_type'].must_equal 'stdout'
128
128
  live_output.first['output'].must_equal 'Hello'
@@ -1,7 +1,7 @@
1
1
  require 'test_plugin_helper'
2
2
 
3
3
  describe ForemanRemoteExecution::HostExtensions do
4
- let(:provider) { 'Ssh' }
4
+ let(:provider) { 'SSH' }
5
5
 
6
6
  before do
7
7
  User.current = FactoryGirl.build(:user, :admin)
@@ -0,0 +1,93 @@
1
+ require 'test_plugin_helper'
2
+
3
+ describe HostStatus::ExecutionStatus::ExecutionTaskStatusMapper do
4
+
5
+ describe '.sql_conditions_for(status)' do
6
+ subject { HostStatus::ExecutionStatus::ExecutionTaskStatusMapper }
7
+
8
+ it 'accepts status number as well as string representation' do
9
+ subject.sql_conditions_for(HostStatus::ExecutionStatus::ERROR).must_equal subject.sql_conditions_for('failed')
10
+ end
11
+
12
+ it 'does not find any task for unknown state' do
13
+ subject.sql_conditions_for(-1).must_equal [ '1 = 0' ]
14
+ end
15
+ end
16
+
17
+ let(:task) { ForemanTasks::Task.new }
18
+ let(:mapper) { HostStatus::ExecutionStatus::ExecutionTaskStatusMapper.new(task) }
19
+
20
+ describe '#status' do
21
+ subject { mapper }
22
+
23
+ describe 'is queued' do
24
+ context 'when there is no task' do
25
+ before { subject.task = nil }
26
+ specify { subject.status.must_equal HostStatus::ExecutionStatus::QUEUED }
27
+ end
28
+
29
+ context 'when the task is scheduled in future' do
30
+ before { subject.task.state = 'scheduled' }
31
+ specify { subject.status.must_equal HostStatus::ExecutionStatus::QUEUED }
32
+ end
33
+ end
34
+
35
+ context 'when task is stopped' do
36
+ before { subject.task.state = 'stopped' }
37
+
38
+ describe 'is succeeded' do
39
+ context 'without error' do
40
+ before { subject.task.result = 'success' }
41
+ specify { subject.status.must_equal HostStatus::ExecutionStatus::OK }
42
+ end
43
+ end
44
+
45
+ describe 'is failed' do
46
+ context 'with error' do
47
+ before { subject.task.result = 'error' }
48
+ specify { subject.status.must_equal HostStatus::ExecutionStatus::ERROR }
49
+ end
50
+
51
+ context 'without error but just with warning (sub task failed)' do
52
+ before { subject.task.result = 'warning' }
53
+ specify { subject.status.must_equal HostStatus::ExecutionStatus::ERROR }
54
+ end
55
+ end
56
+ end
57
+
58
+ context 'when task is pending' do
59
+ before { subject.task.state = 'running' }
60
+
61
+ describe 'is pending' do
62
+ specify { subject.status.must_equal HostStatus::ExecutionStatus::RUNNING }
63
+ end
64
+ end
65
+ end
66
+
67
+ describe '#status_label' do
68
+ subject { mapper.status_label }
69
+
70
+ context 'status is OK' do
71
+ before do
72
+ mapper.task.state = 'stopped'
73
+ mapper.task.result = 'success'
74
+ end
75
+
76
+ it 'returns ok label' do
77
+ subject.must_equal HostStatus::ExecutionStatus::STATUS_NAMES[HostStatus::ExecutionStatus::OK]
78
+ end
79
+ end
80
+
81
+ context 'status is ERROR' do
82
+ before do
83
+ mapper.task.state = 'stopped'
84
+ mapper.task.result = 'error'
85
+ end
86
+
87
+ it 'returns failed label' do
88
+ subject.must_equal HostStatus::ExecutionStatus::STATUS_NAMES[HostStatus::ExecutionStatus::ERROR]
89
+ end
90
+ end
91
+ end
92
+
93
+ end
@@ -1,7 +1,7 @@
1
1
  require 'test_plugin_helper'
2
2
 
3
3
  describe InputTemplateRenderer do
4
- context "renderer for simple template without inputs" do
4
+ context 'renderer for simple template without inputs' do
5
5
  let(:renderer) { InputTemplateRenderer.new(FactoryGirl.build(:job_template, :template => 'id')) }
6
6
 
7
7
  it 'should render the content' do
@@ -13,7 +13,7 @@ describe InputTemplateRenderer do
13
13
  end
14
14
  end
15
15
 
16
- context "renderer for template with user input used" do
16
+ context 'renderer for template with user input used' do
17
17
  let(:template) { FactoryGirl.build(:job_template, :template => 'service restart <%= input("service_name") -%>') }
18
18
  let(:renderer) { InputTemplateRenderer.new(template) }
19
19
 
@@ -95,6 +95,173 @@ describe InputTemplateRenderer do
95
95
  renderer.invocation = template_invocation
96
96
  renderer.render.must_equal 'service restart '
97
97
  end
98
+
99
+ describe 'with circular reference' do
100
+ let(:recursive_template_with_inputs) do
101
+ FactoryGirl.create(:job_template, :name => 'test', :template => 'test')
102
+ end
103
+
104
+ let(:template_with_inputs) do
105
+ FactoryGirl.create(:job_template, :template => 'test').tap do |template|
106
+ template.foreign_input_sets << FactoryGirl.build(:foreign_input_set, :target_template => recursive_template_with_inputs)
107
+ end
108
+ end
109
+
110
+ let(:recursive_template_without_inputs) do
111
+ FactoryGirl.create(:job_template, :name => 'recursive template', :template => '<%= render_template("template with inputs", "action" => "install") %>')
112
+ end
113
+
114
+ let(:template_without_inputs) do
115
+ FactoryGirl.create(:job_template, :name => 'template with inputs', :template => "<%= render_template('#{recursive_template_without_inputs.name}') %>")
116
+ end
117
+
118
+ before do
119
+ User.current = users :admin
120
+ end
121
+
122
+ it 'handles circular references in templates' do
123
+ renderer.invocation = FactoryGirl.build(:template_invocation, :template => template_without_inputs)
124
+ renderer.template = template_without_inputs
125
+ refute renderer.render
126
+ renderer.error_message.must_include 'Recursive rendering of templates detected'
127
+ end
128
+
129
+ it 'handles circular references in inputs' do
130
+ assert_raises(ActiveRecord::RecordInvalid) do
131
+ input_set = FactoryGirl.build(:foreign_input_set, :target_template => template_with_inputs, :include_all => false,
132
+ :include => 'package, debug', :exclude => 'action,debug')
133
+ recursive_template_with_inputs.foreign_input_sets << input_set
134
+ recursive_template_with_inputs.save!
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ context 'renderer for template with input set and render_template' do
142
+ let(:command_template) do
143
+ FactoryGirl.build(:job_template, :name => 'command action', :template => '<%= input("command") -%>').tap do |template|
144
+ template.template_inputs << FactoryGirl.build(:template_input, :name => 'command', :input_type => 'user')
145
+ template.template_inputs << FactoryGirl.build(:template_input, :name => 'debug', :input_type => 'user')
146
+ end
147
+ end
148
+
149
+ let(:package_template) do
150
+ FactoryGirl.build(:job_template, :name => 'package action', :template => <<TEMPLATE) do |template|
151
+ <%= render_template("command action", "command" => "yum -y \#{ input("action") } \#{ input('package') }") -%>
152
+ TEMPLATE
153
+ template.template_inputs << FactoryGirl.build(:template_input, :name => 'package', :input_type => 'user')
154
+ template.template_inputs << FactoryGirl.build(:template_input, :name => 'action', :input_type => 'user')
155
+ template.foreign_input_sets << FactoryGirl.build(:foreign_input_set, :target_template => command_template, :include_all => true, :exclude => 'command')
156
+ end
157
+ end
158
+
159
+ let(:template) do
160
+ FactoryGirl.create(:job_template,
161
+ :template => '<%= render_template("package action", { :action => "install" }, { :with_foreign_input_set => true }) %>').tap do |template|
162
+ template.foreign_input_sets << FactoryGirl.build(:foreign_input_set, :target_template => package_template, :include_all => true, :exclude => 'action')
163
+ end
164
+ end
165
+
166
+ let(:job_invocation) { FactoryGirl.create(:job_invocation) }
167
+ let(:template_invocation) { FactoryGirl.build(:template_invocation, :template => template) }
168
+ let(:renderer) { InputTemplateRenderer.new(template) }
169
+ let(:result) { renderer.render }
170
+
171
+ before do
172
+ User.current = users :admin
173
+ command_template.save!
174
+ package_template.save!
175
+ job_invocation.template_invocations << template_invocation
176
+ end
177
+
178
+ describe 'foreign input set' do
179
+ describe 'with include_all' do
180
+ let(:template) do
181
+ FactoryGirl.create(:job_template, :template => '<%= render_template("package action", "action" => "install") %>').tap do |template|
182
+ template.foreign_input_sets << FactoryGirl.build(:foreign_input_set, :target_template => package_template, :include_all => true)
183
+ end
184
+ end
185
+
186
+ let(:template_2) do
187
+ FactoryGirl.create(:job_template, :template => '<%= render_template("package action", "action" => "install") %>').tap do |template|
188
+ template.foreign_input_sets << FactoryGirl.build(:foreign_input_set,
189
+ :target_template => package_template, :include_all => true, :include => '', :exclude => '')
190
+ end
191
+ end
192
+
193
+ it 'includes all inputs from the imported template' do
194
+ template.template_inputs_with_foreign.map(&:name).sort.must_equal ['action', 'debug', 'package']
195
+ template_2.template_inputs_with_foreign.map(&:name).sort.must_equal ['action', 'debug', 'package']
196
+ end
197
+ end
198
+
199
+ describe 'with include_all and some excludes' do
200
+ let(:template) do
201
+ FactoryGirl.create(:job_template, :template => '<%= render_template("package action", "action" => "install") %>').tap do |template|
202
+ template.foreign_input_sets << FactoryGirl.build(:foreign_input_set, :target_template => package_template, :include_all => true, :exclude => 'action,debug')
203
+ end
204
+ end
205
+
206
+ it 'includes all inputs from the imported template except the listed once' do
207
+ template.template_inputs_with_foreign.map(&:name).sort.must_equal ['package']
208
+ end
209
+ end
210
+
211
+ describe 'with some includes and some excludes' do
212
+ let(:template) do
213
+ FactoryGirl.create(:job_template, :template => '<%= render_template("package action", "action" => "install") %>').tap do |template|
214
+ template.foreign_input_sets << FactoryGirl.build(:foreign_input_set, :target_template => package_template, :include_all => false,
215
+ :include => 'package, debug', :exclude => 'action,debug')
216
+ end
217
+ end
218
+
219
+ it 'includes all inputs from the imported template' do
220
+ template.template_inputs_with_foreign.map(&:name).sort.must_equal ['package']
221
+ end
222
+ end
223
+ end
224
+
225
+ context 'with invocation specified' do
226
+ before do
227
+ FactoryGirl.create(:template_invocation_input_value,
228
+ :template_invocation => template_invocation,
229
+ :template_input => template.template_inputs_with_foreign.find { |input| input.name == 'package' },
230
+ :value => 'zsh')
231
+ renderer.invocation = template_invocation
232
+ renderer.invocation.reload
233
+ end
234
+
235
+ it 'can render with job invocation with corresponding value' do
236
+ rendered = renderer.render
237
+ renderer.error_message.must_be_nil
238
+ rendered.must_equal 'yum -y install zsh'
239
+ end
240
+ end
241
+
242
+ context 'with explicitly specifying inputs' do
243
+ let(:template) do
244
+ FactoryGirl.create(:job_template,
245
+ :template => '<%= render_template("package action", {"action" => "install", :package => "zsh"}) %>')
246
+ end
247
+
248
+ before do
249
+ renderer.invocation = template_invocation
250
+ renderer.invocation.reload
251
+ end
252
+
253
+ it 'can render with job invocation with corresponding value' do
254
+ rendered = renderer.render
255
+ renderer.error_message.must_be_nil
256
+ rendered.must_equal 'yum -y install zsh'
257
+ end
258
+ end
259
+
260
+ it 'renders even without an input value' do
261
+ renderer.invocation = template_invocation
262
+ rendered = renderer.render
263
+ renderer.error_message.must_be_nil
264
+ rendered.must_equal 'yum -y install '
98
265
  end
99
266
  end
100
267
 
@@ -127,7 +294,7 @@ describe InputTemplateRenderer do
127
294
  end
128
295
  end
129
296
 
130
- context "renderer for template with fact input used" do
297
+ context 'renderer for template with fact input used' do
131
298
  let(:template) { FactoryGirl.build(:job_template, :template => 'echo <%= input("issue") -%> > /etc/issue') }
132
299
  let(:renderer) { InputTemplateRenderer.new(template) }
133
300
 
@@ -225,7 +392,7 @@ describe InputTemplateRenderer do
225
392
  end
226
393
  end
227
394
 
228
- context "renderer for template with variable input used" do
395
+ context 'renderer for template with variable input used' do
229
396
  let(:template) { FactoryGirl.build(:job_template, :template => 'echo <%= input("client_key") -%> > /etc/chef/client.pem') }
230
397
  let(:renderer) { InputTemplateRenderer.new(template) }
231
398
 
@@ -288,13 +455,17 @@ describe InputTemplateRenderer do
288
455
  end
289
456
 
290
457
  context 'with existing variable implemented as smart variable' do
291
- let(:puppet_class) { FactoryGirl.create(:puppetclass, :environments => [environment], :hosts => [renderer.host]) }
458
+ let(:puppet_class) do
459
+ puppetclass = FactoryGirl.create(:puppetclass, :environments => [environment])
460
+ puppetclass.update_attribute(:hosts, [renderer.host])
461
+ puppetclass
462
+ end
292
463
  let(:lookup_key) do
293
464
  lookup_key_factory = SETTINGS[:version].short == '1.9' ? :lookup_key : :variable_lookup_key
294
465
  FactoryGirl.create(lookup_key_factory,
295
466
  :key => 'client_key',
296
467
  :puppetclass => puppet_class,
297
- :overrides => {"fqdn=#{renderer.host.fqdn}" => "RSA KEY"})
468
+ :overrides => {"fqdn=#{renderer.host.fqdn}" => 'RSA KEY'})
298
469
  end
299
470
 
300
471
  describe 'rendering' do
@@ -322,7 +493,7 @@ describe InputTemplateRenderer do
322
493
  end
323
494
  end
324
495
 
325
- context "renderer for template with puppet parameter input used" do
496
+ context 'renderer for template with puppet parameter input used' do
326
497
  let(:template) { FactoryGirl.build(:job_template, :template => 'echo "This is WebServer with nginx <%= input("nginx_version") -%>" > /etc/motd') }
327
498
  let(:renderer) { InputTemplateRenderer.new(template) }
328
499
 
@@ -371,7 +542,9 @@ describe InputTemplateRenderer do
371
542
 
372
543
  context 'with existing puppet parameter with matching override' do
373
544
  let(:puppet_class) do
374
- FactoryGirl.create(:puppetclass, :environments => [environment], :hosts => [renderer.host], :name => 'nginx')
545
+ puppetclass = FactoryGirl.create(:puppetclass, :environments => [environment], :name => 'nginx')
546
+ puppetclass.update_attribute(:hosts, [renderer.host])
547
+ puppetclass
375
548
  end
376
549
  let(:lookup_key) do
377
550
  lookup_key_factory = SETTINGS[:version].short == '1.9' ? :lookup_key : :puppetclass_lookup_key
@@ -380,7 +553,7 @@ describe InputTemplateRenderer do
380
553
  :puppetclass => puppet_class,
381
554
  :path => 'fqdn',
382
555
  :override => true,
383
- :overrides => {"fqdn=#{renderer.host.fqdn}" => "1.4.7"})
556
+ :overrides => {"fqdn=#{renderer.host.fqdn}" => '1.4.7'})
384
557
  end
385
558
 
386
559
  describe 'rendering' do