foreman_deployments 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 (133) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE +619 -0
  3. data/README.md +52 -0
  4. data/Rakefile +30 -0
  5. data/app/controllers/foreman_deployments/api/v2/base_controller.rb +25 -0
  6. data/app/controllers/foreman_deployments/api/v2/deployments_controller.rb +102 -0
  7. data/app/controllers/foreman_deployments/api/v2/stacks_controller.rb +52 -0
  8. data/app/controllers/foreman_deployments/create_resources_controller.rb +62 -0
  9. data/app/controllers/foreman_deployments/deployments_controller.rb +5 -0
  10. data/app/controllers/foreman_deployments/stacks_controller.rb +5 -0
  11. data/app/lib/foreman_deployments/base_dereference_visitor.rb +55 -0
  12. data/app/lib/foreman_deployments/config.rb +16 -0
  13. data/app/lib/foreman_deployments/config/array.rb +91 -0
  14. data/app/lib/foreman_deployments/config/configurator.rb +23 -0
  15. data/app/lib/foreman_deployments/config/hash.rb +81 -0
  16. data/app/lib/foreman_deployments/config/load_visitor.rb +23 -0
  17. data/app/lib/foreman_deployments/config/merge_visitor.rb +23 -0
  18. data/app/lib/foreman_deployments/config/save_visitor.rb +23 -0
  19. data/app/lib/foreman_deployments/inputs/base_input_definition.rb +39 -0
  20. data/app/lib/foreman_deployments/inputs/value.rb +25 -0
  21. data/app/lib/foreman_deployments/planner_visitor.rb +26 -0
  22. data/app/lib/foreman_deployments/registry.rb +67 -0
  23. data/app/lib/foreman_deployments/stack_definition.rb +37 -0
  24. data/app/lib/foreman_deployments/stack_parser.rb +121 -0
  25. data/app/lib/foreman_deployments/task_reference.rb +48 -0
  26. data/app/lib/foreman_deployments/tasks/base_action.rb +6 -0
  27. data/app/lib/foreman_deployments/tasks/base_definition.rb +72 -0
  28. data/app/lib/foreman_deployments/tasks/creation_task_definition.rb +68 -0
  29. data/app/lib/foreman_deployments/tasks/host_creation_task_definition.rb +44 -0
  30. data/app/lib/foreman_deployments/tasks/search_task_definition.rb +55 -0
  31. data/app/lib/foreman_deployments/tasks/stack_deploy_action.rb +10 -0
  32. data/app/lib/foreman_deployments/tasks/wait_until_built_task_definition.rb +65 -0
  33. data/app/lib/foreman_deployments/validation/dereference_visitor.rb +18 -0
  34. data/app/lib/foreman_deployments/validation/remove_ids_visitor.rb +59 -0
  35. data/app/lib/foreman_deployments/validation/validation_error.rb +12 -0
  36. data/app/lib/foreman_deployments/validation/validation_result.rb +26 -0
  37. data/app/lib/foreman_deployments/validation/validation_visitor.rb +20 -0
  38. data/app/lib/foreman_deployments/validation/validator.rb +29 -0
  39. data/app/models/foreman_deployments/concerns/belongs_to_single_taxonomy.rb +42 -0
  40. data/app/models/foreman_deployments/concerns/belongs_to_stack_taxonomy.rb +24 -0
  41. data/app/models/foreman_deployments/configuration.rb +26 -0
  42. data/app/models/foreman_deployments/deployment.rb +57 -0
  43. data/app/models/foreman_deployments/resource_models/create_resource.rb +18 -0
  44. data/app/models/foreman_deployments/stack.rb +20 -0
  45. data/app/views/foreman_deployments/api/v2/deployments/base.json.rabl +3 -0
  46. data/app/views/foreman_deployments/api/v2/deployments/create.json.rabl +3 -0
  47. data/app/views/foreman_deployments/api/v2/deployments/index.json.rabl +3 -0
  48. data/app/views/foreman_deployments/api/v2/deployments/main.json.rabl +5 -0
  49. data/app/views/foreman_deployments/api/v2/deployments/merge_configuration.json.rabl +3 -0
  50. data/app/views/foreman_deployments/api/v2/deployments/replace_configuration.json.rabl +3 -0
  51. data/app/views/foreman_deployments/api/v2/deployments/run.json.rabl +3 -0
  52. data/app/views/foreman_deployments/api/v2/deployments/show.json.rabl +11 -0
  53. data/app/views/foreman_deployments/api/v2/deployments/update.json.rabl +3 -0
  54. data/app/views/foreman_deployments/api/v2/stacks/base.json.rabl +3 -0
  55. data/app/views/foreman_deployments/api/v2/stacks/create.json.rabl +3 -0
  56. data/app/views/foreman_deployments/api/v2/stacks/index.json.rabl +3 -0
  57. data/app/views/foreman_deployments/api/v2/stacks/main.json.rabl +3 -0
  58. data/app/views/foreman_deployments/api/v2/stacks/show.json.rabl +7 -0
  59. data/app/views/foreman_deployments/api/v2/stacks/update.json.rabl +3 -0
  60. data/app/views/foreman_deployments/create_resources/new.html.erb +6 -0
  61. data/config/routes.rb +41 -0
  62. data/db/migrate/20150623140612_create_stacks.rb +10 -0
  63. data/db/migrate/20150814092932_create_deployment.rb +20 -0
  64. data/db/migrate/20150916133305_add_task_to_deployments.rb +5 -0
  65. data/db/migrate/20150917130618_add_taxonomy_to_deployments.rb +8 -0
  66. data/db/seeds.d/03-permissions.rb +14 -0
  67. data/doc/deployment_process.md +112 -0
  68. data/doc/design/capsule_stack.puml +51 -0
  69. data/doc/design/complete_stack.puml +17 -0
  70. data/doc/design/config_resource_overview.puml +15 -0
  71. data/doc/design/design.md +230 -0
  72. data/doc/design/diagrams/capsule_stack.png +0 -0
  73. data/doc/design/diagrams/capsule_stack.svg +1 -0
  74. data/doc/design/diagrams/complete_stack.png +0 -0
  75. data/doc/design/diagrams/complete_stack.svg +1 -0
  76. data/doc/design/diagrams/config_resource_overview.png +0 -0
  77. data/doc/design/diagrams/config_resource_overview.svg +1 -0
  78. data/doc/design/diagrams/ordered_resource_overview.png +0 -0
  79. data/doc/design/diagrams/ordered_resource_overview.svg +1 -0
  80. data/doc/design/diagrams/overview.png +0 -0
  81. data/doc/design/diagrams/overview.svg +1 -0
  82. data/doc/design/diagrams/overview_class.png +0 -0
  83. data/doc/design/diagrams/overview_class.svg +1 -0
  84. data/doc/design/diagrams/sat_stack.png +0 -0
  85. data/doc/design/diagrams/sat_stack.svg +1 -0
  86. data/doc/design/diagrams/solr_usecase.png +0 -0
  87. data/doc/design/diagrams/solr_usecase.svg +1 -0
  88. data/doc/design/examples.md +192 -0
  89. data/doc/design/generate-diagrams.sh +7 -0
  90. data/doc/design/implementation.md +128 -0
  91. data/doc/design/ordered_resource_overview.puml +15 -0
  92. data/doc/design/overview.puml +42 -0
  93. data/doc/design/overview_class.puml +64 -0
  94. data/doc/design/resources.md +134 -0
  95. data/doc/design/sat_stack.puml +37 -0
  96. data/doc/design/shared.puml +171 -0
  97. data/doc/design/solr_usecase.puml +189 -0
  98. data/doc/design/tasks.md +74 -0
  99. data/doc/design/user_interfaces.md +189 -0
  100. data/doc/introduction.md +84 -0
  101. data/doc/writing_stacks.md +102 -0
  102. data/lib/foreman_deployments.rb +7 -0
  103. data/lib/foreman_deployments/engine.rb +94 -0
  104. data/lib/foreman_deployments/monkey_patches.rb +9 -0
  105. data/lib/foreman_deployments/version.rb +3 -0
  106. data/lib/tasks/foreman_deployments_tasks.rake +22 -0
  107. data/locale/Makefile +62 -0
  108. data/test/factories/foreman_deployments.rb +70 -0
  109. data/test/functional/api/v2/deployments_controller_test.rb +318 -0
  110. data/test/functional/api/v2/stacks_controller_test.rb +140 -0
  111. data/test/test_plugin_helper.rb +14 -0
  112. data/test/unit/lib/config/array_test.rb +217 -0
  113. data/test/unit/lib/config/configurator_test.rb +66 -0
  114. data/test/unit/lib/config/hash_test.rb +178 -0
  115. data/test/unit/lib/inputs/value_test.rb +47 -0
  116. data/test/unit/lib/registry_test.rb +117 -0
  117. data/test/unit/lib/stack_definition_test.rb +54 -0
  118. data/test/unit/lib/stack_parser_test.rb +129 -0
  119. data/test/unit/lib/task_reference_test.rb +63 -0
  120. data/test/unit/lib/tasks/base_definition_test.rb +137 -0
  121. data/test/unit/lib/tasks/creation_task_definition_test.rb +57 -0
  122. data/test/unit/lib/tasks/host_creation_task_definition_test.rb +10 -0
  123. data/test/unit/lib/tasks/search_task_definition_test.rb +49 -0
  124. data/test/unit/lib/tasks/stack_deploy_action_test.rb +83 -0
  125. data/test/unit/lib/tasks/wait_until_built_task_definition_test.rb +71 -0
  126. data/test/unit/lib/validation/dereference_visitor_test.rb +48 -0
  127. data/test/unit/lib/validation/remove_ids_visitor_test.rb +90 -0
  128. data/test/unit/lib/validation/validation_result_test.rb +40 -0
  129. data/test/unit/lib/validation/validation_visitor_test.rb +67 -0
  130. data/test/unit/model/configuration_test.rb +88 -0
  131. data/test/unit/model/deployment_test.rb +159 -0
  132. data/test/unit/model/stack_test.rb +33 -0
  133. metadata +241 -0
