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,5 @@
1
+ class AddTaskToDeployments < ActiveRecord::Migration
2
+ def change
3
+ add_column :deployments, :task_id, :string
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ class AddTaxonomyToDeployments < ActiveRecord::Migration
2
+ def change
3
+ add_column :deployments, :organization_id, :integer
4
+ add_column :deployments, :location_id, :integer
5
+ add_foreign_key :deployments, :taxonomies, :name => :deployemnts_organziation_id_fk, :column => :organization_id
6
+ add_foreign_key :deployments, :taxonomies, :name => :deployemnts_location_id_fk, :column => :location_id
7
+ end
8
+ end
@@ -0,0 +1,14 @@
1
+ # rubocop:disable Style/FileName
2
+ permissions = [
3
+ %w(Deploy view_deployments),
4
+ %w(Deploy create_deployments),
5
+ %w(Deploy edit_deployments),
6
+ %w(Deploy destroy_deployments),
7
+ %w(Stack view_stacks),
8
+ %w(Stack create_stacks),
9
+ %w(Stack edit_stacks),
10
+ %w(Stack destroy_stacks)
11
+ ]
12
+ permissions.each do |resource, permission|
13
+ Permission.find_or_create_by_resource_type_and_name resource, permission
14
+ end
@@ -0,0 +1,112 @@
1
+ # Create, configure and deploy a stack
2
+
3
+ The current version of Foreman deployments provides only API for accessing the functionality.
4
+ The online api documentation is available at `<YOUR_FOREMAN_URL>/apidoc/v2/` after you install
5
+ the plugin. Look for resources `Stacks` and `Deployments`.
6
+
7
+ The following example shows how to use [apipie bindings](https://github.com/Apipie/apipie-bindings)
8
+ to create, configure and deploy a stack from a ruby script.
9
+
10
+ Basic initialization:
11
+ ```ruby
12
+ require 'apipie-bindings'
13
+ require 'yaml'
14
+ require 'awesome_print'
15
+
16
+ @api = ApipieBindings::API.new({
17
+ :uri => 'http://localhost:5500/',
18
+ :username => 'admin',
19
+ :password => :changeme,
20
+ :api_version => 2,
21
+ :aggressive_cache_checking => true,
22
+ :timeout => -1
23
+ })
24
+
25
+ ```
26
+
27
+ Create a stack. See description of [available tasks](writing_stacks.md) in our documentation:
28
+ ```yml
29
+ # stack_definition.yml
30
+ test_hostgroup: !task:FindResource
31
+ class: Hostgroup
32
+ search_term: 'name = Test'
33
+
34
+ test_host: !task:CreateResource
35
+ class: Host
36
+ params:
37
+ hostgroup_id: !reference
38
+ object: test_hostgroup
39
+ field: result.ids.first
40
+ compute_resource_id: 1
41
+ compute_profile_id: 1
42
+ compute_attributes:
43
+ start: '1'
44
+ name: !input:Value
45
+ default: deployment-test
46
+ description: Name for the test host
47
+
48
+ wait: !task:WaitUntilBuilt
49
+ host_id: !reference
50
+ object: test_host
51
+ field: object.id
52
+ ```
53
+
54
+ ```ruby
55
+ file = '/path/to/stack_definition.yml'
56
+ params = {
57
+ :stack => {
58
+ :name => 'Test stack',
59
+ :definition => File.read(file)
60
+ }
61
+ }
62
+ stack = @api.resource(:stacks).action(:create).call(params)
63
+ ```
64
+
65
+ Create a deployment of the stack:
66
+ ```ruby
67
+ params = {
68
+ :deployment => {
69
+ :stack_id => stack['id'],
70
+ :name => 'Test deployment',
71
+ }
72
+ }
73
+ deployment = @api.resource(:deployments).action(:create).call(params)
74
+ ```
75
+
76
+ Configure the inputs:
77
+ ```ruby
78
+ values = {
79
+ :test_host => {
80
+ :params => {
81
+ :name => 'my-test-host'
82
+ }
83
+ }
84
+ }
85
+
86
+ params = {
87
+ :id => deployment['id'],
88
+ :values => values
89
+ }
90
+ @api.resource(:deployments).action(:replace_configuration).call(params)
91
+ ```
92
+
93
+ Check the configuration and validation status:
94
+ ```ruby
95
+ params = {
96
+ :id => deployment['id']
97
+ }
98
+ ap @api.resource(:deployments).action(:show).call(params)
99
+ ```
100
+
101
+ Start the deployment:
102
+ ```ruby
103
+ params = {
104
+ :id => deployment['id']
105
+ }
106
+ ap @api.resource(:deployments).action(:run).call(params)
107
+
108
+ ```
109
+
110
+ Now, if the configured deployment is valid, it starts the deployment
111
+ process. The api returns `task_id` so that users can track the deployment
112
+ progress in the foreman tasks' UI.
@@ -0,0 +1,51 @@
1
+ @startuml
2
+
3
+ object CapsuleProvisioningSubnet <<TakeSubnet>> {
4
+
5
+ }
6
+
7
+ object CapsuleOs <<TakeOs>> {
8
+ description: OS for the Capsule machine
9
+ family: RHEL
10
+ version: '>= 6.5'
11
+ }
12
+
13
+ object CapsuleSatelliteMachine <<TakeHost>> {
14
+ description: The satellite master machine
15
+ count: 1
16
+ }
17
+
18
+ object CapsuleMachine <<TakeHost>> {
19
+ count: <input>
20
+ name: <template "capsule-#{index}">
21
+ subnet: <reference to CapsuleProvisioningSubnet>
22
+ os: <reference to CapsuleOs>
23
+ activation_key: <input>
24
+ }
25
+
26
+ object ProvisionCapsule <<ProvisionHost>> {
27
+ host: <reference to CapsuleMachine>
28
+ }
29
+
30
+ object GenerateAndDistributeCertificates <<RemoteExecution>> {
31
+ hosts: <reference to CapsuleSatelliteMachine>
32
+ command: "<% hosts.map(&:name).each {|fqdn| `capsule-certs-generate --capsule-fqdn ..."
33
+ params: [<references to capsules>]
34
+ result: [<capsule hosts>]
35
+ }
36
+
37
+ object InstallCapsule <<RemoteExecution>> {
38
+ host: <reference to GenerateAndDistributeCertificates>
39
+ command: "capsule-installer ..."
40
+ parameters: [oauth_key, oauth_secret, ...]
41
+ }
42
+
43
+
44
+ CapsuleProvisioningSubnet -[#gray]-> CapsuleMachine
45
+ CapsuleOs -[#gray]-> CapsuleMachine
46
+ CapsuleMachine -[#gray]-> ProvisionCapsule
47
+ ProvisionCapsule -[#gray]-> GenerateAndDistributeCertificates
48
+ CapsuleSatelliteMachine -[#gray]-> GenerateAndDistributeCertificates
49
+ GenerateAndDistributeCertificates -[#gray]-> InstallCapsule
50
+
51
+ @enduml
@@ -0,0 +1,17 @@
1
+ @startuml
2
+
3
+ package Satellite {
4
+ !include sat_stack.puml
5
+ }
6
+
7
+ package Capsule {
8
+ !include capsule_stack.puml
9
+ }
10
+
11
+
12
+ ProvisioningSubnet -[#red]-> CapsuleProvisioningSubnet : provide subnet
13
+ SatelliteMachine -[#red]-> CapsuleMachine : provide activation key
14
+ ProvisionSatellite -[#red]-> CapsuleSatelliteMachine : provide satellite instance
15
+
16
+ @enduml
17
+
@@ -0,0 +1,15 @@
1
+ @startuml
2
+
3
+ title Configuration Resource Types
4
+ scale 850 width
5
+
6
+ !include shared.puml
7
+ FONT
8
+ CONFIGRESOURCES
9
+
10
+ legend
11
+ All types share a single table.
12
+ It's using STI. Plugins can add another implementations.
13
+ end legend
14
+
15
+ @enduml
@@ -0,0 +1,230 @@
1
+ # Design
2
+
3
+
4
+ This design document describes the concept of multi-host orchestration in the Foreman.
5
+
6
+
7
+ ## Goals
8
+ * allow for defining multi-host provisioning, configuration and orchestration
9
+ * instance independent deployment definition
10
+ * sharing the definitions
11
+ * pre-configured "one click" deployments
12
+
13
+ ![Overview diagram](./diagrams/overview.png)
14
+
15
+ ## Stack
16
+
17
+ *Stack* is an abstract representation of the multi-host infrastructure to be built. They are composed of multiple *tasks* dependent on each other and define
18
+ relationships between them. Example tasks are "create host", "create hostgroup", "provision host", "run puppet", etc. See the "Tasks" section below
19
+ for the detailed definition of the term.
20
+
21
+ *Stacks* are designed to be independent of the Foreman instances and therefore they allow for being shared. The ultimate goal is being able to import a stack that
22
+ has been created elswhere into your Foreman instance and deploy it on our infrastructure. User inputs and mapping to the Foreman objects take place
23
+ in the configuration phase of the deployment. All inputs are defined by the *tasks*.
24
+
25
+ Same as majority of entities in the Foreman, stacks can be available to multiple organizations and locations.
26
+
27
+
28
+ ## Tasks
29
+
30
+ Tasks are the units a stack is composed of. Each task has defined input parameters and results that it produces. Result of one task can be used as an input
31
+ of another one, which enables for setting dependencies.
32
+
33
+ The stack definition gives a name and description for each of the task instances, to make it more clear what's its purpose. This information will be reused
34
+ in user interface for configuring deployments.
35
+
36
+ **Example:**
37
+
38
+ A task for creating subnets accepts input parameters
39
+ - name
40
+ - network_address
41
+ - network_mask
42
+ - ...
43
+
44
+ and produces a subnet instance
45
+
46
+ See [list of tasks](tasks.md) for details about planned tasks.
47
+
48
+
49
+ ## Stack definition
50
+
51
+ The stack defines tasks to be used, their inputs and relationships. Task's input can be:
52
+ * hardcoded value
53
+ * input required form a user in the configuration phase (will allow for basic type validations)
54
+ * reference to a value from another task
55
+ * ignored (default value is used)
56
+
57
+ Stacks are defined in yaml files.
58
+
59
+ ```yaml
60
+ DbServerHostgroup: !!createResource
61
+ resource: 'Hostgroup'
62
+ parameters:
63
+ name: 'DB servers'
64
+
65
+ DbHost: !!createResource
66
+ resource: 'Host'
67
+ description: 'Database hosts'
68
+ count: !!input
69
+ data_type: 'int'
70
+ min: '1'
71
+ parameters:
72
+ name: !!template
73
+ value: 'db-%'
74
+ puppet_classes:
75
+ - ntp
76
+ - postgres
77
+ comment: 'Database server'
78
+ hostgroup: !!reference
79
+ object: 'DbServerHostgroup'
80
+ field: 'result'
81
+ ```
82
+
83
+
84
+ #### Ordering actions without direct dependency
85
+
86
+ Each task has input field `after`, which can be used for forcing the order.
87
+
88
+ ```yaml
89
+ FirstRun: !!puppetRun
90
+
91
+ SecondRun: !!puppetRun
92
+ after: !!reference
93
+ object: 'FirstRun'
94
+ field: 'result'
95
+ ```
96
+
97
+
98
+ #### Stack's lifecycle
99
+
100
+ 1. Stacks are created as yaml descriptions of the infrastructure. Such yaml file is imported into the Foreman either via UI or API.
101
+ Yaml is the only supported import format. We can create conversion tools from a dedicated DSL to the yaml for the users' convenience
102
+ 1. Modification of imported stacks is not enabled. If the yaml definition is changed, users must import it again as a new stack.
103
+ 1. Stacks can be deleted only when there's no existing deployment of them. The removal action deletes the stack, it's resource definition and configurations.
104
+
105
+
106
+ ## Deployment
107
+
108
+ A *deployment* is a result of performing the instructions in a *stack*. It is an instance of a *stack*.
109
+
110
+ Similar to hosts, deployments belong to a single organization and location.
111
+
112
+ #### Deployment's lifecycle
113
+
114
+ 1. A deployment is created as a named instance of a stack.
115
+ 2. Before the deployment can be deployed, it needs to be configured. Users fill missing parameters in this step and assign Foreman's resources like hostgroups and subnets.
116
+ More on this step later.
117
+ 3. A configured deployment can be deployed onto the Foreman's infrastructure. This step is handled by dynflow.
118
+ 4. A deployment record(s) can be deleted while the deployed hosts keep on running. Although they save links to Foreman objects, deployments are separate from them.
119
+ Deleting associated hosts and hostgroups together with the deployment can be added as a future feature.
120
+
121
+
122
+
123
+ ## Deployment configuration
124
+
125
+ Deployment configuration holds set of user's inputs and mapping on the Foreman instance's objects. For example
126
+ what parent usergroups should be used, mapping of subnets, number of hosts and their network interfaces.
127
+
128
+ Configuration is always instance specific. It is kept separate from the deployments to enable saving pre-configurations and cloning of existing deployments.
129
+
130
+ Pre-configurations are saved without foregin key to any deployment. Users can clone and create a new deployment based on the saved config.
131
+ Unclonable fields like mac addresses are blanked and users need to replace them with new values. In certain circumstances this enables one click deployments.
132
+
133
+ The saved configuration consists of pieces belonging to individual resources. Each piece is saved into DB as an exported json. Resources
134
+ provide classes responsible for interpreting and saving the config.
135
+
136
+
137
+ ## Extensibility
138
+
139
+ Deployments will be extensible via foreman plugins that can define their own tasks, add properties to existing tasks and define additional input validators.
140
+
141
+ Tasks don't need to be limited to the Foreman only. In future the system can be extended with tasks for email notifications,
142
+ approvals, integration of third-party sytems (e.g. REST calls), etc.
143
+
144
+
145
+ ### Integration with Katello
146
+
147
+ We will integrate with Katello the same way. In the first phase we count with defining fields for an activation key
148
+ on tasks for creating `Hosts` and `Hostgroups`. It will also be possible to select resources from Katello.
149
+
150
+
151
+ ### Integration with Discovery
152
+
153
+ We plan two usecases:
154
+
155
+ 1. using already discovered host when you start a deployment manually
156
+
157
+ The configuration of a host selection task should enable you choosing discovered hosts to be used in the deployment alongside with managed hosts.
158
+ The stack description should not care about where the host comes from (whether it's discovered, existing to be re-provisioned or a newly created one).
159
+
160
+ 2. automatic deployment on discovered hosts
161
+
162
+ Discovery already has a feature called [automatic provisioning](http://theforeman.org/plugins/foreman_discovery/3.0/index.html#4.3Automaticprovisioning)
163
+ that allows for setting rules for matching discovered hosts, assigning them to a hostgroup automatically and start their provisioning once they're discovered.
164
+ This mechanism should be extended to enable assigning hosts to a deployment (and it's tasks for selecting hosts) and running it when there's enough of them.
165
+
166
+
167
+ ## The basic deployment workflow
168
+ 1. stack definition
169
+ * the user writes the yaml definition and imports it into the foreman → new stack is created
170
+ 2. stack import
171
+ * check it is valid yaml
172
+ * check all the used tasks are present in foreman
173
+ * save it
174
+ 3. deployment creation
175
+ * user selects the stack to deploy and gives the deployment a name
176
+ * user optionaly selects an existing (pre)configuration of the stack
177
+ * clone the configuration or create a new one
178
+ 4. deployment configuration
179
+ * parse the stack and get list of tasks
180
+ * apply the (pre)configuration and get fields that need input
181
+ * the task inputs are presented in their order
182
+ * take a value for an input, validate it, save it if it's correct
183
+ * check if all required fields are configured
184
+ 5. deploying the deployment
185
+ * take configuration
186
+ * execute pre-run validation for each task
187
+ - can test for example if required puppet classes are present
188
+ - tests whether selected record ids still exist (could be deleted since the configuration had been saved)
189
+ * parse the stack and get list of tasks
190
+ * plan dynflow actions with the values from above ^
191
+ - one main action that takes stack and configuration
192
+ - merge configuration for the task with values hardcoded in the stack definition
193
+ - plan the tasks with their configuration hashes
194
+ * execute the main task
195
+
196
+
197
+ ## Editing deployed infrastructure
198
+
199
+ Editing a deployed infrastructure (e.g. adding more hosts or removing some) is a complex task that can't be done automatically in most cases.
200
+ Users will need to define an extra stack for that process and run it separately.
201
+
202
+
203
+ ## Compatibility issues
204
+
205
+ Some stacks might not be applicable to all operating systems, for example because of incompatibility of the used puppet classes.
206
+ We will solve this by description of the stack (descriptions are shown to user during deployment configuration and creation).
207
+
208
+ There are no plans to implement any kind of such compatibility checks in the first phase. We can later implement it via better validations
209
+ for user input's.
210
+
211
+
212
+ ## Future features
213
+
214
+ Features that won't be part of the first implementation but can be added later to extend the design.
215
+
216
+ #### Composed stacks
217
+
218
+ Apart from defining usual tasks, a stack can define usage of another existing stack. User can for example define a "Web app stack" that is composed of a "Database stack" and a "Web server stack".
219
+
220
+ #### Stack abstraction
221
+
222
+ It is possible to define an abstract stack that can't be deployed. Such stacks require their concrete implementations, that fulfill [The Liskov substitution principle](http://en.wikipedia.org/wiki/Liskov_substitution_principle).
223
+
224
+ E.g. a "Web app stack" could be defined as composition of "Abstract DB stack" and "Abstract server stack". This needs to be substituted by concrete implementations (e.g. "Sinatra stack" and "Mongo DB stack") upon a deployment creation.
225
+
226
+ #### Stack inheritance
227
+
228
+ Stacks can inherit properties from their parents. All parent resources and their associations are then also part of child stacks. Child stack can add new resources, but no updates or removals are allowed. Child resource may depend on resource from parent stack.
229
+
230
+ Example use case can be abstract DB stack and its implementations where inheritance makes the implementation easier.