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.
- checksums.yaml +15 -0
- data/LICENSE +619 -0
- data/README.md +52 -0
- data/Rakefile +30 -0
- data/app/controllers/foreman_deployments/api/v2/base_controller.rb +25 -0
- data/app/controllers/foreman_deployments/api/v2/deployments_controller.rb +102 -0
- data/app/controllers/foreman_deployments/api/v2/stacks_controller.rb +52 -0
- data/app/controllers/foreman_deployments/create_resources_controller.rb +62 -0
- data/app/controllers/foreman_deployments/deployments_controller.rb +5 -0
- data/app/controllers/foreman_deployments/stacks_controller.rb +5 -0
- data/app/lib/foreman_deployments/base_dereference_visitor.rb +55 -0
- data/app/lib/foreman_deployments/config.rb +16 -0
- data/app/lib/foreman_deployments/config/array.rb +91 -0
- data/app/lib/foreman_deployments/config/configurator.rb +23 -0
- data/app/lib/foreman_deployments/config/hash.rb +81 -0
- data/app/lib/foreman_deployments/config/load_visitor.rb +23 -0
- data/app/lib/foreman_deployments/config/merge_visitor.rb +23 -0
- data/app/lib/foreman_deployments/config/save_visitor.rb +23 -0
- data/app/lib/foreman_deployments/inputs/base_input_definition.rb +39 -0
- data/app/lib/foreman_deployments/inputs/value.rb +25 -0
- data/app/lib/foreman_deployments/planner_visitor.rb +26 -0
- data/app/lib/foreman_deployments/registry.rb +67 -0
- data/app/lib/foreman_deployments/stack_definition.rb +37 -0
- data/app/lib/foreman_deployments/stack_parser.rb +121 -0
- data/app/lib/foreman_deployments/task_reference.rb +48 -0
- data/app/lib/foreman_deployments/tasks/base_action.rb +6 -0
- data/app/lib/foreman_deployments/tasks/base_definition.rb +72 -0
- data/app/lib/foreman_deployments/tasks/creation_task_definition.rb +68 -0
- data/app/lib/foreman_deployments/tasks/host_creation_task_definition.rb +44 -0
- data/app/lib/foreman_deployments/tasks/search_task_definition.rb +55 -0
- data/app/lib/foreman_deployments/tasks/stack_deploy_action.rb +10 -0
- data/app/lib/foreman_deployments/tasks/wait_until_built_task_definition.rb +65 -0
- data/app/lib/foreman_deployments/validation/dereference_visitor.rb +18 -0
- data/app/lib/foreman_deployments/validation/remove_ids_visitor.rb +59 -0
- data/app/lib/foreman_deployments/validation/validation_error.rb +12 -0
- data/app/lib/foreman_deployments/validation/validation_result.rb +26 -0
- data/app/lib/foreman_deployments/validation/validation_visitor.rb +20 -0
- data/app/lib/foreman_deployments/validation/validator.rb +29 -0
- data/app/models/foreman_deployments/concerns/belongs_to_single_taxonomy.rb +42 -0
- data/app/models/foreman_deployments/concerns/belongs_to_stack_taxonomy.rb +24 -0
- data/app/models/foreman_deployments/configuration.rb +26 -0
- data/app/models/foreman_deployments/deployment.rb +57 -0
- data/app/models/foreman_deployments/resource_models/create_resource.rb +18 -0
- data/app/models/foreman_deployments/stack.rb +20 -0
- data/app/views/foreman_deployments/api/v2/deployments/base.json.rabl +3 -0
- data/app/views/foreman_deployments/api/v2/deployments/create.json.rabl +3 -0
- data/app/views/foreman_deployments/api/v2/deployments/index.json.rabl +3 -0
- data/app/views/foreman_deployments/api/v2/deployments/main.json.rabl +5 -0
- data/app/views/foreman_deployments/api/v2/deployments/merge_configuration.json.rabl +3 -0
- data/app/views/foreman_deployments/api/v2/deployments/replace_configuration.json.rabl +3 -0
- data/app/views/foreman_deployments/api/v2/deployments/run.json.rabl +3 -0
- data/app/views/foreman_deployments/api/v2/deployments/show.json.rabl +11 -0
- data/app/views/foreman_deployments/api/v2/deployments/update.json.rabl +3 -0
- data/app/views/foreman_deployments/api/v2/stacks/base.json.rabl +3 -0
- data/app/views/foreman_deployments/api/v2/stacks/create.json.rabl +3 -0
- data/app/views/foreman_deployments/api/v2/stacks/index.json.rabl +3 -0
- data/app/views/foreman_deployments/api/v2/stacks/main.json.rabl +3 -0
- data/app/views/foreman_deployments/api/v2/stacks/show.json.rabl +7 -0
- data/app/views/foreman_deployments/api/v2/stacks/update.json.rabl +3 -0
- data/app/views/foreman_deployments/create_resources/new.html.erb +6 -0
- data/config/routes.rb +41 -0
- data/db/migrate/20150623140612_create_stacks.rb +10 -0
- data/db/migrate/20150814092932_create_deployment.rb +20 -0
- data/db/migrate/20150916133305_add_task_to_deployments.rb +5 -0
- data/db/migrate/20150917130618_add_taxonomy_to_deployments.rb +8 -0
- data/db/seeds.d/03-permissions.rb +14 -0
- data/doc/deployment_process.md +112 -0
- data/doc/design/capsule_stack.puml +51 -0
- data/doc/design/complete_stack.puml +17 -0
- data/doc/design/config_resource_overview.puml +15 -0
- data/doc/design/design.md +230 -0
- data/doc/design/diagrams/capsule_stack.png +0 -0
- data/doc/design/diagrams/capsule_stack.svg +1 -0
- data/doc/design/diagrams/complete_stack.png +0 -0
- data/doc/design/diagrams/complete_stack.svg +1 -0
- data/doc/design/diagrams/config_resource_overview.png +0 -0
- data/doc/design/diagrams/config_resource_overview.svg +1 -0
- data/doc/design/diagrams/ordered_resource_overview.png +0 -0
- data/doc/design/diagrams/ordered_resource_overview.svg +1 -0
- data/doc/design/diagrams/overview.png +0 -0
- data/doc/design/diagrams/overview.svg +1 -0
- data/doc/design/diagrams/overview_class.png +0 -0
- data/doc/design/diagrams/overview_class.svg +1 -0
- data/doc/design/diagrams/sat_stack.png +0 -0
- data/doc/design/diagrams/sat_stack.svg +1 -0
- data/doc/design/diagrams/solr_usecase.png +0 -0
- data/doc/design/diagrams/solr_usecase.svg +1 -0
- data/doc/design/examples.md +192 -0
- data/doc/design/generate-diagrams.sh +7 -0
- data/doc/design/implementation.md +128 -0
- data/doc/design/ordered_resource_overview.puml +15 -0
- data/doc/design/overview.puml +42 -0
- data/doc/design/overview_class.puml +64 -0
- data/doc/design/resources.md +134 -0
- data/doc/design/sat_stack.puml +37 -0
- data/doc/design/shared.puml +171 -0
- data/doc/design/solr_usecase.puml +189 -0
- data/doc/design/tasks.md +74 -0
- data/doc/design/user_interfaces.md +189 -0
- data/doc/introduction.md +84 -0
- data/doc/writing_stacks.md +102 -0
- data/lib/foreman_deployments.rb +7 -0
- data/lib/foreman_deployments/engine.rb +94 -0
- data/lib/foreman_deployments/monkey_patches.rb +9 -0
- data/lib/foreman_deployments/version.rb +3 -0
- data/lib/tasks/foreman_deployments_tasks.rake +22 -0
- data/locale/Makefile +62 -0
- data/test/factories/foreman_deployments.rb +70 -0
- data/test/functional/api/v2/deployments_controller_test.rb +318 -0
- data/test/functional/api/v2/stacks_controller_test.rb +140 -0
- data/test/test_plugin_helper.rb +14 -0
- data/test/unit/lib/config/array_test.rb +217 -0
- data/test/unit/lib/config/configurator_test.rb +66 -0
- data/test/unit/lib/config/hash_test.rb +178 -0
- data/test/unit/lib/inputs/value_test.rb +47 -0
- data/test/unit/lib/registry_test.rb +117 -0
- data/test/unit/lib/stack_definition_test.rb +54 -0
- data/test/unit/lib/stack_parser_test.rb +129 -0
- data/test/unit/lib/task_reference_test.rb +63 -0
- data/test/unit/lib/tasks/base_definition_test.rb +137 -0
- data/test/unit/lib/tasks/creation_task_definition_test.rb +57 -0
- data/test/unit/lib/tasks/host_creation_task_definition_test.rb +10 -0
- data/test/unit/lib/tasks/search_task_definition_test.rb +49 -0
- data/test/unit/lib/tasks/stack_deploy_action_test.rb +83 -0
- data/test/unit/lib/tasks/wait_until_built_task_definition_test.rb +71 -0
- data/test/unit/lib/validation/dereference_visitor_test.rb +48 -0
- data/test/unit/lib/validation/remove_ids_visitor_test.rb +90 -0
- data/test/unit/lib/validation/validation_result_test.rb +40 -0
- data/test/unit/lib/validation/validation_visitor_test.rb +67 -0
- data/test/unit/model/configuration_test.rb +88 -0
- data/test/unit/model/deployment_test.rb +159 -0
- data/test/unit/model/stack_test.rb +33 -0
- metadata +241 -0
|
@@ -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,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
|
data/locale/Makefile
ADDED
|
@@ -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
|