@@ -0,0 +1,7 @@
1
+ require 'foreman_deployments/engine'
2
+
3
+ module ForemanDeployments
4
+ def self.registry
5
+ @task_registry ||= ForemanDeployments::Registry.new
6
+ end
7
+ end
@@ -0,0 +1,94 @@
1
+ require 'foreman_tasks'
2
+ require 'safe_yaml/load'
3
+ require 'foreman_deployments/monkey_patches'
4
+
5
+ module ForemanDeployments
6
+ class Engine < ::Rails::Engine
7
+ config.autoload_paths += Dir["#{config.root}/app/**/"]
8
+ config.autoload_paths += ["#{config.root}/test/"]
9
+
10
+ # Add any db migrations
11
+ initializer 'foreman_deployments.load_app_instance_data' do |app|
12
+ app.config.paths['db/migrate'] += ForemanDeployments::Engine.paths['db/migrate'].existent
13
+ end
14
+
15
+ initializer 'foreman_deployments.register_plugin', after: :finisher_hook do
16
+ Foreman::Plugin.register :foreman_deployments do
17
+ requires_foreman '>= 1.8'
18
+
19
+ # Add permissions
20
+ security_block :foreman_deployments do |map|
21
+ map.permission :view_deployments,
22
+ { :'foreman_deployments/api/v2/deployments' => [:index, :show] },
23
+ :resource_type => ForemanDeployments::Deployment.name
24
+ map.permission :create_deployments,
25
+ { :'foreman_deployments/api/v2/deployments' => [:create,
26
+ :merge_configuration,
27
+ :replace_configuration]
28
+ },
29
+ :resource_type => ForemanDeployments::Deployment.name
30
+ map.permission :run_deployments,
31
+ { :'foreman_deployments/api/v2/deployments' => [:run] },
32
+ :resource_type => ForemanDeployments::Deployment.name
33
+ map.permission :destroy_deployments,
34
+ { :'foreman_deployments/api/v2/deployments' => [:destroy] },
35
+ :resource_type => ForemanDeployments::Deployment.name
36
+
37
+ map.permission :view_stacks,
38
+ { :'foreman_deployments/api/v2/stacks' => [:index, :show] },
39
+ :resource_type => ForemanDeployments::Stack.name
40
+ map.permission :create_stacks,
41
+ { :'foreman_deployments/api/v2/stacks' => [:create] },
42
+ :resource_type => ForemanDeployments::Stack.name
43
+ map.permission :edit_stacks,
44
+ { :'foreman_deployments/api/v2/stacks' => [:update] },
45
+ :resource_type => ForemanDeployments::Stack.name
46
+ map.permission :destroy_stacks,
47
+ { :'foreman_deployments/api/v2/stacks' => [:destroy] },
48
+ :resource_type => ForemanDeployments::Stack.name
49
+ end
50
+
51
+ search_path_override('ForemanDeployments') do |resource|
52
+ "/#{resource.demodulize.underscore.pluralize}/auto_complete_search"
53
+ end
54
+ end
55
+ end
56
+
57
+ initializer 'foreman_deployments.apipie' do
58
+ # rubocop:disable Metrics/LineLength
59
+ Apipie.configuration.api_controllers_matcher << "#{ForemanDeployments::Engine.root}/app/controllers/foreman_deployments/api/v2/*.rb"
60
+ Apipie.configuration.checksum_path += ['/foreman_deployments/api/']
61
+ end
62
+
63
+ initializer 'foreman_deployments.require_dynflow', before: 'foreman_tasks.initialize_dynflow' do
64
+ ::ForemanTasks.dynflow.require!
65
+ ::ForemanTasks.dynflow.config.eager_load_paths << File.join(ForemanDeployments::Engine.root, 'app/services/foreman_deployments/tasks')
66
+ end
67
+
68
+ initializer 'foreman_deployments.safe_yaml' do
69
+ SafeYAML::OPTIONS[:default_mode] = :safe
70
+ SafeYAML::OPTIONS[:deserialize_symbols] = true
71
+ end
72
+
73
+ config.to_prepare do
74
+ ForemanDeployments.registry.register_task(ForemanDeployments::Tasks::CreationTaskDefinition)
75
+ ForemanDeployments.registry.register_task(ForemanDeployments::Tasks::SearchTaskDefinition)
76
+ ForemanDeployments.registry.register_task(ForemanDeployments::Tasks::WaitUntilBuiltTaskDefinition)
77
+ ForemanDeployments.registry.register_input(ForemanDeployments::Inputs::Value)
78
+ end
79
+
80
+ # Include concerns in this config.to_prepare block
81
+ # config.to_prepare do
82
+ # ::Hostgroup.send :include, ForemanDeployments::Concerns::Hostgroup
83
+ # ::GroupParameter.send :include, ForemanDeployments::Concerns::GroupParameter
84
+ # end
85
+
86
+ # config.eager_load_paths += ["#{config.root}/app/models/foreman_deployments/resource/"]
87
+
88
+ rake_tasks do
89
+ Rake::Task['db:seed'].enhance do
90
+ ForemanDeployments::Engine.load_seed
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,9 @@
1
+ module ActiveRecord
2
+ class Base
3
+ # adding to_hash to enable for using in dynflog actions' output
4
+ def to_hash
5
+ # TODO: replace passwords
6
+ attributes
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module ForemanDeployments
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,22 @@
1
+
2
+ # Tests
3
+ namespace :test do
4
+ desc 'Test ForemanDeployments'
5
+ Rake::TestTask.new(:foreman_deployments) do |t|
6
+ test_dir = File.join(File.dirname(__FILE__), '../..', 'test')
7
+ t.libs << ['test', test_dir]
8
+ t.pattern = "#{test_dir}/**/*_test.rb"
9
+ t.verbose = true
10
+ end
11
+ end
12
+
13
+ Rake::Task[:test].enhance do
14
+ Rake::Task['test:foreman_deployments'].invoke
15
+ end
16
+
17
+ load 'tasks/jenkins.rake'
18
+ if Rake::Task.task_defined?(:'jenkins:unit')
19
+ Rake::Task['jenkins:unit'].enhance do
20
+ Rake::Task['test:foreman_deployments'].invoke
21
+ end
22
+ end
@@ -0,0 +1,62 @@
1
+ #
2
+ # Makefile for PO merging and MO generation. More info in the README.
3
+ #
4
+ # make all-mo (default) - generate MO files
5
+ # make check - check translations using translate-tool
6
+ # make tx-update - download and merge translations from Transifex
7
+ # make clean - clean everything
8
+ #
9
+ DOMAIN = foreman_plugin_template
10
+ VERSION = $(shell ruby -e 'require "rubygems";spec = Gem::Specification::load(Dir.glob("../*.gemspec")[0]);puts spec.version')
11
+ POTFILE = $(DOMAIN).pot
12
+ MOFILE = $(DOMAIN).mo
13
+ POFILES = $(shell find . -name '*.po')
14
+ MOFILES = $(patsubst %.po,%.mo,$(POFILES))
15
+ POXFILES = $(patsubst %.po,%.pox,$(POFILES))
16
+
17
+ %.mo: %.po
18
+ mkdir -p $(shell dirname $@)/LC_MESSAGES
19
+ msgfmt -o $(shell dirname $@)/LC_MESSAGES/$(MOFILE) $<
20
+
21
+ # Generate MO files from PO files
22
+ all-mo: $(MOFILES)
23
+
24
+ # Check for malformed strings
25
+ %.pox: %.po
26
+ msgfmt -c $<
27
+ pofilter --nofuzzy -t variables -t blank -t urls -t emails -t long -t newlines \
28
+ -t endwhitespace -t endpunc -t puncspacing -t options -t printf -t validchars --gnome $< > $@
29
+ cat $@
30
+ ! grep -q msgid $@
31
+
32
+ check: $(POXFILES)
33
+ msgfmt -c ${POTFILE}
34
+
35
+ # Merge PO files
36
+ update-po:
37
+ for f in $(shell find ./ -name "*.po") ; do \
38
+ msgmerge -N --backup=none -U $$f ${POTFILE} ; \
39
+ done
40
+
41
+ # Unify duplicate translations
42
+ uniq-po:
43
+ for f in $(shell find ./ -name "*.po") ; do \
44
+ msguniq $$f -o $$f ; \
45
+ done
46
+
47
+ tx-pull:
48
+ tx pull -f
49
+ for f in $(POFILES) ; do \
50
+ sed -i 's/^\("Project-Id-Version: \).*$$/\1$(DOMAIN) $(VERSION)\\n"/' $$f; \
51
+ done
52
+ -git commit -a -m "i18n - pulling from tx"
53
+
54
+ reset-po:
55
+ # merging po files is unnecessary when using transifex.com
56
+ git checkout -- ../locale/*/*po
57
+
58
+ tx-update: tx-pull reset-po $(MOFILES)
59
+ # amend mo files
60
+ git add ../locale/*/LC_MESSAGES
61
+ git commit -a --amend -m "i18n - pulling from tx"
62
+ -echo Changes commited!
@@ -0,0 +1,70 @@
1
+ FactoryGirl.define do
2
+ factory :stack, :class => ForemanDeployments::Stack do
3
+ sequence(:name) { |n| "stack_#{n}" }
4
+ definition [
5
+ 'Task1: !task:FakeTask',
6
+ ' hardcoded_param: hardcoded',
7
+ 'Task2: !task:FakeTask'
8
+ ].join("\n")
9
+
10
+ trait :with_taxonomy do
11
+ organizations do
12
+ [FactoryGirl.create(:organization)]
13
+ end
14
+ locations do
15
+ [FactoryGirl.create(:location)]
16
+ end
17
+ end
18
+ end
19
+
20
+ factory :configuration, :class => ForemanDeployments::Configuration do
21
+ end
22
+
23
+ factory :deployment, :class => ForemanDeployments::Deployment do
24
+ sequence(:name) { |n| "deployment_#{n}" }
25
+ transient do
26
+ stack nil
27
+ end
28
+
29
+ after(:build) do |deployment, evaluator|
30
+ unless evaluator.stack.nil?
31
+ deployment.configuration = FactoryGirl.build(:configuration, :stack => evaluator.stack)
32
+ end
33
+ end
34
+
35
+ trait :with_stack do
36
+ stack do
37
+ FactoryGirl.create(:stack)
38
+ end
39
+
40
+ after(:build) do |deployment, _evaluator|
41
+ deployment.stack.organizations << deployment.organization
42
+ deployment.stack.locations << deployment.location
43
+ end
44
+ end
45
+
46
+ trait :with_stack_taxonomy do
47
+ after(:build) do |deployment, _evaluator|
48
+ deployment.organization = deployment.stack.organizations.first
49
+ deployment.location = deployment.stack.locations.first
50
+ end
51
+ end
52
+
53
+ trait :with_taxonomy do
54
+ organization do
55
+ FactoryGirl.create(:organization)
56
+ end
57
+ location do
58
+ FactoryGirl.create(:location)
59
+ end
60
+ end
61
+ end
62
+
63
+ factory :foreman_task, :class => ForemanTasks::Task do
64
+ sequence(:label) { |n| "task#{n}" }
65
+ sequence(:id) { |n| 'b8317062-c664-4792-9d9a-8167b23c%04d' % n }
66
+ type 'Tasks::StackDeployAction'
67
+ state 'pending'
68
+ result 'success'
69
+ end
70
+ end
@@ -0,0 +1,318 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class ForemanDeployments::Api::V2::DeploymentsControllerTest < ActionController::TestCase
4
+ include RegistryStub
5
+
6
+ class FakeTask < ForemanDeployments::Tasks::BaseDefinition
7
+ def validate
8
+ ForemanDeployments::Validation::ValidationResult.new
9
+ end
10
+ end
11
+
12
+ class InvalidFakeTask < ForemanDeployments::Tasks::BaseDefinition
13
+ def validate
14
+ ForemanDeployments::Validation::ValidationResult.new([
15
+ 'Some validation error'
16
+ ])
17
+ end
18
+ end
19
+
20
+ setup do
21
+ @stack = FactoryGirl.create(:stack,
22
+ :organizations => [taxonomies(:organization1), taxonomies(:organization2)],
23
+ :locations => [taxonomies(:location1), taxonomies(:location2)]
24
+ )
25
+ @deployment = FactoryGirl.create(:deployment, :with_taxonomy, :with_stack)
26
+
27
+ @registry = stub_registry
28
+ @registry.register_task(FakeTask)
29
+ @registry.register_task(InvalidFakeTask)
30
+ end
31
+
32
+ describe 'creating a deployment' do
33
+ setup do
34
+ @deployment_params = {
35
+ :name => 'A Deployment',
36
+ :stack_id => @stack.id,
37
+ :organization_id => taxonomies(:organization1).id,
38
+ :location_id => taxonomies(:location1).id
39
+ }
40
+ end
41
+
42
+ test 'it creates a deployment' do
43
+ assert_difference('ForemanDeployments::Deployment.count', 1) do
44
+ post :create, :deployment => @deployment_params
45
+ end
46
+ assert_response :success
47
+
48
+ parsed_response = JSON.parse(response.body)
49
+ assert_equal('A Deployment', parsed_response['name'])
50
+ end
51
+
52
+ test 'it creates configuration for the deployment' do
53
+ assert_difference('ForemanDeployments::Configuration.count', 1) do
54
+ post :create, :deployment => @deployment_params
55
+ end
56
+ assert_response :success
57
+ end
58
+
59
+ test 'should complain when a name is missing' do
60
+ assert_difference('ForemanDeployments::Stack.count', 0) do
61
+ post :create, :deployment => @deployment_params.except(:name)
62
+ end
63
+ assert_response :unprocessable_entity
64
+ parsed_response = JSON.parse(response.body)
65
+
66
+ assert_includes(parsed_response['error']['full_messages'], 'Name can\'t be blank')
67
+ end
68
+
69
+ test 'should complain when a stack is missing' do
70
+ assert_difference('ForemanDeployments::Stack.count', 0) do
71
+ post :create, :deployment => @deployment_params.except(:stack_id)
72
+ end
73
+ assert_response :unprocessable_entity
74
+ parsed_response = JSON.parse(response.body)
75
+
76
+ assert_includes(parsed_response['error']['full_messages'], 'Stack can\'t be blank')
77
+ end
78
+ end
79
+
80
+ describe 'listing deployments' do
81
+ setup do
82
+ @org_deployment = FactoryGirl.create(:deployment, :with_stack,
83
+ :location_id => taxonomies(:location2).id,
84
+ :organization_id => taxonomies(:organization1).id
85
+ )
86
+ @loc_deployment = FactoryGirl.create(:deployment, :with_stack,
87
+ :location_id => taxonomies(:location1).id,
88
+ :organization_id => taxonomies(:organization2).id
89
+ )
90
+ @both_deployment = FactoryGirl.create(:deployment, :with_stack,
91
+ :location_id => taxonomies(:location1).id,
92
+ :organization_id => taxonomies(:organization1).id
93
+ )
94
+ end
95
+
96
+ test 'it lists deployments' do
97
+ get :index
98
+ assert_response :success
99
+ end
100
+
101
+ test 'should get deployments for location only' do
102
+ get :index, :location_id => taxonomies(:location1).id
103
+ assert_response :success
104
+ assert_equal [@loc_deployment, @both_deployment], assigns(:deployments)
105
+ end
106
+
107
+ test 'should get deployments for organization only' do
108
+ get :index, :organization_id => taxonomies(:organization1).id
109
+ assert_response :success
110
+ assert_equal [@org_deployment, @both_deployment], assigns(:deployments)
111
+ end
112
+
113
+ test 'should get deployments for both location and organization' do
114
+ get :index, :organization_id => taxonomies(:organization1).id, :location_id => taxonomies(:location1).id
115
+ assert_response :success
116
+ assert_equal [@both_deployment], assigns(:deployments)
117
+ end
118
+ end
119
+
120
+ describe 'configuration' do
121
+ describe 'new configuration' do
122
+ test 'it configures the value' do
123
+ task1_config = {
124
+ 'organization_id' => '1',
125
+ 'location_id' => '2'
126
+ }
127
+ task2_config = {
128
+ 'organization_id' => '3',
129
+ 'location_id' => '4'
130
+ }
131
+ values = {
132
+ :Task1 => task1_config,
133
+ :Task2 => task2_config
134
+ }
135
+
136
+ put :replace_configuration, :id => @deployment.id, :values => values
137
+ assert_response :success
138
+
139
+ @deployment.reload
140
+ assert_equal(task1_config, @deployment.configuration.get_config_for(stub(:task_id => 'Task1')))
141
+ assert_equal(task2_config, @deployment.configuration.get_config_for(stub(:task_id => 'Task2')))
142
+ end
143
+
144
+ test 'it replaces the values from the previous configuration' do
145
+ previous_config = {
146
+ 'organization_id' => '1',
147
+ 'location_id' => '2'
148
+ }
149
+ new_config = {
150
+ 'location_id' => '3',
151
+ 'host_id' => '4'
152
+ }
153
+
154
+ @deployment.configuration.set_config_for(stub(:task_id => 'Task1'), previous_config)
155
+ @deployment.configuration.save
156
+
157
+ put :replace_configuration, :id => @deployment.id, :values => { :Task1 => new_config }
158
+ assert_response :success
159
+
160
+ @deployment.reload
161
+ assert_equal(new_config, @deployment.configuration.get_config_for(stub(:task_id => 'Task1')))
162
+ end
163
+
164
+ test 'it fails when a hardcoded value would be overwritten' do
165
+ task1_config = {
166
+ 'organization_id' => '1',
167
+ 'hardcoded_param' => 'new_value'
168
+ }
169
+ values = {
170
+ :Task1 => task1_config
171
+ }
172
+
173
+ put :replace_configuration, :id => @deployment.id, :values => values
174
+ assert_response :unprocessable_entity
175
+
176
+ parsed_response = JSON.parse(response.body)
177
+ assert_includes(parsed_response['error']['message'], 'You can\'t override values hardcoded in the stack definition')
178
+
179
+ @deployment.reload
180
+ assert_equal({}, @deployment.configuration.get_config_for(stub(:task_id => 'Task1')))
181
+ assert_equal({}, @deployment.configuration.get_config_for(stub(:task_id => 'Task2')))
182
+ end
183
+ end
184
+
185
+ describe 'merge configuration' do
186
+ test 'it configures the value' do
187
+ task1_config = {
188
+ 'organization_id' => '1',
189
+ 'location_id' => '2'
190
+ }
191
+ task2_config = {
192
+ 'organization_id' => '3',
193
+ 'location_id' => '4'
194
+ }
195
+ values = {
196
+ :Task1 => task1_config,
197
+ :Task2 => task2_config
198
+ }
199
+
200
+ post :merge_configuration, :id => @deployment.id, :values => values
201
+ assert_response :success
202
+
203
+ @deployment.reload
204
+ assert_equal(task1_config, @deployment.configuration.get_config_for(stub(:task_id => 'Task1')))
205
+ assert_equal(task2_config, @deployment.configuration.get_config_for(stub(:task_id => 'Task2')))
206
+ end
207
+
208
+ test 'it merges with the values from the previous configuration' do
209
+ previous_config = {
210
+ 'organization_id' => '1',
211
+ 'location_id' => '2'
212
+ }
213
+ new_config = {
214
+ 'location_id' => '3',
215
+ 'host_id' => '4'
216
+ }
217
+ expected_config = previous_config.merge(new_config)
218
+
219
+ @deployment.configuration.set_config_for(stub(:task_id => 'Task1'), previous_config)
220
+ @deployment.configuration.save
221
+
222
+ post :merge_configuration, :id => @deployment.id, :values => { :Task1 => new_config }
223
+ assert_response :success
224
+
225
+ @deployment.reload
226
+ assert_equal(expected_config, @deployment.configuration.get_config_for(stub(:task_id => 'Task1')))
227
+ end
228
+
229
+ test 'it allows for removing values when nil (null in json) is passed' do
230
+ previous_config = {
231
+ 'organization_id' => '1',
232
+ 'location_id' => '2'
233
+ }
234
+ new_config = {
235
+ 'location_id' => nil,
236
+ 'host_id' => '4'
237
+ }
238
+ expected_config = {
239
+ 'organization_id' => '1',
240
+ 'host_id' => '4'
241
+ }
242
+
243
+ @deployment.configuration.set_config_for(stub(:task_id => 'Task1'), previous_config)
244
+ @deployment.configuration.save
245
+
246
+ post :merge_configuration, :id => @deployment.id, :values => { :Task1 => new_config }
247
+ assert_response :success
248
+
249
+ @deployment.reload
250
+ assert_equal(expected_config, @deployment.configuration.get_config_for(stub(:task_id => 'Task1')))
251
+ end
252
+
253
+ test 'it fails when a hardcoded value would be overwritten' do
254
+ task1_config = {
255
+ 'organization_id' => '1',
256
+ 'hardcoded_param' => 'new_value'
257
+ }
258
+ values = {
259
+ :Task1 => task1_config
260
+ }
261
+
262
+ post :merge_configuration, :id => @deployment.id, :values => values
263
+ assert_response :unprocessable_entity
264
+
265
+ parsed_response = JSON.parse(response.body)
266
+ assert_includes(parsed_response['error']['message'], 'You can\'t override values hardcoded in the stack definition')
267
+
268
+ @deployment.reload
269
+ assert_equal({}, @deployment.configuration.get_config_for(stub(:task_id => 'Task1')))
270
+ assert_equal({}, @deployment.configuration.get_config_for(stub(:task_id => 'Task2')))
271
+ end
272
+ end
273
+ end
274
+
275
+ describe 'run deployments' do
276
+ test 'it plans the deployment tasks' do
277
+ @deployment.configuration.set_config_for(stub(:task_id => 'Task1'), 'param2' => '1')
278
+ @deployment.configuration.set_config_for(stub(:task_id => 'Task2'), 'param2' => '2')
279
+ @deployment.configuration.save
280
+
281
+ ForemanTasks.expects(:async_task).with do |main_task, parsed_stack|
282
+ assert_equal(ForemanDeployments::Tasks::StackDeployAction, main_task)
283
+ assert_equal({ 'param2' => '1' }, parsed_stack.tasks['Task1'].configuration)
284
+ assert_equal({ 'param2' => '2' }, parsed_stack.tasks['Task2'].configuration)
285
+ end
286
+
287
+ post :run, :id => @deployment.id
288
+ assert_response :success
289
+ end
290
+
291
+ test 'it saves the task id' do
292
+ task = FactoryGirl.build(:foreman_task)
293
+ ForemanTasks.stubs(:async_task).returns(task)
294
+
295
+ post :run, :id => @deployment.id
296
+ assert_response :success
297
+
298
+ @deployment.reload
299
+ assert_equal(task.id, @deployment.task_id)
300
+ end
301
+
302
+ test 'it fails when one of the tasks is not valid' do
303
+ invalid_stack = FactoryGirl.create(:stack, :with_taxonomy,
304
+ :definition => [
305
+ 'Task1: !task:InvalidFakeTask',
306
+ 'Task2: !task:FakeTask'
307
+ ].join("\n")
308
+ )
309
+ deployment = FactoryGirl.create(:deployment, :with_stack_taxonomy, :stack => invalid_stack)
310
+
311
+ post :run, :id => deployment.id
312
+ assert_response :unprocessable_entity
313
+
314
+ parsed_response = JSON.parse(response.body)
315
+ assert_includes(parsed_response['error']['message'], 'Stack definition is invalid')
316
+ end
317
+ end
318
+ end