foreman_remote_execution 0.1.2 → 0.2.1
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/.rubocop.yml +3 -0
- data/.rubocop_todo.yml +0 -6
- data/app/assets/javascripts/template_input.js +5 -0
- data/app/assets/javascripts/template_invocation.js +44 -12
- data/app/controllers/api/v2/foreign_input_sets_controller.rb +80 -0
- data/app/controllers/api/v2/job_invocations_controller.rb +28 -14
- data/app/controllers/api/v2/job_templates_controller.rb +24 -20
- data/app/controllers/api/v2/template_inputs_controller.rb +10 -7
- data/app/controllers/job_invocations_controller.rb +18 -6
- data/app/controllers/job_templates_controller.rb +14 -4
- data/app/controllers/template_invocations_controller.rb +5 -3
- data/app/helpers/concerns/foreman_remote_execution/hosts_helper_extensions.rb +1 -1
- data/app/helpers/concerns/foreman_remote_execution/job_templates_extensions.rb +19 -0
- data/app/helpers/remote_execution_helper.rb +88 -39
- data/app/lib/actions/remote_execution/run_host_job.rb +11 -8
- data/app/lib/actions/remote_execution/run_hosts_job.rb +5 -2
- data/app/lib/actions/remote_execution/run_proxy_command.rb +9 -4
- data/app/models/concerns/foreman_remote_execution/errors_flattener.rb +2 -2
- data/app/models/concerns/foreman_remote_execution/host_extensions.rb +2 -2
- data/app/models/concerns/foreman_remote_execution/smart_proxy_extensions.rb +1 -1
- data/app/models/concerns/foreman_remote_execution/template_extensions.rb +9 -1
- data/app/models/foreign_input_set.rb +49 -0
- data/app/models/host_status/execution_status.rb +50 -5
- data/app/models/input_template_renderer.rb +52 -7
- data/app/models/job_invocation.rb +89 -32
- data/app/models/job_invocation_composer.rb +71 -55
- data/app/models/job_template.rb +43 -7
- data/app/models/remote_execution_provider.rb +1 -1
- data/app/models/setting/remote_execution.rb +7 -7
- data/app/models/ssh_execution_provider.rb +1 -1
- data/app/models/targeting.rb +1 -1
- data/app/models/template_invocation.rb +9 -4
- data/app/views/api/v2/foreign_input_sets/base.json.rabl +3 -0
- data/app/views/api/v2/foreign_input_sets/create.json.rabl +3 -0
- data/app/views/api/v2/foreign_input_sets/index.json.rabl +3 -0
- data/app/views/api/v2/foreign_input_sets/main.json.rabl +5 -0
- data/app/views/api/v2/foreign_input_sets/show.json.rabl +3 -0
- data/app/views/api/v2/job_invocations/base.json.rabl +10 -1
- data/app/views/api/v2/job_invocations/main.json.rabl +14 -1
- data/app/views/api/v2/job_templates/base.json.rabl +1 -1
- data/app/views/api/v2/job_templates/main.json.rabl +9 -1
- data/app/views/api/v2/job_templates/show.json.rabl +0 -10
- data/app/views/api/v2/template_inputs/main.json.rabl +2 -1
- data/app/views/job_invocation_task_groups/_job_invocation_task_group.html.erb +1 -1
- data/app/views/job_invocations/_description_fields.html.erb +4 -0
- data/app/views/job_invocations/_form.html.erb +73 -91
- data/app/views/job_invocations/_host_actions_td.html.erb +2 -2
- data/app/views/job_invocations/_host_name_td.html.erb +7 -0
- data/app/views/job_invocations/_tab_hosts.html.erb +6 -6
- data/app/views/job_invocations/_tab_overview.html.erb +3 -3
- data/app/views/job_invocations/index.html.erb +6 -4
- data/app/views/job_invocations/refresh.js.erb +1 -0
- data/app/views/job_invocations/show.html.erb +1 -1
- data/app/views/job_invocations/show.js.erb +6 -3
- data/app/views/job_templates/_custom_tabs.html.erb +24 -14
- data/app/views/job_templates/index.html.erb +3 -1
- data/app/views/template_inputs/_foreign_input_set_form.html.erb +12 -0
- data/app/views/template_inputs/_form.html.erb +11 -12
- data/app/views/template_invocations/show.html.erb +2 -2
- data/app/views/templates/package_action.erb +2 -2
- data/app/views/templates/puppet_run_once.erb +3 -3
- data/app/views/templates/run_command.erb +3 -3
- data/app/views/templates/service_action.erb +2 -2
- data/app/views/unattended/snippets/_remote_execution_ssh_keys.erb +1 -1
- data/config/routes.rb +5 -3
- data/db/migrate/20150616080015_create_template_input.rb +1 -1
- data/db/migrate/20150708133241_add_targeting.rb +7 -7
- data/db/migrate/20150708133242_add_invocation.rb +2 -2
- data/db/migrate/20150708133305_add_template_invocation.rb +6 -6
- data/db/migrate/20151215114631_add_host_id_to_template_invocation.rb +3 -3
- data/db/migrate/20151217092555_migrate_to_task_groups.rb +1 -1
- data/db/migrate/20160108134600_create_template_input_sets.rb +16 -0
- data/db/migrate/20160108141144_make_job_name_default_to_something.rb +9 -0
- data/db/migrate/20160111113032_upcase_ssh_feature.rb +19 -0
- data/db/migrate/20160113161916_add_run_host_job_task_id_to_template_invocation.rb +6 -0
- data/db/migrate/20160113162007_expand_all_template_invocations.rb +45 -0
- data/db/migrate/20160114120200_rename_job_categories.rb +20 -0
- data/db/migrate/20160114125628_rename_job_name_to_job_category.rb +19 -0
- data/db/seeds.d/60-ssh_proxy_feature.rb +1 -1
- data/db/seeds.d/80-provision_templates.rb +2 -2
- data/db/seeds.d/90-bookmarks.rb +19 -0
- data/doc/plugins/graphviz.rb +5 -5
- data/doc/plugins/plantuml.rb +6 -6
- data/doc/plugins/tags.rb +4 -4
- data/foreman_remote_execution.gemspec +3 -4
- data/lib/foreman_remote_execution/engine.rb +12 -9
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/test/factories/foreman_remote_execution_factories.rb +11 -9
- data/test/functional/api/v2/foreign_input_sets_controller_test.rb +63 -0
- data/test/functional/api/v2/job_invocations_controller_test.rb +45 -13
- data/test/functional/api/v2/job_templates_controller_test.rb +6 -6
- data/test/functional/api/v2/template_inputs_controller_test.rb +3 -3
- data/test/unit/actions/run_hosts_job_test.rb +3 -4
- data/test/unit/actions/run_proxy_command_test.rb +7 -7
- data/test/unit/concerns/host_extensions_test.rb +1 -1
- data/test/unit/execution_task_status_mapper_test.rb +93 -0
- data/test/unit/input_template_renderer_test.rb +182 -9
- data/test/unit/job_invocation_composer_test.rb +144 -168
- data/test/unit/job_invocation_test.rb +67 -15
- data/test/unit/job_template_effective_user_test.rb +2 -2
- data/test/unit/job_template_test.rb +36 -12
- data/test/unit/remote_execution_provider_test.rb +6 -6
- data/test/unit/targeting_test.rb +2 -2
- metadata +27 -21
- data/app/models/concerns/foreman_remote_execution/template_relations.rb +0 -10
- data/app/views/job_invocations/_host_provider_td.html.erb +0 -3
- data/app/views/job_templates/auto_complete_job_name.json.erb +0 -3
|
@@ -7,7 +7,7 @@ describe JobInvocationComposer do
|
|
|
7
7
|
permission1 = FactoryGirl.create(:permission, :name => 'view_job_templates', :resource_type => 'JobTemplate')
|
|
8
8
|
permission2 = Permission.find_by_name('view_bookmarks')
|
|
9
9
|
permission3 = Permission.find_by_name('view_hosts')
|
|
10
|
-
filter1 = FactoryGirl.build(:filter, :permissions => [permission1], :search => 'name ~
|
|
10
|
+
filter1 = FactoryGirl.build(:filter, :permissions => [permission1], :search => 'name ~ trying*')
|
|
11
11
|
filter2 = FactoryGirl.build(:filter, :permissions => [permission2])
|
|
12
12
|
filter3 = FactoryGirl.build(:filter, :permissions => [permission3])
|
|
13
13
|
filter1.save
|
|
@@ -21,16 +21,16 @@ describe JobInvocationComposer do
|
|
|
21
21
|
User.current.save
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
let(:
|
|
25
|
-
let(:
|
|
26
|
-
let(:
|
|
27
|
-
let(:unauthorized_job_template_1) { FactoryGirl.create(:job_template, :
|
|
28
|
-
let(:unauthorized_job_template_2) { FactoryGirl.create(:job_template, :
|
|
24
|
+
let(:trying_job_template_1) { FactoryGirl.create(:job_template, :job_category => 'trying_job_template_1', :name => 'trying1', :provider_type => 'SSH') }
|
|
25
|
+
let(:trying_job_template_2) { FactoryGirl.create(:job_template, :job_category => 'trying_job_template_2', :name => 'trying2', :provider_type => 'Mcollective') }
|
|
26
|
+
let(:trying_job_template_3) { FactoryGirl.create(:job_template, :job_category => 'trying_job_template_1', :name => 'trying3', :provider_type => 'SSH') }
|
|
27
|
+
let(:unauthorized_job_template_1) { FactoryGirl.create(:job_template, :job_category => 'trying_job_template_1', :name => 'unauth1', :provider_type => 'SSH') }
|
|
28
|
+
let(:unauthorized_job_template_2) { FactoryGirl.create(:job_template, :job_category => 'unauthorized_job_template_2', :name => 'unauth2', :provider_type => 'Ansible') }
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
let(:input1) { FactoryGirl.create(:template_input, :template =>
|
|
32
|
-
let(:input2) { FactoryGirl.create(:template_input, :template =>
|
|
33
|
-
let(:input3) { FactoryGirl.create(:template_input, :template =>
|
|
31
|
+
let(:input1) { FactoryGirl.create(:template_input, :template => trying_job_template_1, :input_type => 'user') }
|
|
32
|
+
let(:input2) { FactoryGirl.create(:template_input, :template => trying_job_template_3, :input_type => 'user') }
|
|
33
|
+
let(:input3) { FactoryGirl.create(:template_input, :template => trying_job_template_1, :input_type => 'user', :required => true) }
|
|
34
34
|
let(:unauthorized_input1) { FactoryGirl.create(:template_input, :template => unauthorized_job_template_1, :input_type => 'user') }
|
|
35
35
|
|
|
36
36
|
let(:ansible_params) { { } }
|
|
@@ -45,44 +45,44 @@ describe JobInvocationComposer do
|
|
|
45
45
|
describe '#available_templates' do
|
|
46
46
|
it 'obeys authorization' do
|
|
47
47
|
composer # lazy load composer before stubbing
|
|
48
|
-
JobTemplate.expects(:authorized).with(:view_job_templates).returns(JobTemplate.
|
|
48
|
+
JobTemplate.expects(:authorized).with(:view_job_templates).returns(JobTemplate.where({}))
|
|
49
49
|
composer.available_templates
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
context 'job templates exist' do
|
|
54
54
|
before do
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
trying_job_template_1
|
|
56
|
+
trying_job_template_2
|
|
57
|
+
trying_job_template_3
|
|
58
58
|
unauthorized_job_template_1
|
|
59
59
|
unauthorized_job_template_2
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
describe '#available_templates_for(
|
|
62
|
+
describe '#available_templates_for(job_category)' do
|
|
63
63
|
it 'find the templates only for a given job name' do
|
|
64
|
-
results = composer.available_templates_for(
|
|
65
|
-
results.must_include
|
|
66
|
-
results.wont_include
|
|
64
|
+
results = composer.available_templates_for(trying_job_template_1.job_category)
|
|
65
|
+
results.must_include trying_job_template_1
|
|
66
|
+
results.wont_include trying_job_template_2
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
it 'it respects view permissions' do
|
|
70
|
-
results = composer.available_templates_for(
|
|
70
|
+
results = composer.available_templates_for(trying_job_template_1.job_category)
|
|
71
71
|
results.wont_include unauthorized_job_template_1
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
-
describe '#
|
|
76
|
-
let(:
|
|
75
|
+
describe '#available_job_categories' do
|
|
76
|
+
let(:job_categories) { composer.available_job_categories }
|
|
77
77
|
|
|
78
78
|
it 'find only job names that user is granted to view' do
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
job_categories.must_include trying_job_template_1.job_category
|
|
80
|
+
job_categories.must_include trying_job_template_2.job_category
|
|
81
|
+
job_categories.wont_include unauthorized_job_template_2.job_category
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
it 'every job name is listed just once' do
|
|
85
|
-
|
|
85
|
+
job_categories.uniq.must_equal job_categories
|
|
86
86
|
end
|
|
87
87
|
end
|
|
88
88
|
|
|
@@ -90,8 +90,8 @@ describe JobInvocationComposer do
|
|
|
90
90
|
let(:provider_types) { composer.available_provider_types }
|
|
91
91
|
|
|
92
92
|
it 'finds only providers which user is granted to view' do
|
|
93
|
-
composer.job_invocation.
|
|
94
|
-
provider_types.must_include '
|
|
93
|
+
composer.job_invocation.job_category = 'trying_job_template_1'
|
|
94
|
+
provider_types.must_include 'SSH'
|
|
95
95
|
provider_types.wont_include 'Mcollective'
|
|
96
96
|
provider_types.wont_include 'Ansible'
|
|
97
97
|
end
|
|
@@ -115,7 +115,7 @@ describe JobInvocationComposer do
|
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
context 'params contains job template ids' do
|
|
118
|
-
let(:ssh_params) { { :job_template_id =>
|
|
118
|
+
let(:ssh_params) { { :job_template_id => trying_job_template_1.id.to_s } }
|
|
119
119
|
let(:ansible_params) { { :job_template_id => '' } }
|
|
120
120
|
let(:mcollective_params) { { :job_template_id => '' } }
|
|
121
121
|
let(:params) { { :job_invocation => providers_params }.with_indifferent_access }
|
|
@@ -130,58 +130,34 @@ describe JobInvocationComposer do
|
|
|
130
130
|
|
|
131
131
|
describe '#needs_provider_type_selection?' do
|
|
132
132
|
it 'returns true if there are more than one providers respecting authorization' do
|
|
133
|
-
composer.stubs(:available_provider_types => [ '
|
|
133
|
+
composer.stubs(:available_provider_types => [ 'SSH', 'Ansible' ])
|
|
134
134
|
assert composer.needs_provider_type_selection?
|
|
135
135
|
end
|
|
136
136
|
|
|
137
137
|
it 'returns false if there is one provider' do
|
|
138
|
-
composer.stubs(:available_provider_types => [ '
|
|
138
|
+
composer.stubs(:available_provider_types => [ 'SSH' ])
|
|
139
139
|
refute composer.needs_provider_type_selection?
|
|
140
140
|
end
|
|
141
141
|
end
|
|
142
142
|
|
|
143
|
-
describe '#only_one_template_available?' do
|
|
144
|
-
context 'composer needs provider type selection' do
|
|
145
|
-
before { composer.stubs(:needs_provider_type_selection? => true) }
|
|
146
|
-
|
|
147
|
-
it 'returns false because it means we have at least two providers so we need to be able to disable it per provider' do
|
|
148
|
-
refute composer.only_one_template_available?
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
context 'composer does not need provider type selection' do
|
|
153
|
-
before { composer.stubs(:needs_provider_type_selection? => false) }
|
|
154
|
-
|
|
155
|
-
it 'returns true if there is only one template for the provider' do
|
|
156
|
-
composer.stubs(:templates_for_provider => [ testing_job_template_1 ])
|
|
157
|
-
assert composer.only_one_template_available?
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
it 'returns false if there is more than one template for the provider' do
|
|
161
|
-
composer.stubs(:templates_for_provider => [ testing_job_template_1, testing_job_template_3 ])
|
|
162
|
-
refute composer.only_one_template_available?
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
|
|
167
143
|
describe '#displayed_provider_types' do
|
|
168
144
|
# nothing to test yet
|
|
169
145
|
end
|
|
170
146
|
|
|
171
147
|
describe '#templates_for_provider(provider_type)' do
|
|
172
148
|
it 'returns all templates for a given provider respecting template permissions' do
|
|
173
|
-
|
|
174
|
-
result = composer.templates_for_provider('
|
|
175
|
-
result.must_include
|
|
176
|
-
result.must_include
|
|
149
|
+
trying_job_template_4 = FactoryGirl.create(:job_template, :job_category => 'trying_job_template_1', :name => 'trying4', :provider_type => 'Ansible')
|
|
150
|
+
result = composer.templates_for_provider('SSH')
|
|
151
|
+
result.must_include trying_job_template_1
|
|
152
|
+
result.must_include trying_job_template_3
|
|
177
153
|
result.wont_include unauthorized_job_template_1
|
|
178
|
-
result.wont_include
|
|
154
|
+
result.wont_include trying_job_template_4
|
|
179
155
|
|
|
180
156
|
result = composer.templates_for_provider('Ansible')
|
|
181
|
-
result.wont_include
|
|
182
|
-
result.wont_include
|
|
157
|
+
result.wont_include trying_job_template_1
|
|
158
|
+
result.wont_include trying_job_template_3
|
|
183
159
|
result.wont_include unauthorized_job_template_2
|
|
184
|
-
result.must_include
|
|
160
|
+
result.must_include trying_job_template_4
|
|
185
161
|
end
|
|
186
162
|
end
|
|
187
163
|
|
|
@@ -191,9 +167,9 @@ describe JobInvocationComposer do
|
|
|
191
167
|
end
|
|
192
168
|
|
|
193
169
|
context 'extra unavailable templates id were selected' do
|
|
194
|
-
let(:unauthorized) { FactoryGirl.create(:job_template, :
|
|
195
|
-
let(:mcollective_authorized) { FactoryGirl.create(:job_template, :
|
|
196
|
-
let(:ssh_params) { { :job_template_id =>
|
|
170
|
+
let(:unauthorized) { FactoryGirl.create(:job_template, :job_category => 'trying_job_template_1', :name => 'unauth3', :provider_type => 'Ansible') }
|
|
171
|
+
let(:mcollective_authorized) { FactoryGirl.create(:job_template, :job_category => 'trying_job_template_1', :name => 'trying4', :provider_type => 'Mcollective') }
|
|
172
|
+
let(:ssh_params) { { :job_template_id => trying_job_template_1.id.to_s } }
|
|
197
173
|
let(:ansible_params) { { :job_template_id => unauthorized.id.to_s } }
|
|
198
174
|
let(:mcollective_params) { { :job_template_id => mcollective_authorized.id.to_s } }
|
|
199
175
|
let(:params) { { :job_invocation => providers_params }.with_indifferent_access }
|
|
@@ -205,44 +181,44 @@ describe JobInvocationComposer do
|
|
|
205
181
|
|
|
206
182
|
it 'contains only authorized template specified in params' do
|
|
207
183
|
mcollective_authorized # make sure mcollective_authorized exists
|
|
208
|
-
composer.selected_job_templates.must_include
|
|
184
|
+
composer.selected_job_templates.must_include trying_job_template_1
|
|
209
185
|
composer.selected_job_templates.must_include mcollective_authorized
|
|
210
|
-
composer.selected_job_templates.wont_include
|
|
186
|
+
composer.selected_job_templates.wont_include trying_job_template_3
|
|
211
187
|
end
|
|
212
188
|
end
|
|
213
189
|
end
|
|
214
190
|
|
|
215
|
-
describe '#
|
|
191
|
+
describe '#preselected_template_for_provider(provider_type)' do
|
|
216
192
|
context 'none template was selected through params' do
|
|
217
|
-
it 'returns
|
|
218
|
-
|
|
193
|
+
it 'returns nil' do
|
|
194
|
+
composer.preselected_template_for_provider('SSH').must_be_nil
|
|
219
195
|
end
|
|
220
196
|
end
|
|
221
197
|
|
|
222
198
|
context 'available template was selected for a specified provider through params' do
|
|
223
|
-
let(:ssh_params) { { :job_template_id =>
|
|
199
|
+
let(:ssh_params) { { :job_template_id => trying_job_template_1.id.to_s } }
|
|
224
200
|
let(:params) { { :job_invocation => providers_params }.with_indifferent_access }
|
|
225
201
|
|
|
226
|
-
it 'returns
|
|
227
|
-
|
|
202
|
+
it 'returns the selected template because it is available for provider' do
|
|
203
|
+
composer.preselected_template_for_provider('SSH').must_equal trying_job_template_1
|
|
228
204
|
end
|
|
229
205
|
end
|
|
230
206
|
end
|
|
231
207
|
|
|
232
|
-
describe '#template_invocations' do
|
|
208
|
+
describe '#pattern template_invocations' do
|
|
233
209
|
let(:ssh_params) do
|
|
234
|
-
{ :job_template_id =>
|
|
210
|
+
{ :job_template_id => trying_job_template_1.id.to_s,
|
|
235
211
|
:job_templates => {
|
|
236
|
-
|
|
212
|
+
trying_job_template_1.id.to_s => {
|
|
237
213
|
:input_values => { input1.id.to_s => { :value => 'value1' }, unauthorized_input1.id.to_s => { :value => 'dropped' } }
|
|
238
214
|
}
|
|
239
215
|
}
|
|
240
216
|
}
|
|
241
217
|
end
|
|
242
218
|
let(:params) { { :job_invocation => { :providers => { :ssh => ssh_params } } }.with_indifferent_access }
|
|
243
|
-
let(:invocations) { composer.
|
|
219
|
+
let(:invocations) { composer.pattern_template_invocations }
|
|
244
220
|
|
|
245
|
-
it 'builds template invocations based on passed params and it filters out wrong inputs' do
|
|
221
|
+
it 'builds pattern template invocations based on passed params and it filters out wrong inputs' do
|
|
246
222
|
invocations.size.must_equal 1
|
|
247
223
|
invocations.first.input_values.size.must_equal 1
|
|
248
224
|
invocations.first.input_values.first.value.must_equal 'value1'
|
|
@@ -251,9 +227,9 @@ describe JobInvocationComposer do
|
|
|
251
227
|
|
|
252
228
|
describe '#effective_user' do
|
|
253
229
|
let(:ssh_params) do
|
|
254
|
-
{ :job_template_id =>
|
|
230
|
+
{ :job_template_id => trying_job_template_1.id.to_s,
|
|
255
231
|
:job_templates => {
|
|
256
|
-
|
|
232
|
+
trying_job_template_1.id.to_s => {
|
|
257
233
|
:effective_user => invocation_effective_user
|
|
258
234
|
}
|
|
259
235
|
}
|
|
@@ -261,8 +237,8 @@ describe JobInvocationComposer do
|
|
|
261
237
|
end
|
|
262
238
|
let(:params) { { :job_invocation => { :providers => { :ssh => ssh_params } } }.with_indifferent_access }
|
|
263
239
|
let(:template_invocation) do
|
|
264
|
-
|
|
265
|
-
composer.
|
|
240
|
+
trying_job_template_1.effective_user.update_attributes(:overridable => overridable, :value => 'template user')
|
|
241
|
+
composer.pattern_template_invocations.first
|
|
266
242
|
end
|
|
267
243
|
|
|
268
244
|
before do
|
|
@@ -280,7 +256,7 @@ describe JobInvocationComposer do
|
|
|
280
256
|
|
|
281
257
|
context 'when overridable and not provided' do
|
|
282
258
|
let(:overridable) { true }
|
|
283
|
-
let(:invocation_effective_user) {
|
|
259
|
+
let(:invocation_effective_user) { '' }
|
|
284
260
|
|
|
285
261
|
it 'takes the value from the job template' do
|
|
286
262
|
template_invocation.effective_user.must_equal 'template user'
|
|
@@ -289,7 +265,7 @@ describe JobInvocationComposer do
|
|
|
289
265
|
|
|
290
266
|
context 'when not overridable and provided' do
|
|
291
267
|
let(:overridable) { false }
|
|
292
|
-
let(:invocation_effective_user) {
|
|
268
|
+
let(:invocation_effective_user) { 'invocation user' }
|
|
293
269
|
|
|
294
270
|
it 'takes the value from the job template' do
|
|
295
271
|
template_invocation.effective_user.must_equal 'template user'
|
|
@@ -347,7 +323,7 @@ describe JobInvocationComposer do
|
|
|
347
323
|
describe '#available_bookmarks' do
|
|
348
324
|
it 'obeys authorization' do
|
|
349
325
|
composer
|
|
350
|
-
Bookmark.expects(:authorized).with(:view_bookmarks).returns(Bookmark.
|
|
326
|
+
Bookmark.expects(:authorized).with(:view_bookmarks).returns(Bookmark.where({}))
|
|
351
327
|
composer.available_bookmarks
|
|
352
328
|
end
|
|
353
329
|
|
|
@@ -372,7 +348,7 @@ describe JobInvocationComposer do
|
|
|
372
348
|
|
|
373
349
|
it 'obeys authorization' do
|
|
374
350
|
composer.stubs(:displayed_search_query => "name = #{host.name}")
|
|
375
|
-
Host.expects(:authorized).with(:view_hosts, Host).returns(Host.
|
|
351
|
+
Host.expects(:authorized).with(:view_hosts, Host).returns(Host.where({}))
|
|
376
352
|
composer.targeted_hosts_count
|
|
377
353
|
end
|
|
378
354
|
|
|
@@ -382,7 +358,7 @@ describe JobInvocationComposer do
|
|
|
382
358
|
end
|
|
383
359
|
|
|
384
360
|
it 'returns 0 for queries with syntax errors' do
|
|
385
|
-
composer.stubs(:displayed_search_query =>
|
|
361
|
+
composer.stubs(:displayed_search_query => 'name = ')
|
|
386
362
|
composer.targeted_hosts_count.must_equal 0
|
|
387
363
|
end
|
|
388
364
|
|
|
@@ -393,7 +369,7 @@ describe JobInvocationComposer do
|
|
|
393
369
|
end
|
|
394
370
|
|
|
395
371
|
describe '#template_invocation_input_value_for(input)' do
|
|
396
|
-
let(:value1) { composer.template_invocation_input_value_for(input1) }
|
|
372
|
+
let(:value1) { composer.template_invocation_input_value_for(trying_job_template_1, input1) }
|
|
397
373
|
it 'returns new empty input value if there is no invocation' do
|
|
398
374
|
assert value1.new_record?
|
|
399
375
|
value1.value.must_be_empty
|
|
@@ -401,9 +377,9 @@ describe JobInvocationComposer do
|
|
|
401
377
|
|
|
402
378
|
context 'there are invocations without input values for a given input' do
|
|
403
379
|
let(:ssh_params) do
|
|
404
|
-
{ :job_template_id =>
|
|
380
|
+
{ :job_template_id => trying_job_template_1.id.to_s,
|
|
405
381
|
:job_templates => {
|
|
406
|
-
|
|
382
|
+
trying_job_template_1.id.to_s => {
|
|
407
383
|
:input_values => { }
|
|
408
384
|
} } }
|
|
409
385
|
end
|
|
@@ -417,9 +393,9 @@ describe JobInvocationComposer do
|
|
|
417
393
|
|
|
418
394
|
context 'there are invocations with input values for a given input' do
|
|
419
395
|
let(:ssh_params) do
|
|
420
|
-
{ :job_template_id =>
|
|
396
|
+
{ :job_template_id => trying_job_template_1.id.to_s,
|
|
421
397
|
:job_templates => {
|
|
422
|
-
|
|
398
|
+
trying_job_template_1.id.to_s => {
|
|
423
399
|
:input_values => { input1.id.to_s => { :value => 'value1' } }
|
|
424
400
|
} } }
|
|
425
401
|
end
|
|
@@ -434,9 +410,9 @@ describe JobInvocationComposer do
|
|
|
434
410
|
describe '#valid?' do
|
|
435
411
|
let(:host) { FactoryGirl.create(:host) }
|
|
436
412
|
let(:ssh_params) do
|
|
437
|
-
{ :job_template_id =>
|
|
413
|
+
{ :job_template_id => trying_job_template_1.id.to_s,
|
|
438
414
|
:job_templates => {
|
|
439
|
-
|
|
415
|
+
trying_job_template_1.id.to_s => {
|
|
440
416
|
:input_values => { input1.id.to_s => { :value => 'value1' } }
|
|
441
417
|
} } }
|
|
442
418
|
end
|
|
@@ -448,7 +424,7 @@ describe JobInvocationComposer do
|
|
|
448
424
|
composer
|
|
449
425
|
composer.job_invocation.expects(:valid?).returns(false)
|
|
450
426
|
composer.targeting.expects(:valid?).returns(false)
|
|
451
|
-
composer.
|
|
427
|
+
composer.pattern_template_invocations.each { |invocation| invocation.expects(:valid?).returns(false) }
|
|
452
428
|
refute composer.valid?
|
|
453
429
|
end
|
|
454
430
|
end
|
|
@@ -477,11 +453,11 @@ describe JobInvocationComposer do
|
|
|
477
453
|
end
|
|
478
454
|
end
|
|
479
455
|
|
|
480
|
-
describe '#
|
|
481
|
-
it 'triggers
|
|
456
|
+
describe '#job_category' do
|
|
457
|
+
it 'triggers job_category on job_invocation' do
|
|
482
458
|
composer
|
|
483
|
-
composer.job_invocation.expects(:
|
|
484
|
-
composer.
|
|
459
|
+
composer.job_invocation.expects(:job_category)
|
|
460
|
+
composer.job_category
|
|
485
461
|
end
|
|
486
462
|
end
|
|
487
463
|
|
|
@@ -496,9 +472,9 @@ describe JobInvocationComposer do
|
|
|
496
472
|
describe '#compose_from_invocation(existing_invocation)' do
|
|
497
473
|
let(:host) { FactoryGirl.create(:host) }
|
|
498
474
|
let(:ssh_params) do
|
|
499
|
-
{ :job_template_id =>
|
|
475
|
+
{ :job_template_id => trying_job_template_1.id.to_s,
|
|
500
476
|
:job_templates => {
|
|
501
|
-
|
|
477
|
+
trying_job_template_1.id.to_s => {
|
|
502
478
|
:input_values => { input1.id.to_s => { :value => 'value1' } }
|
|
503
479
|
} } }
|
|
504
480
|
end
|
|
@@ -522,7 +498,7 @@ describe JobInvocationComposer do
|
|
|
522
498
|
end
|
|
523
499
|
|
|
524
500
|
it 'sets the same job name' do
|
|
525
|
-
new_composer.
|
|
501
|
+
new_composer.job_category.must_equal existing.job_category
|
|
526
502
|
end
|
|
527
503
|
|
|
528
504
|
it 'builds new targeting object which keeps search query' do
|
|
@@ -531,11 +507,11 @@ describe JobInvocationComposer do
|
|
|
531
507
|
end
|
|
532
508
|
|
|
533
509
|
it 'keeps job template ids' do
|
|
534
|
-
new_composer.job_template_ids.must_equal existing.
|
|
510
|
+
new_composer.job_template_ids.must_equal existing.pattern_template_invocations.map(&:template_id)
|
|
535
511
|
end
|
|
536
512
|
|
|
537
513
|
it 'keeps template invocations and their values' do
|
|
538
|
-
new_composer.
|
|
514
|
+
new_composer.pattern_template_invocations.size.must_equal existing.pattern_template_invocations.size
|
|
539
515
|
end
|
|
540
516
|
|
|
541
517
|
end
|
|
@@ -549,153 +525,153 @@ describe JobInvocationComposer do
|
|
|
549
525
|
context 'with targeting from bookmark' do
|
|
550
526
|
|
|
551
527
|
before do
|
|
552
|
-
[
|
|
528
|
+
[trying_job_template_1, trying_job_template_3] # mentioning templates we want to have initialized in the test
|
|
553
529
|
end
|
|
554
530
|
|
|
555
531
|
let(:params) do
|
|
556
|
-
{ :
|
|
557
|
-
:job_template_id =>
|
|
558
|
-
:targeting_type =>
|
|
532
|
+
{ :job_category => trying_job_template_1.job_category,
|
|
533
|
+
:job_template_id => trying_job_template_1.id,
|
|
534
|
+
:targeting_type => 'static_query',
|
|
559
535
|
:bookmark_id => bookmark.id }
|
|
560
536
|
end
|
|
561
537
|
|
|
562
|
-
it
|
|
538
|
+
it 'creates invocation with a bookmark' do
|
|
563
539
|
assert composer.save!
|
|
564
540
|
assert_equal bookmark, composer.job_invocation.targeting.bookmark
|
|
565
541
|
assert_equal composer.job_invocation.targeting.user, User.current
|
|
566
|
-
refute_empty composer.job_invocation.
|
|
542
|
+
refute_empty composer.job_invocation.pattern_template_invocations
|
|
567
543
|
end
|
|
568
544
|
end
|
|
569
545
|
|
|
570
|
-
context
|
|
546
|
+
context 'with targeting from search query' do
|
|
571
547
|
let(:params) do
|
|
572
|
-
{ :
|
|
573
|
-
:job_template_id =>
|
|
574
|
-
:targeting_type =>
|
|
575
|
-
:search_query =>
|
|
548
|
+
{ :job_category => trying_job_template_1.job_category,
|
|
549
|
+
:job_template_id => trying_job_template_1.id,
|
|
550
|
+
:targeting_type => 'static_query',
|
|
551
|
+
:search_query => 'some hosts' }
|
|
576
552
|
end
|
|
577
553
|
|
|
578
|
-
it
|
|
554
|
+
it 'creates invocation with a search query' do
|
|
579
555
|
assert composer.save!
|
|
580
|
-
assert_equal
|
|
581
|
-
refute_empty composer.job_invocation.
|
|
556
|
+
assert_equal 'some hosts', composer.job_invocation.targeting.search_query
|
|
557
|
+
refute_empty composer.job_invocation.pattern_template_invocations
|
|
582
558
|
end
|
|
583
559
|
end
|
|
584
560
|
|
|
585
|
-
context
|
|
561
|
+
context 'with with inputs' do
|
|
586
562
|
let(:params) do
|
|
587
|
-
{ :
|
|
588
|
-
:job_template_id =>
|
|
589
|
-
:targeting_type =>
|
|
590
|
-
:search_query =>
|
|
591
|
-
:inputs => {input1.name =>
|
|
563
|
+
{ :job_category => trying_job_template_1.job_category,
|
|
564
|
+
:job_template_id => trying_job_template_1.id,
|
|
565
|
+
:targeting_type => 'static_query',
|
|
566
|
+
:search_query => 'some hosts',
|
|
567
|
+
:inputs => {input1.name => 'some_value'}}
|
|
592
568
|
end
|
|
593
569
|
|
|
594
|
-
it
|
|
570
|
+
it 'finds the inputs by name' do
|
|
595
571
|
assert composer.save!
|
|
596
|
-
assert_equal 1, composer.
|
|
572
|
+
assert_equal 1, composer.pattern_template_invocations.first.input_values.count
|
|
597
573
|
end
|
|
598
574
|
end
|
|
599
575
|
|
|
600
|
-
context
|
|
576
|
+
context 'with effective user' do
|
|
601
577
|
let(:params) do
|
|
602
|
-
{ :
|
|
603
|
-
:job_template_id =>
|
|
578
|
+
{ :job_category => trying_job_template_1.job_category,
|
|
579
|
+
:job_template_id => trying_job_template_1.id,
|
|
604
580
|
:effective_user => 'invocation user',
|
|
605
|
-
:targeting_type =>
|
|
606
|
-
:search_query =>
|
|
607
|
-
:inputs => {input1.name =>
|
|
581
|
+
:targeting_type => 'static_query',
|
|
582
|
+
:search_query => 'some hosts',
|
|
583
|
+
:inputs => {input1.name => 'some_value'}}
|
|
608
584
|
end
|
|
609
585
|
|
|
610
|
-
let(:template_invocation) { composer.job_invocation.
|
|
586
|
+
let(:template_invocation) { composer.job_invocation.pattern_template_invocations.first }
|
|
611
587
|
|
|
612
|
-
it
|
|
588
|
+
it 'sets the effective user based on the input' do
|
|
613
589
|
assert composer.save!
|
|
614
590
|
template_invocation.effective_user.must_equal 'invocation user'
|
|
615
591
|
end
|
|
616
592
|
end
|
|
617
593
|
|
|
618
|
-
context
|
|
594
|
+
context 'with invalid targeting' do
|
|
619
595
|
let(:params) do
|
|
620
|
-
{ :
|
|
621
|
-
:job_template_id =>
|
|
622
|
-
:search_query =>
|
|
623
|
-
:inputs => {input1.name =>
|
|
596
|
+
{ :job_category => trying_job_template_1.job_category,
|
|
597
|
+
:job_template_id => trying_job_template_1.id,
|
|
598
|
+
:search_query => 'some hosts',
|
|
599
|
+
:inputs => {input1.name => 'some_value'}}
|
|
624
600
|
end
|
|
625
601
|
|
|
626
|
-
it
|
|
602
|
+
it 'handles errors' do
|
|
627
603
|
assert_raises(ActiveRecord::RecordNotSaved) do
|
|
628
604
|
composer.save!
|
|
629
605
|
end
|
|
630
606
|
end
|
|
631
607
|
end
|
|
632
608
|
|
|
633
|
-
context
|
|
609
|
+
context 'with invalid bookmark and search query' do
|
|
634
610
|
let(:params) do
|
|
635
|
-
{ :
|
|
636
|
-
:job_template_id =>
|
|
637
|
-
:targeting_type =>
|
|
638
|
-
:search_query =>
|
|
611
|
+
{ :job_category => trying_job_template_1.job_category,
|
|
612
|
+
:job_template_id => trying_job_template_1.id,
|
|
613
|
+
:targeting_type => 'static_query',
|
|
614
|
+
:search_query => 'some hosts',
|
|
639
615
|
:bookmark_id => bookmark.id,
|
|
640
|
-
:inputs => {input1.name =>
|
|
616
|
+
:inputs => {input1.name => 'some_value'}}
|
|
641
617
|
end
|
|
642
618
|
|
|
643
|
-
it
|
|
619
|
+
it 'handles errors' do
|
|
644
620
|
assert_raises(Foreman::Exception) do
|
|
645
621
|
JobInvocationComposer.from_api_params(params)
|
|
646
622
|
end
|
|
647
623
|
end
|
|
648
624
|
end
|
|
649
625
|
|
|
650
|
-
context
|
|
626
|
+
context 'with invalid inputs' do
|
|
651
627
|
let(:params) do
|
|
652
|
-
{ :
|
|
653
|
-
:job_template_id =>
|
|
654
|
-
:targeting_type =>
|
|
655
|
-
:search_query =>
|
|
628
|
+
{ :job_category => trying_job_template_1.job_category,
|
|
629
|
+
:job_template_id => trying_job_template_1.id,
|
|
630
|
+
:targeting_type => 'static_query',
|
|
631
|
+
:search_query => 'some hosts',
|
|
656
632
|
:inputs => {input3.name => nil}}
|
|
657
633
|
end
|
|
658
634
|
|
|
659
|
-
it
|
|
635
|
+
it 'handles errors' do
|
|
660
636
|
error = assert_raises(ActiveRecord::RecordNotSaved) do
|
|
661
637
|
composer.save!
|
|
662
638
|
end
|
|
663
|
-
error.message.must_include "Template #{
|
|
639
|
+
error.message.must_include "Template #{trying_job_template_1.name}: Input #{input3.name.downcase}: Value can't be blank"
|
|
664
640
|
end
|
|
665
641
|
end
|
|
666
642
|
|
|
667
|
-
context
|
|
643
|
+
context 'with empty values for non-required inputs' do
|
|
668
644
|
let(:params) do
|
|
669
|
-
{ :
|
|
670
|
-
:job_template_id =>
|
|
671
|
-
:targeting_type =>
|
|
672
|
-
:search_query =>
|
|
673
|
-
:inputs => {input3.name =>
|
|
645
|
+
{ :job_category => trying_job_template_1.job_category,
|
|
646
|
+
:job_template_id => trying_job_template_1.id,
|
|
647
|
+
:targeting_type => 'static_query',
|
|
648
|
+
:search_query => 'some hosts',
|
|
649
|
+
:inputs => {input3.name => 'some value'}}
|
|
674
650
|
end
|
|
675
651
|
|
|
676
|
-
it
|
|
652
|
+
it 'accepts the params' do
|
|
677
653
|
composer.save!
|
|
678
654
|
refute composer.job_invocation.new_record?
|
|
679
655
|
end
|
|
680
656
|
end
|
|
681
657
|
|
|
682
|
-
context
|
|
658
|
+
context 'with missing required inputs' do
|
|
683
659
|
let(:params) do
|
|
684
|
-
{ :
|
|
685
|
-
:job_template_id =>
|
|
686
|
-
:targeting_type =>
|
|
687
|
-
:search_query =>
|
|
688
|
-
:inputs => {input1.name =>
|
|
660
|
+
{ :job_category => trying_job_template_1.job_category,
|
|
661
|
+
:job_template_id => trying_job_template_1.id,
|
|
662
|
+
:targeting_type => 'static_query',
|
|
663
|
+
:search_query => 'some hosts',
|
|
664
|
+
:inputs => {input1.name => 'some_value'}}
|
|
689
665
|
end
|
|
690
666
|
|
|
691
|
-
it
|
|
667
|
+
it 'handles errors' do
|
|
692
668
|
input3.must_be :required
|
|
693
669
|
|
|
694
670
|
error = assert_raises(ActiveRecord::RecordNotSaved) do
|
|
695
671
|
composer.save!
|
|
696
672
|
end
|
|
697
673
|
|
|
698
|
-
error.message.must_include "Template #{
|
|
674
|
+
error.message.must_include "Template #{trying_job_template_1.name}: Not all required inputs have values. Missing inputs: #{input3.name}"
|
|
699
675
|
end
|
|
700
676
|
end
|
|
701
677
|
end
|