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,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
|
+

|
|
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.
|