foreman_remote_execution 0.1.1 → 0.1.2
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/app/assets/javascripts/template_invocation.js +48 -5
- data/app/controllers/api/v2/job_invocations_controller.rb +55 -10
- data/app/controllers/api/v2/job_templates_controller.rb +19 -4
- data/app/controllers/api/v2/template_inputs_controller.rb +88 -0
- data/app/controllers/job_invocations_controller.rb +17 -15
- data/app/controllers/template_invocations_controller.rb +2 -0
- data/app/helpers/remote_execution_helper.rb +27 -16
- data/app/lib/actions/middleware/bind_job_invocation.rb +7 -3
- data/app/lib/actions/remote_execution/run_host_job.rb +28 -17
- data/app/lib/actions/remote_execution/run_hosts_job.rb +9 -6
- data/app/models/concerns/foreman_remote_execution/foreman_tasks_task_extensions.rb +1 -1
- data/app/models/concerns/foreman_remote_execution/foreman_tasks_triggering_extensions.rb +9 -0
- data/app/models/concerns/foreman_remote_execution/host_extensions.rb +3 -1
- data/app/models/job_invocation.rb +48 -41
- data/app/models/job_invocation_composer.rb +205 -80
- data/app/models/job_invocation_task_group.rb +18 -0
- data/app/models/job_template.rb +25 -1
- data/app/models/job_template_effective_user.rb +23 -0
- data/app/models/remote_execution_provider.rb +25 -11
- data/app/models/setting/remote_execution.rb +6 -0
- data/app/models/ssh_execution_provider.rb +37 -0
- data/app/models/targeting.rb +13 -0
- data/app/models/template_input.rb +4 -1
- data/app/models/template_invocation.rb +23 -0
- data/app/views/api/v2/job_invocations/base.json.rabl +4 -0
- data/app/views/api/v2/job_invocations/index.json.rabl +1 -1
- data/app/views/api/v2/job_invocations/main.json.rabl +19 -0
- data/app/views/api/v2/job_invocations/show.json.rabl +0 -15
- data/app/views/api/v2/job_templates/base.json.rabl +1 -1
- data/app/views/api/v2/job_templates/index.json.rabl +1 -1
- data/app/views/api/v2/job_templates/main.json.rabl +5 -1
- data/app/views/api/v2/job_templates/show.json.rabl +4 -0
- data/app/views/api/v2/job_templates/update.json.rabl +3 -0
- data/app/views/api/v2/template_inputs/base.json.rabl +3 -0
- data/app/views/api/v2/template_inputs/create.json.rabl +3 -0
- data/app/views/api/v2/template_inputs/index.json.rabl +3 -0
- data/app/views/api/v2/template_inputs/main.json.rabl +9 -0
- data/app/views/api/v2/template_inputs/show.json.rabl +3 -0
- data/app/views/job_invocation_task_groups/_job_invocation_task_group.html.erb +31 -0
- data/app/views/job_invocation_task_groups/_job_invocation_task_groups.html.erb +3 -0
- data/app/views/job_invocations/_form.html.erb +102 -71
- data/app/views/job_invocations/_tab_overview.html.erb +5 -2
- data/app/views/job_invocations/index.html.erb +4 -4
- data/app/views/job_invocations/refresh.js.erb +2 -1
- data/app/views/job_invocations/show.html.erb +13 -2
- data/app/views/job_invocations/show.js.erb +1 -1
- data/app/views/job_templates/_custom_tabs.html.erb +16 -0
- data/app/views/templates/package_action.erb +1 -0
- data/app/views/templates/puppet_run_once.erb +1 -0
- data/app/views/templates/run_command.erb +1 -0
- data/app/views/templates/service_action.erb +1 -0
- data/config/routes.rb +15 -2
- data/db/migrate/20150923125825_add_job_invocation_task_group.rb +10 -0
- data/db/migrate/20151022105508_rename_last_task_id_column.rb +6 -0
- data/db/migrate/20151116105412_add_triggering_to_job_invocation.rb +10 -0
- data/db/migrate/20151120171100_add_effective_user_to_template_invocation.rb +5 -0
- data/db/migrate/20151124162300_create_job_template_effective_users.rb +13 -0
- data/db/migrate/20151203100824_add_description_to_job_invocation.rb +11 -0
- data/db/migrate/20151215114631_add_host_id_to_template_invocation.rb +29 -0
- data/db/migrate/20151217092555_migrate_to_task_groups.rb +16 -0
- data/foreman_remote_execution.gemspec +2 -1
- data/lib/foreman_remote_execution/engine.rb +30 -5
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/test/factories/foreman_remote_execution_factories.rb +5 -0
- data/test/functional/api/v2/job_invocations_controller_test.rb +3 -3
- data/test/functional/api/v2/template_inputs_controller_test.rb +61 -0
- data/test/unit/actions/run_hosts_job_test.rb +10 -3
- data/test/unit/concerns/host_extensions_test.rb +10 -6
- data/test/unit/job_invocation_composer_test.rb +229 -10
- data/test/unit/job_invocation_test.rb +27 -27
- data/test/unit/job_template_effective_user_test.rb +41 -0
- data/test/unit/job_template_test.rb +24 -0
- data/test/unit/remote_execution_provider_test.rb +39 -0
- metadata +42 -7
- data/app/models/job_invocation_api_composer.rb +0 -69
- data/test/unit/job_invocation_api_composer_test.rb +0 -143
|
@@ -27,8 +27,10 @@ describe JobInvocationComposer do
|
|
|
27
27
|
let(:unauthorized_job_template_1) { FactoryGirl.create(:job_template, :job_name => 'testing_job_template_1', :name => 'unauth1', :provider_type => 'Ssh') }
|
|
28
28
|
let(:unauthorized_job_template_2) { FactoryGirl.create(:job_template, :job_name => 'unauthorized_job_template_2', :name => 'unauth2', :provider_type => 'Ansible') }
|
|
29
29
|
|
|
30
|
+
|
|
30
31
|
let(:input1) { FactoryGirl.create(:template_input, :template => testing_job_template_1, :input_type => 'user') }
|
|
31
32
|
let(:input2) { FactoryGirl.create(:template_input, :template => testing_job_template_3, :input_type => 'user') }
|
|
33
|
+
let(:input3) { FactoryGirl.create(:template_input, :template => testing_job_template_1, :input_type => 'user', :required => true) }
|
|
32
34
|
let(:unauthorized_input1) { FactoryGirl.create(:template_input, :template => unauthorized_job_template_1, :input_type => 'user') }
|
|
33
35
|
|
|
34
36
|
let(:ansible_params) { { } }
|
|
@@ -38,8 +40,7 @@ describe JobInvocationComposer do
|
|
|
38
40
|
|
|
39
41
|
context 'with general new invocation and empty params' do
|
|
40
42
|
let(:params) { {} }
|
|
41
|
-
let(:
|
|
42
|
-
let(:composer) { JobInvocationComposer.new(job_invocation).compose_from_params(params) }
|
|
43
|
+
let(:composer) { JobInvocationComposer.from_ui_params(params) }
|
|
43
44
|
|
|
44
45
|
describe '#available_templates' do
|
|
45
46
|
it 'obeys authorization' do
|
|
@@ -108,7 +109,9 @@ describe JobInvocationComposer do
|
|
|
108
109
|
end
|
|
109
110
|
|
|
110
111
|
it 'returns only authorized inputs based on templates' do
|
|
111
|
-
composer.available_template_inputs.
|
|
112
|
+
composer.available_template_inputs.must_include(input1)
|
|
113
|
+
composer.available_template_inputs.must_include(input2)
|
|
114
|
+
composer.available_template_inputs.wont_include(unauthorized_input1)
|
|
112
115
|
end
|
|
113
116
|
|
|
114
117
|
context 'params contains job template ids' do
|
|
@@ -246,6 +249,54 @@ describe JobInvocationComposer do
|
|
|
246
249
|
end
|
|
247
250
|
end
|
|
248
251
|
|
|
252
|
+
describe '#effective_user' do
|
|
253
|
+
let(:ssh_params) do
|
|
254
|
+
{ :job_template_id => testing_job_template_1.id.to_s,
|
|
255
|
+
:job_templates => {
|
|
256
|
+
testing_job_template_1.id.to_s => {
|
|
257
|
+
:effective_user => invocation_effective_user
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
end
|
|
262
|
+
let(:params) { { :job_invocation => { :providers => { :ssh => ssh_params } } }.with_indifferent_access }
|
|
263
|
+
let(:template_invocation) do
|
|
264
|
+
testing_job_template_1.effective_user.update_attributes(:overridable => overridable, :value => 'template user')
|
|
265
|
+
composer.template_invocations.first
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
before do
|
|
269
|
+
Setting::RemoteExecution.load_defaults
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
context 'when overridable and provided' do
|
|
273
|
+
let(:overridable) { true }
|
|
274
|
+
let(:invocation_effective_user) { 'invocation user' }
|
|
275
|
+
|
|
276
|
+
it 'takes the value from the template invocation' do
|
|
277
|
+
template_invocation.effective_user.must_equal 'invocation user'
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
context 'when overridable and not provided' do
|
|
282
|
+
let(:overridable) { true }
|
|
283
|
+
let(:invocation_effective_user) { "" }
|
|
284
|
+
|
|
285
|
+
it 'takes the value from the job template' do
|
|
286
|
+
template_invocation.effective_user.must_equal 'template user'
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
context 'when not overridable and provided' do
|
|
291
|
+
let(:overridable) { false }
|
|
292
|
+
let(:invocation_effective_user) { "invocation user" }
|
|
293
|
+
|
|
294
|
+
it 'takes the value from the job template' do
|
|
295
|
+
template_invocation.effective_user.must_equal 'template user'
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
249
300
|
describe '#displayed_search_query' do
|
|
250
301
|
it 'is empty by default' do
|
|
251
302
|
composer.displayed_search_query.must_be_empty
|
|
@@ -395,23 +446,33 @@ describe JobInvocationComposer do
|
|
|
395
446
|
|
|
396
447
|
it 'validates all associated objects even if some of the is invalid' do
|
|
397
448
|
composer
|
|
398
|
-
job_invocation.expects(:valid?).returns(false)
|
|
449
|
+
composer.job_invocation.expects(:valid?).returns(false)
|
|
399
450
|
composer.targeting.expects(:valid?).returns(false)
|
|
400
451
|
composer.template_invocations.each { |invocation| invocation.expects(:valid?).returns(false) }
|
|
401
452
|
refute composer.valid?
|
|
402
453
|
end
|
|
403
454
|
end
|
|
404
455
|
|
|
456
|
+
describe 'triggering' do
|
|
457
|
+
let(:params) do
|
|
458
|
+
{ :job_invocation => { :providers => { :ssh => ssh_params } }, :triggering => { :mode => 'future' }}.with_indifferent_access
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
it 'accepts the triggering params' do
|
|
462
|
+
composer.job_invocation.triggering.mode.must_equal :future
|
|
463
|
+
end
|
|
464
|
+
end
|
|
465
|
+
|
|
405
466
|
describe '#save' do
|
|
406
467
|
it 'triggers save on job_invocation if it is valid' do
|
|
407
468
|
composer.stubs(:valid? => true)
|
|
408
|
-
job_invocation.expects(:save)
|
|
469
|
+
composer.job_invocation.expects(:save)
|
|
409
470
|
composer.save
|
|
410
471
|
end
|
|
411
472
|
|
|
412
473
|
it 'does not trigger save on job_invocation if it is invalid' do
|
|
413
474
|
composer.stubs(:valid? => false)
|
|
414
|
-
job_invocation.expects(:save).never
|
|
475
|
+
composer.job_invocation.expects(:save).never
|
|
415
476
|
composer.save
|
|
416
477
|
end
|
|
417
478
|
end
|
|
@@ -419,7 +480,7 @@ describe JobInvocationComposer do
|
|
|
419
480
|
describe '#job_name' do
|
|
420
481
|
it 'triggers job_name on job_invocation' do
|
|
421
482
|
composer
|
|
422
|
-
job_invocation.expects(:job_name)
|
|
483
|
+
composer.job_invocation.expects(:job_name)
|
|
423
484
|
composer.job_name
|
|
424
485
|
end
|
|
425
486
|
end
|
|
@@ -427,7 +488,7 @@ describe JobInvocationComposer do
|
|
|
427
488
|
describe '#targeting' do
|
|
428
489
|
it 'triggers targeting on job_invocation' do
|
|
429
490
|
composer
|
|
430
|
-
job_invocation.expects(:targeting)
|
|
491
|
+
composer.job_invocation.expects(:targeting)
|
|
431
492
|
composer.targeting
|
|
432
493
|
end
|
|
433
494
|
end
|
|
@@ -452,9 +513,9 @@ describe JobInvocationComposer do
|
|
|
452
513
|
}
|
|
453
514
|
}.with_indifferent_access
|
|
454
515
|
end
|
|
455
|
-
let(:existing) { job_invocation.reload }
|
|
516
|
+
let(:existing) { composer.job_invocation.reload }
|
|
456
517
|
let(:new_job_invocation) { JobInvocation.new }
|
|
457
|
-
let(:new_composer) { JobInvocationComposer.
|
|
518
|
+
let(:new_composer) { JobInvocationComposer.from_job_invocation(composer.job_invocation) }
|
|
458
519
|
|
|
459
520
|
before do
|
|
460
521
|
composer.save
|
|
@@ -480,4 +541,162 @@ describe JobInvocationComposer do
|
|
|
480
541
|
end
|
|
481
542
|
end
|
|
482
543
|
end
|
|
544
|
+
|
|
545
|
+
describe '#from_api_params' do
|
|
546
|
+
let(:composer) { JobInvocationComposer.from_api_params(params) }
|
|
547
|
+
let(:bookmark) { bookmarks(:one) }
|
|
548
|
+
|
|
549
|
+
context 'with targeting from bookmark' do
|
|
550
|
+
|
|
551
|
+
before do
|
|
552
|
+
[testing_job_template_1, testing_job_template_3] # mentioning templates we want to have initialized in the test
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
let(:params) do
|
|
556
|
+
{ :job_name => testing_job_template_1.job_name,
|
|
557
|
+
:job_template_id => testing_job_template_1.id,
|
|
558
|
+
:targeting_type => "static_query",
|
|
559
|
+
:bookmark_id => bookmark.id }
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
it "creates invocation with a bookmark" do
|
|
563
|
+
assert composer.save!
|
|
564
|
+
assert_equal bookmark, composer.job_invocation.targeting.bookmark
|
|
565
|
+
assert_equal composer.job_invocation.targeting.user, User.current
|
|
566
|
+
refute_empty composer.job_invocation.template_invocations
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
context "with targeting from search query" do
|
|
571
|
+
let(:params) do
|
|
572
|
+
{ :job_name => testing_job_template_1.job_name,
|
|
573
|
+
:job_template_id => testing_job_template_1.id,
|
|
574
|
+
:targeting_type => "static_query",
|
|
575
|
+
:search_query => "some hosts" }
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
it "creates invocation with a search query" do
|
|
579
|
+
assert composer.save!
|
|
580
|
+
assert_equal "some hosts", composer.job_invocation.targeting.search_query
|
|
581
|
+
refute_empty composer.job_invocation.template_invocations
|
|
582
|
+
end
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
context "with with inputs" do
|
|
586
|
+
let(:params) do
|
|
587
|
+
{ :job_name => testing_job_template_1.job_name,
|
|
588
|
+
:job_template_id => testing_job_template_1.id,
|
|
589
|
+
:targeting_type => "static_query",
|
|
590
|
+
:search_query => "some hosts",
|
|
591
|
+
:inputs => {input1.name => "some_value"}}
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
it "finds the inputs by name" do
|
|
595
|
+
assert composer.save!
|
|
596
|
+
assert_equal 1, composer.template_invocations.first.input_values.count
|
|
597
|
+
end
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
context "with effective user" do
|
|
601
|
+
let(:params) do
|
|
602
|
+
{ :job_name => testing_job_template_1.job_name,
|
|
603
|
+
:job_template_id => testing_job_template_1.id,
|
|
604
|
+
:effective_user => 'invocation user',
|
|
605
|
+
:targeting_type => "static_query",
|
|
606
|
+
:search_query => "some hosts",
|
|
607
|
+
:inputs => {input1.name => "some_value"}}
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
let(:template_invocation) { composer.job_invocation.template_invocations.first }
|
|
611
|
+
|
|
612
|
+
it "sets the effective user based on the input" do
|
|
613
|
+
assert composer.save!
|
|
614
|
+
template_invocation.effective_user.must_equal 'invocation user'
|
|
615
|
+
end
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
context "with invalid targeting" do
|
|
619
|
+
let(:params) do
|
|
620
|
+
{ :job_name => testing_job_template_1.job_name,
|
|
621
|
+
:job_template_id => testing_job_template_1.id,
|
|
622
|
+
:search_query => "some hosts",
|
|
623
|
+
:inputs => {input1.name => "some_value"}}
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
it "handles errors" do
|
|
627
|
+
assert_raises(ActiveRecord::RecordNotSaved) do
|
|
628
|
+
composer.save!
|
|
629
|
+
end
|
|
630
|
+
end
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
context "with invalid bookmark and search query" do
|
|
634
|
+
let(:params) do
|
|
635
|
+
{ :job_name => testing_job_template_1.job_name,
|
|
636
|
+
:job_template_id => testing_job_template_1.id,
|
|
637
|
+
:targeting_type => "static_query",
|
|
638
|
+
:search_query => "some hosts",
|
|
639
|
+
:bookmark_id => bookmark.id,
|
|
640
|
+
:inputs => {input1.name => "some_value"}}
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
it "handles errors" do
|
|
644
|
+
assert_raises(Foreman::Exception) do
|
|
645
|
+
JobInvocationComposer.from_api_params(params)
|
|
646
|
+
end
|
|
647
|
+
end
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
context "with invalid inputs" do
|
|
651
|
+
let(:params) do
|
|
652
|
+
{ :job_name => testing_job_template_1.job_name,
|
|
653
|
+
:job_template_id => testing_job_template_1.id,
|
|
654
|
+
:targeting_type => "static_query",
|
|
655
|
+
:search_query => "some hosts",
|
|
656
|
+
:inputs => {input3.name => nil}}
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
it "handles errors" do
|
|
660
|
+
error = assert_raises(ActiveRecord::RecordNotSaved) do
|
|
661
|
+
composer.save!
|
|
662
|
+
end
|
|
663
|
+
error.message.must_include "Template #{testing_job_template_1.name}: Input #{input3.name.downcase}: Value can't be blank"
|
|
664
|
+
end
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
context "with empty values for non-required inputs" do
|
|
668
|
+
let(:params) do
|
|
669
|
+
{ :job_name => testing_job_template_1.job_name,
|
|
670
|
+
:job_template_id => testing_job_template_1.id,
|
|
671
|
+
:targeting_type => "static_query",
|
|
672
|
+
:search_query => "some hosts",
|
|
673
|
+
:inputs => {input3.name => "some value"}}
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
it "accepts the params" do
|
|
677
|
+
composer.save!
|
|
678
|
+
refute composer.job_invocation.new_record?
|
|
679
|
+
end
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
context "with missing required inputs" do
|
|
683
|
+
let(:params) do
|
|
684
|
+
{ :job_name => testing_job_template_1.job_name,
|
|
685
|
+
:job_template_id => testing_job_template_1.id,
|
|
686
|
+
:targeting_type => "static_query",
|
|
687
|
+
:search_query => "some hosts",
|
|
688
|
+
:inputs => {input1.name => "some_value"}}
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
it "handles errors" do
|
|
692
|
+
input3.must_be :required
|
|
693
|
+
|
|
694
|
+
error = assert_raises(ActiveRecord::RecordNotSaved) do
|
|
695
|
+
composer.save!
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
error.message.must_include "Template #{testing_job_template_1.name}: Not all required inputs have values. Missing inputs: #{input3.name}"
|
|
699
|
+
end
|
|
700
|
+
end
|
|
701
|
+
end
|
|
483
702
|
end
|
|
@@ -5,6 +5,17 @@ describe JobInvocation do
|
|
|
5
5
|
let(:job_invocation) { FactoryGirl.build(:job_invocation) }
|
|
6
6
|
let(:template) { FactoryGirl.create(:job_template, :with_input) }
|
|
7
7
|
|
|
8
|
+
context 'Search for job invocations' do
|
|
9
|
+
before do
|
|
10
|
+
job_invocation.save
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'is able to perform search through job invocations' do
|
|
14
|
+
found_jobs = JobInvocation.search_for(%{job_name = "#{job_invocation.job_name}"}).paginate(:page => 1).with_task.order('job_invocations.id DESC')
|
|
15
|
+
found_jobs.must_equal [job_invocation]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
8
19
|
context 'Able to be created' do
|
|
9
20
|
it { assert job_invocation.save }
|
|
10
21
|
end
|
|
@@ -35,6 +46,22 @@ describe JobInvocation do
|
|
|
35
46
|
@input_value.destroy
|
|
36
47
|
refute job_invocation.reload.valid?
|
|
37
48
|
end
|
|
49
|
+
|
|
50
|
+
describe 'descriptions' do
|
|
51
|
+
it 'generates description from input values' do
|
|
52
|
+
job_invocation.expects(:save!)
|
|
53
|
+
job_invocation.description_format = '%{job_name} - %{foo}'
|
|
54
|
+
job_invocation.generate_description!
|
|
55
|
+
job_invocation.description.must_equal "#{job_invocation.job_name} - #{@input_value.value}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'handles missing keys correctly' do
|
|
59
|
+
job_invocation.expects(:save!)
|
|
60
|
+
job_invocation.description_format = '%{job_name} - %{missing_key}'
|
|
61
|
+
job_invocation.generate_description!
|
|
62
|
+
job_invocation.description.must_equal "#{job_invocation.job_name} - %{missing_key}"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
38
65
|
end
|
|
39
66
|
|
|
40
67
|
context 'future execution' do
|
|
@@ -45,32 +72,5 @@ describe JobInvocation do
|
|
|
45
72
|
job_invocation.total_hosts_count.must_equal 0
|
|
46
73
|
end
|
|
47
74
|
|
|
48
|
-
it 'has default trigger mode' do
|
|
49
|
-
job_invocation.trigger_mode.must_equal :immediate
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
it 'cannot set trigger mode to anything other than :immediate or :future' do
|
|
53
|
-
proc { job_invocation.trigger_mode = 'test' }.must_raise ::Foreman::Exception
|
|
54
|
-
job_invocation.trigger_mode.must_equal :immediate
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
it 'cannot change trigger mode once set' do
|
|
58
|
-
job_invocation.trigger_mode = 'future'
|
|
59
|
-
job_invocation.trigger_mode = 'immediate'
|
|
60
|
-
job_invocation.trigger_mode.must_equal :future
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
it 'parses times' do
|
|
64
|
-
time = Time.new(2015, 9, 16, 13, 56)
|
|
65
|
-
time_string = time.strftime(job_invocation.time_format)
|
|
66
|
-
job_invocation.start_at_parsed.must_equal false
|
|
67
|
-
job_invocation.start_at = time_string
|
|
68
|
-
job_invocation.start_at_parsed.must_equal time
|
|
69
|
-
job_invocation.start_before.must_be_nil
|
|
70
|
-
job_invocation.start_before_parsed.must_be_nil
|
|
71
|
-
job_invocation.start_before = time_string
|
|
72
|
-
job_invocation.start_before_parsed.must_equal time
|
|
73
|
-
end
|
|
74
|
-
|
|
75
75
|
end
|
|
76
76
|
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'test_plugin_helper'
|
|
2
|
+
|
|
3
|
+
describe JobTemplateEffectiveUser do
|
|
4
|
+
let(:job_template) { FactoryGirl.build(:job_template, :job_name => '') }
|
|
5
|
+
let(:effective_user) { job_template.effective_user }
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
Setting::RemoteExecution.load_defaults
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe 'by default' do
|
|
12
|
+
it 'is overridable' do
|
|
13
|
+
assert effective_user.overridable?
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it 'does not use the current user' do
|
|
17
|
+
refute effective_user.current_user?
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe 'compute value' do
|
|
22
|
+
it 'computes the value based on the current user when current_user set to true' do
|
|
23
|
+
user = FactoryGirl.create(:user)
|
|
24
|
+
User.current = user
|
|
25
|
+
effective_user.current_user = true
|
|
26
|
+
effective_user.compute_value.must_equal user.login
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'returns the value when not current user is set to true' do
|
|
30
|
+
effective_user.current_user = false
|
|
31
|
+
effective_user.value = 'testuser'
|
|
32
|
+
effective_user.compute_value.must_equal 'testuser'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'returns a default value when no value is specified for the user' do
|
|
36
|
+
effective_user.value = ""
|
|
37
|
+
Setting[:remote_execution_effective_user] = 'myuser'
|
|
38
|
+
effective_user.compute_value.must_equal 'myuser'
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -14,6 +14,30 @@ describe JobTemplate do
|
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
context 'description format' do
|
|
18
|
+
let(:template_with_description) { FactoryGirl.build(:job_template, :with_description_format, :job_name => 'test job') }
|
|
19
|
+
let(:template) { FactoryGirl.build(:job_template, :with_input, :job_name => 'test job') }
|
|
20
|
+
let(:minimal_template) { FactoryGirl.build(:job_template) }
|
|
21
|
+
|
|
22
|
+
it 'uses the description_format attribute if set' do
|
|
23
|
+
template_with_description.generate_description_format.must_equal template_with_description.description_format
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'uses the job name as description_format if not set or blank and has no inputs' do
|
|
27
|
+
minimal_template.generate_description_format.must_equal '%{job_name}'
|
|
28
|
+
minimal_template.description_format = ''
|
|
29
|
+
minimal_template.generate_description_format.must_equal '%{job_name}'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'generates the description_format if not set or blank and has inputs' do
|
|
33
|
+
input_name = template.template_inputs.first.name
|
|
34
|
+
expected_result = %Q(%{job_name} with inputs #{input_name}="%{#{input_name}}")
|
|
35
|
+
template.generate_description_format.must_equal expected_result
|
|
36
|
+
template.description_format = ''
|
|
37
|
+
template.generate_description_format.must_equal expected_result
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
17
41
|
context 'cloning' do
|
|
18
42
|
let(:job_template) { FactoryGirl.build(:job_template, :with_input) }
|
|
19
43
|
|
|
@@ -48,4 +48,43 @@ describe RemoteExecutionProvider do
|
|
|
48
48
|
it { provider_names.must_include 'Custom' }
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
|
+
|
|
52
|
+
describe SSHExecutionProvider do
|
|
53
|
+
before do
|
|
54
|
+
Setting::RemoteExecution.load_defaults
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
let(:job_invocation) { FactoryGirl.create(:job_invocation, :with_template) }
|
|
58
|
+
let(:template_invocation) { job_invocation.template_invocations.first }
|
|
59
|
+
let(:host) { FactoryGirl.create(:host) }
|
|
60
|
+
let(:proxy_options) { SSHExecutionProvider.proxy_command_options(template_invocation, host) }
|
|
61
|
+
|
|
62
|
+
describe 'effective user' do
|
|
63
|
+
it 'takes the effective user from value from the template invocation' do
|
|
64
|
+
template_invocation.effective_user = 'my user'
|
|
65
|
+
proxy_options[:effective_user].must_equal 'my user'
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe 'ssh user' do
|
|
70
|
+
it 'uses the remote_execution_ssh_user on the host param' do
|
|
71
|
+
host.params['remote_execution_ssh_user'] = 'my user'
|
|
72
|
+
host.host_parameters << FactoryGirl.build(:host_parameter, :name => 'remote_execution_ssh_user', :value => 'my user')
|
|
73
|
+
proxy_options[:ssh_user].must_equal 'my user'
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
describe 'sudo' do
|
|
78
|
+
it 'uses the remote_execution_ssh_user on the host param' do
|
|
79
|
+
host.params['remote_execution_effective_user_method'] = 'sudo'
|
|
80
|
+
method_param = FactoryGirl.build(:host_parameter, :name => 'remote_execution_effective_user_method', :value => 'sudo')
|
|
81
|
+
host.host_parameters << method_param
|
|
82
|
+
proxy_options[:effective_user_method].must_equal 'sudo'
|
|
83
|
+
method_param.update_attributes!(:value => 'su')
|
|
84
|
+
host.clear_host_parameters_cache!
|
|
85
|
+
proxy_options = SSHExecutionProvider.proxy_command_options(template_invocation, host)
|
|
86
|
+
proxy_options[:effective_user_method].must_equal 'su'
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
51
90
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: foreman_remote_execution
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Foreman Remote Execution team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-
|
|
11
|
+
date: 2015-12-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: deface
|
|
@@ -38,20 +38,34 @@ dependencies:
|
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: 3.2.8
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: dynflow
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 0.8.8
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 0.8.8
|
|
41
55
|
- !ruby/object:Gem::Dependency
|
|
42
56
|
name: foreman-tasks
|
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
|
44
58
|
requirements:
|
|
45
59
|
- - "~>"
|
|
46
60
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: 0.7.
|
|
61
|
+
version: 0.7.8
|
|
48
62
|
type: :runtime
|
|
49
63
|
prerelease: false
|
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
65
|
requirements:
|
|
52
66
|
- - "~>"
|
|
53
67
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: 0.7.
|
|
68
|
+
version: 0.7.8
|
|
55
69
|
- !ruby/object:Gem::Dependency
|
|
56
70
|
name: rubocop
|
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -142,6 +156,7 @@ files:
|
|
|
142
156
|
- app/assets/stylesheets/template_invocation.css.scss
|
|
143
157
|
- app/controllers/api/v2/job_invocations_controller.rb
|
|
144
158
|
- app/controllers/api/v2/job_templates_controller.rb
|
|
159
|
+
- app/controllers/api/v2/template_inputs_controller.rb
|
|
145
160
|
- app/controllers/job_invocations_controller.rb
|
|
146
161
|
- app/controllers/job_templates_controller.rb
|
|
147
162
|
- app/controllers/template_invocations_controller.rb
|
|
@@ -157,6 +172,7 @@ files:
|
|
|
157
172
|
- app/models/concerns/foreman_remote_execution/bookmark_extensions.rb
|
|
158
173
|
- app/models/concerns/foreman_remote_execution/errors_flattener.rb
|
|
159
174
|
- app/models/concerns/foreman_remote_execution/foreman_tasks_task_extensions.rb
|
|
175
|
+
- app/models/concerns/foreman_remote_execution/foreman_tasks_triggering_extensions.rb
|
|
160
176
|
- app/models/concerns/foreman_remote_execution/host_extensions.rb
|
|
161
177
|
- app/models/concerns/foreman_remote_execution/nic_extensions.rb
|
|
162
178
|
- app/models/concerns/foreman_remote_execution/smart_proxy_extensions.rb
|
|
@@ -168,9 +184,10 @@ files:
|
|
|
168
184
|
- app/models/host_status/execution_status.rb
|
|
169
185
|
- app/models/input_template_renderer.rb
|
|
170
186
|
- app/models/job_invocation.rb
|
|
171
|
-
- app/models/job_invocation_api_composer.rb
|
|
172
187
|
- app/models/job_invocation_composer.rb
|
|
188
|
+
- app/models/job_invocation_task_group.rb
|
|
173
189
|
- app/models/job_template.rb
|
|
190
|
+
- app/models/job_template_effective_user.rb
|
|
174
191
|
- app/models/remote_execution_provider.rb
|
|
175
192
|
- app/models/setting/remote_execution.rb
|
|
176
193
|
- app/models/ssh_execution_provider.rb
|
|
@@ -196,7 +213,15 @@ files:
|
|
|
196
213
|
- app/views/api/v2/job_templates/index.json.rabl
|
|
197
214
|
- app/views/api/v2/job_templates/main.json.rabl
|
|
198
215
|
- app/views/api/v2/job_templates/show.json.rabl
|
|
216
|
+
- app/views/api/v2/job_templates/update.json.rabl
|
|
217
|
+
- app/views/api/v2/template_inputs/base.json.rabl
|
|
218
|
+
- app/views/api/v2/template_inputs/create.json.rabl
|
|
219
|
+
- app/views/api/v2/template_inputs/index.json.rabl
|
|
220
|
+
- app/views/api/v2/template_inputs/main.json.rabl
|
|
221
|
+
- app/views/api/v2/template_inputs/show.json.rabl
|
|
199
222
|
- app/views/dashboard/.gitkeep
|
|
223
|
+
- app/views/job_invocation_task_groups/_job_invocation_task_group.html.erb
|
|
224
|
+
- app/views/job_invocation_task_groups/_job_invocation_task_groups.html.erb
|
|
200
225
|
- app/views/job_invocations/_form.html.erb
|
|
201
226
|
- app/views/job_invocations/_host_actions_td.html.erb
|
|
202
227
|
- app/views/job_invocations/_host_provider_td.html.erb
|
|
@@ -238,7 +263,15 @@ files:
|
|
|
238
263
|
- db/migrate/20150827144500_change_targeting_search_query_type.rb
|
|
239
264
|
- db/migrate/20150827152730_add_options_to_template_input.rb
|
|
240
265
|
- db/migrate/20150903192731_add_execution_to_interface.rb
|
|
266
|
+
- db/migrate/20150923125825_add_job_invocation_task_group.rb
|
|
241
267
|
- db/migrate/20151013135415_add_pub_key_to_smart_proxy.rb
|
|
268
|
+
- db/migrate/20151022105508_rename_last_task_id_column.rb
|
|
269
|
+
- db/migrate/20151116105412_add_triggering_to_job_invocation.rb
|
|
270
|
+
- db/migrate/20151120171100_add_effective_user_to_template_invocation.rb
|
|
271
|
+
- db/migrate/20151124162300_create_job_template_effective_users.rb
|
|
272
|
+
- db/migrate/20151203100824_add_description_to_job_invocation.rb
|
|
273
|
+
- db/migrate/20151215114631_add_host_id_to_template_invocation.rb
|
|
274
|
+
- db/migrate/20151217092555_migrate_to_task_groups.rb
|
|
242
275
|
- db/seeds.d/60-ssh_proxy_feature.rb
|
|
243
276
|
- db/seeds.d/70-job_templates.rb
|
|
244
277
|
- db/seeds.d/80-provision_templates.rb
|
|
@@ -291,15 +324,16 @@ files:
|
|
|
291
324
|
- test/factories/foreman_remote_execution_factories.rb
|
|
292
325
|
- test/functional/api/v2/job_invocations_controller_test.rb
|
|
293
326
|
- test/functional/api/v2/job_templates_controller_test.rb
|
|
327
|
+
- test/functional/api/v2/template_inputs_controller_test.rb
|
|
294
328
|
- test/test_plugin_helper.rb
|
|
295
329
|
- test/unit/actions/run_hosts_job_test.rb
|
|
296
330
|
- test/unit/actions/run_proxy_command_test.rb
|
|
297
331
|
- test/unit/concerns/host_extensions_test.rb
|
|
298
332
|
- test/unit/concerns/nic_extensions_test.rb
|
|
299
333
|
- test/unit/input_template_renderer_test.rb
|
|
300
|
-
- test/unit/job_invocation_api_composer_test.rb
|
|
301
334
|
- test/unit/job_invocation_composer_test.rb
|
|
302
335
|
- test/unit/job_invocation_test.rb
|
|
336
|
+
- test/unit/job_template_effective_user_test.rb
|
|
303
337
|
- test/unit/job_template_test.rb
|
|
304
338
|
- test/unit/proxy_load_balancer_test.rb
|
|
305
339
|
- test/unit/remote_execution_provider_test.rb
|
|
@@ -334,15 +368,16 @@ test_files:
|
|
|
334
368
|
- test/factories/foreman_remote_execution_factories.rb
|
|
335
369
|
- test/functional/api/v2/job_invocations_controller_test.rb
|
|
336
370
|
- test/functional/api/v2/job_templates_controller_test.rb
|
|
371
|
+
- test/functional/api/v2/template_inputs_controller_test.rb
|
|
337
372
|
- test/test_plugin_helper.rb
|
|
338
373
|
- test/unit/actions/run_hosts_job_test.rb
|
|
339
374
|
- test/unit/actions/run_proxy_command_test.rb
|
|
340
375
|
- test/unit/concerns/host_extensions_test.rb
|
|
341
376
|
- test/unit/concerns/nic_extensions_test.rb
|
|
342
377
|
- test/unit/input_template_renderer_test.rb
|
|
343
|
-
- test/unit/job_invocation_api_composer_test.rb
|
|
344
378
|
- test/unit/job_invocation_composer_test.rb
|
|
345
379
|
- test/unit/job_invocation_test.rb
|
|
380
|
+
- test/unit/job_template_effective_user_test.rb
|
|
346
381
|
- test/unit/job_template_test.rb
|
|
347
382
|
- test/unit/proxy_load_balancer_test.rb
|
|
348
383
|
- test/unit/remote_execution_provider_test.rb
|