foreman_remote_execution 0.0.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.
Files changed (83) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE +619 -0
  3. data/README.md +54 -0
  4. data/Rakefile +47 -0
  5. data/app/assets/javascripts/template_input.js +9 -0
  6. data/app/assets/javascripts/template_invocation.js +32 -0
  7. data/app/assets/stylesheets/job_invocations.css.scss +35 -0
  8. data/app/assets/stylesheets/template_invocation.css.scss +16 -0
  9. data/app/controllers/api/v2/job_templates_controller.rb +108 -0
  10. data/app/controllers/job_invocations_controller.rb +35 -0
  11. data/app/controllers/job_templates_controller.rb +35 -0
  12. data/app/helpers/concerns/foreman_remote_execution/hosts_helper_extensions.rb +40 -0
  13. data/app/helpers/remote_execution_helper.rb +88 -0
  14. data/app/lib/actions/remote_execution/run_host_job.rb +93 -0
  15. data/app/lib/actions/remote_execution/run_hosts_job.rb +35 -0
  16. data/app/lib/actions/remote_execution/run_proxy_command.rb +34 -0
  17. data/app/models/concerns/foreman_remote_execution/bookmark_extensions.rb +9 -0
  18. data/app/models/concerns/foreman_remote_execution/foreman_tasks_task_extensions.rb +9 -0
  19. data/app/models/concerns/foreman_remote_execution/host_extensions.rb +19 -0
  20. data/app/models/concerns/foreman_remote_execution/template_extensions.rb +20 -0
  21. data/app/models/concerns/foreman_remote_execution/template_relations.rb +10 -0
  22. data/app/models/concerns/foreman_remote_execution/user_extensions.rb +9 -0
  23. data/app/models/input_template_renderer.rb +42 -0
  24. data/app/models/job_invocation.rb +21 -0
  25. data/app/models/job_invocation_composer.rb +210 -0
  26. data/app/models/job_template.rb +52 -0
  27. data/app/models/remote_execution_provider.rb +17 -0
  28. data/app/models/setting/remote_execution.rb +19 -0
  29. data/app/models/ssh_execution_provider.rb +2 -0
  30. data/app/models/targeting.rb +56 -0
  31. data/app/models/targeting_host.rb +9 -0
  32. data/app/models/template_input.rb +154 -0
  33. data/app/models/template_invocation.rb +13 -0
  34. data/app/models/template_invocation_input_value.rb +8 -0
  35. data/app/views/api/v2/job_templates/base.json.rabl +3 -0
  36. data/app/views/api/v2/job_templates/create.json.rabl +3 -0
  37. data/app/views/api/v2/job_templates/index.json.rabl +3 -0
  38. data/app/views/api/v2/job_templates/main.json.rabl +5 -0
  39. data/app/views/api/v2/job_templates/show.json.rabl +9 -0
  40. data/app/views/job_invocations/_form.html.erb +67 -0
  41. data/app/views/job_invocations/_tab_hosts.html.erb +33 -0
  42. data/app/views/job_invocations/_tab_overview.html.erb +41 -0
  43. data/app/views/job_invocations/index.html.erb +30 -0
  44. data/app/views/job_invocations/new.html.erb +8 -0
  45. data/app/views/job_invocations/refresh.js.erb +1 -0
  46. data/app/views/job_invocations/show.html.erb +21 -0
  47. data/app/views/job_templates/_custom_tab_headers.html.erb +2 -0
  48. data/app/views/job_templates/_custom_tabs.html.erb +28 -0
  49. data/app/views/job_templates/auto_complete_job_name.json.erb +3 -0
  50. data/app/views/job_templates/edit.html.erb +6 -0
  51. data/app/views/job_templates/index.html.erb +33 -0
  52. data/app/views/job_templates/new.html.erb +6 -0
  53. data/app/views/template_inputs/_form.html.erb +22 -0
  54. data/config/routes.rb +35 -0
  55. data/db/migrate/20150612121541_add_job_template_to_template.rb +6 -0
  56. data/db/migrate/20150616080015_create_template_input.rb +19 -0
  57. data/db/migrate/20150708133241_add_targeting.rb +25 -0
  58. data/db/migrate/20150708133242_add_invocation.rb +11 -0
  59. data/db/migrate/20150708133305_add_template_invocation.rb +22 -0
  60. data/db/migrate/20150812110800_add_resolved_at_to_targeting.rb +5 -0
  61. data/db/migrate/20150812145900_add_last_task_id_to_job_invocation.rb +6 -0
  62. data/db/seeds.d/60-ssh_proxy_feature.rb +2 -0
  63. data/lib/foreman_remote_execution/engine.rb +119 -0
  64. data/lib/foreman_remote_execution/version.rb +3 -0
  65. data/lib/foreman_remote_execution.rb +6 -0
  66. data/lib/tasks/foreman_remote_execution_tasks.rake +49 -0
  67. data/locale/Makefile +62 -0
  68. data/locale/en/foreman_remote_execution.po +19 -0
  69. data/locale/foreman_remote_execution.pot +19 -0
  70. data/locale/gemspec.rb +2 -0
  71. data/test/factories/foreman_remote_execution_factories.rb +48 -0
  72. data/test/functional/api/v2/job_templates_controller_test.rb +74 -0
  73. data/test/test_plugin_helper.rb +8 -0
  74. data/test/unit/actions/run_hosts_job_test.rb +40 -0
  75. data/test/unit/actions/run_proxy_command_test.rb +30 -0
  76. data/test/unit/input_template_renderer_test.rb +366 -0
  77. data/test/unit/job_invocation_composer_test.rb +415 -0
  78. data/test/unit/job_invocation_test.rb +31 -0
  79. data/test/unit/job_template_test.rb +5 -0
  80. data/test/unit/remote_execution_provider_test.rb +51 -0
  81. data/test/unit/targeting_test.rb +107 -0
  82. data/test/unit/template_input_test.rb +25 -0
  83. metadata +195 -0
@@ -0,0 +1,366 @@
1
+ require 'test_plugin_helper'
2
+
3
+ describe InputTemplateRenderer do
4
+ context "renderer for simple template without inputs" do
5
+ let(:renderer) { InputTemplateRenderer.new(FactoryGirl.build(:job_template, :template => 'id')) }
6
+
7
+ it 'should render the content' do
8
+ renderer.render.must_equal 'id'
9
+ end
10
+
11
+ it 'should render preview' do
12
+ renderer.preview.must_equal 'id'
13
+ end
14
+ end
15
+
16
+ context "renderer for template with user input used" do
17
+ let(:template) { FactoryGirl.build(:job_template, :template => 'service restart <%= input("service_name") -%>') }
18
+ let(:renderer) { InputTemplateRenderer.new(template) }
19
+
20
+ context 'but without input defined' do
21
+ describe 'rendering' do
22
+ let(:result) { renderer.render }
23
+ it { result.must_equal false }
24
+
25
+ it 'registers an error' do
26
+ result # let is lazy
27
+ renderer.error_message.wont_be_nil
28
+ renderer.error_message.wont_be_empty
29
+ end
30
+ end
31
+
32
+ describe 'preview' do
33
+ let(:result) { renderer.preview }
34
+ it { result.must_equal false }
35
+
36
+ it 'registers an error' do
37
+ result # let is lazy
38
+ renderer.error_message.wont_be_nil
39
+ renderer.error_message.wont_be_empty
40
+ end
41
+ end
42
+ end
43
+
44
+ context 'with matching input defined' do
45
+
46
+ let(:job_invocation) { FactoryGirl.create(:job_invocation) }
47
+ let(:template_invocation) { FactoryGirl.build(:template_invocation, :template => template) }
48
+ let(:result) { renderer.render }
49
+
50
+ before do
51
+ template.template_inputs << FactoryGirl.build(:template_input, :name => 'service_name', :input_type => 'user')
52
+ job_invocation.template_invocations << template_invocation
53
+ renderer.invocation = template_invocation
54
+ end
55
+
56
+ describe 'rendering' do
57
+ it 'can\'t render the content without job invocation since we don\'t have values' do
58
+ refute result
59
+ end
60
+
61
+ it 'registers an error' do
62
+ result # let is lazy
63
+ renderer.error_message.wont_be_nil
64
+ renderer.error_message.wont_be_empty
65
+ end
66
+
67
+ context 'with invocation specified' do
68
+ before do
69
+ FactoryGirl.create(:template_invocation_input_value,
70
+ :template_invocation => template_invocation,
71
+ :template_input => template.template_inputs.first,
72
+ :value => 'foreman')
73
+ end
74
+
75
+ it 'can render with job invocation with corresponding value' do
76
+ renderer.render.must_equal 'service restart foreman'
77
+ end
78
+ end
79
+ end
80
+
81
+ describe 'preview' do
82
+ it 'should render preview' do
83
+ renderer.preview.must_equal 'service restart $USER_INPUT[service_name]'
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ context "renderer for template with fact input used" do
90
+ let(:template) { FactoryGirl.build(:job_template, :template => 'echo <%= input("issue") -%> > /etc/issue') }
91
+ let(:renderer) { InputTemplateRenderer.new(template) }
92
+
93
+ context 'with matching input defined' do
94
+ before { renderer.template.template_inputs<< FactoryGirl.build(:template_input, :name => 'issue', :input_type => 'fact', :fact_name => 'issue') }
95
+ let(:result) { renderer.render }
96
+
97
+ describe 'rendering' do
98
+ it 'can\'t render the content without host since we don\'t have facts' do
99
+ refute result
100
+ end
101
+
102
+ it 'registers an error' do
103
+ result # let is lazy
104
+ renderer.error_message.wont_be_nil
105
+ renderer.error_message.wont_be_empty
106
+ end
107
+
108
+ context 'with host specified' do
109
+ before { renderer.host = FactoryGirl.create(:host) }
110
+
111
+ describe 'rendering' do
112
+ it 'can\'t render the content without host since we don\'t have fact value' do
113
+ refute result
114
+ end
115
+
116
+ it 'registers an error' do
117
+ result # let is lazy
118
+ renderer.error_message.wont_be_nil
119
+ renderer.error_message.wont_be_empty
120
+ end
121
+ end
122
+
123
+ describe 'preview' do
124
+ it 'should render preview' do
125
+ renderer.preview.must_equal 'echo $FACT_INPUT[issue] > /etc/issue'
126
+ end
127
+ end
128
+
129
+ context 'with existing fact' do
130
+ let(:fact) { FactoryGirl.create(:fact_name, :name => 'issue') }
131
+
132
+ describe 'rendering' do
133
+ it 'can\'t render the content without host since we don\'t have fact value' do
134
+ fact # let is lazy
135
+ refute result
136
+ end
137
+
138
+ it 'registers an error' do
139
+ result # let is lazy
140
+ renderer.error_message.wont_be_nil
141
+ renderer.error_message.wont_be_empty
142
+ end
143
+ end
144
+
145
+ describe 'preview' do
146
+ it 'should render preview' do
147
+ renderer.preview.must_equal 'echo $FACT_INPUT[issue] > /etc/issue'
148
+ end
149
+ end
150
+
151
+ context 'with fact issue value' do
152
+ before { FactoryGirl.create(:fact_value, :host => renderer.host, :fact_name => fact, :value => 'banner') }
153
+
154
+ let(:result) { renderer.render }
155
+
156
+ it 'can render with job invocation with corresponding value' do
157
+ result.must_equal 'echo banner > /etc/issue'
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ describe 'preview' do
165
+ it 'should render preview' do
166
+ renderer.preview.must_equal 'echo $FACT_INPUT[issue] > /etc/issue'
167
+ end
168
+
169
+ context 'with host specified' do
170
+ before do
171
+ host = FactoryGirl.create(:host)
172
+ fact = FactoryGirl.create(:fact_name, :name => 'issue')
173
+ FactoryGirl.create(:fact_value, :host => host, :fact_name => fact, :value => 'banner')
174
+ renderer.host = host
175
+ end
176
+
177
+ let(:result) { renderer.render }
178
+
179
+ it 'uses the value even in preview' do
180
+ result.must_equal 'echo banner > /etc/issue'
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ context "renderer for template with variable input used" do
188
+ let(:template) { FactoryGirl.build(:job_template, :template => 'echo <%= input("client_key") -%> > /etc/chef/client.pem') }
189
+ let(:renderer) { InputTemplateRenderer.new(template) }
190
+
191
+ context 'with matching input defined' do
192
+ before { renderer.template.template_inputs<< FactoryGirl.build(:template_input, :name => 'client_key', :input_type => 'variable', :variable_name => 'client_key') }
193
+ let(:result) { renderer.render }
194
+
195
+ describe 'rendering' do
196
+ it 'can\'t render the content without host since we don\'t have host so no classification' do
197
+ refute result
198
+ end
199
+
200
+ it 'registers an error' do
201
+ result # let is lazy
202
+ renderer.error_message.wont_be_nil
203
+ renderer.error_message.wont_be_empty
204
+ end
205
+
206
+ context 'with host specified' do
207
+ let(:environment) { FactoryGirl.create(:environment) }
208
+ before { renderer.host = FactoryGirl.create(:host, :environment => environment) }
209
+
210
+ describe 'rendering' do
211
+ it 'can\'t render the content without host since we don\'t have variable value in classification' do
212
+ refute result
213
+ end
214
+
215
+ it 'registers an error' do
216
+ result # let is lazy
217
+ renderer.error_message.wont_be_nil
218
+ renderer.error_message.wont_be_empty
219
+ end
220
+ end
221
+
222
+ describe 'preview' do
223
+ it 'should render preview' do
224
+ renderer.preview.must_equal 'echo $VARIABLE_INPUT[client_key] > /etc/chef/client.pem'
225
+ end
226
+ end
227
+
228
+
229
+ context 'with existing variable implemented as host parameter' do
230
+ let(:parameter) { FactoryGirl.create(:host_parameter, :host => renderer.host, :name => 'client_key', :value => 'RSA KEY') }
231
+
232
+ describe 'rendering' do
233
+ it 'renders the value from host parameter' do
234
+ parameter
235
+ renderer.host.reload
236
+ result.must_equal 'echo RSA KEY > /etc/chef/client.pem'
237
+ end
238
+ end
239
+
240
+ describe 'preview' do
241
+ it 'should render preview' do
242
+ parameter
243
+ renderer.host.reload
244
+ renderer.preview.must_equal 'echo RSA KEY > /etc/chef/client.pem'
245
+ end
246
+ end
247
+ end
248
+
249
+ context 'with existing variable implemented as smart variable' do
250
+ let(:puppet_class) { FactoryGirl.create(:puppetclass, :environments => [environment], :hosts => [renderer.host]) }
251
+ let(:lookup_key) do
252
+ FactoryGirl.create(:lookup_key,
253
+ :key => 'client_key',
254
+ :puppetclass => puppet_class,
255
+ :overrides => {"fqdn=#{renderer.host.fqdn}" => "RSA KEY"})
256
+ end
257
+
258
+ describe 'rendering' do
259
+ it 'renders the value from host parameter' do
260
+ lookup_key
261
+ result.must_equal 'echo RSA KEY > /etc/chef/client.pem'
262
+ end
263
+ end
264
+
265
+ describe 'preview' do
266
+ it 'should render preview' do
267
+ lookup_key
268
+ renderer.preview.must_equal 'echo RSA KEY > /etc/chef/client.pem'
269
+ end
270
+ end
271
+ end
272
+ end
273
+
274
+ describe 'preview' do
275
+ it 'should render preview' do
276
+ renderer.preview.must_equal 'echo $VARIABLE_INPUT[client_key] > /etc/chef/client.pem'
277
+ end
278
+ end
279
+ end
280
+ end
281
+ end
282
+
283
+ context "renderer for template with puppet parameter input used" do
284
+ let(:template) { FactoryGirl.build(:job_template, :template => 'echo "This is WebServer with nginx <%= input("nginx_version") -%>" > /etc/motd') }
285
+ let(:renderer) { InputTemplateRenderer.new(template) }
286
+
287
+ context 'with matching input defined' do
288
+ before do
289
+ renderer.template.template_inputs<< FactoryGirl.build(:template_input,
290
+ :name => 'nginx_version',
291
+ :input_type => 'puppet_parameter',
292
+ :puppet_parameter_name => 'version',
293
+ :puppet_class_name => 'nginx')
294
+ end
295
+ let(:result) { renderer.render }
296
+
297
+ describe 'rendering' do
298
+ it 'can\'t render the content without host since we don\'t have host so no classification' do
299
+ refute result
300
+ end
301
+
302
+ it 'registers an error' do
303
+ result # let is lazy
304
+ renderer.error_message.wont_be_nil
305
+ renderer.error_message.wont_be_empty
306
+ end
307
+
308
+ context 'with host specified' do
309
+ let(:environment) { FactoryGirl.create(:environment) }
310
+ before { renderer.host = FactoryGirl.create(:host, :environment => environment) }
311
+
312
+ describe 'rendering' do
313
+ it 'can\'t render the content without host since we don\'t have puppet parameter in classification' do
314
+ refute result
315
+ end
316
+
317
+ it 'registers an error' do
318
+ result # let is lazy
319
+ renderer.error_message.wont_be_nil
320
+ renderer.error_message.wont_be_empty
321
+ end
322
+ end
323
+
324
+ describe 'preview' do
325
+ it 'should render preview' do
326
+ renderer.preview.must_equal 'echo "This is WebServer with nginx $PUPPET_PARAMETER_INPUT[nginx_version]" > /etc/motd'
327
+ end
328
+ end
329
+
330
+ context 'with existing puppet parameter with matching override' do
331
+ let(:puppet_class) do
332
+ FactoryGirl.create(:puppetclass, :environments => [environment], :hosts => [renderer.host], :name => 'nginx')
333
+ end
334
+ let(:lookup_key) do
335
+ FactoryGirl.create(:lookup_key, :as_smart_class_param, :with_override,
336
+ :key => 'version',
337
+ :puppetclass => puppet_class,
338
+ :path => 'fqdn',
339
+ :overrides => {"fqdn=#{renderer.host.fqdn}" => "1.4.7"})
340
+ end
341
+
342
+ describe 'rendering' do
343
+ it 'renders the value from puppet parameter' do
344
+ lookup_key
345
+ result.must_equal 'echo "This is WebServer with nginx 1.4.7" > /etc/motd'
346
+ end
347
+ end
348
+
349
+ describe 'preview' do
350
+ it 'should render preview' do
351
+ lookup_key
352
+ renderer.preview.must_equal 'echo "This is WebServer with nginx 1.4.7" > /etc/motd'
353
+ end
354
+ end
355
+ end
356
+ end
357
+
358
+ describe 'preview' do
359
+ it 'should render preview' do
360
+ renderer.preview.must_equal 'echo "This is WebServer with nginx $PUPPET_PARAMETER_INPUT[nginx_version]" > /etc/motd'
361
+ end
362
+ end
363
+ end
364
+ end
365
+ end
366
+ end