dopv 0.11.0
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 +7 -0
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/ChangeLog.md +456 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +260 -0
- data/Guardfile +22 -0
- data/LICENSE.txt +177 -0
- data/README.md +214 -0
- data/Rakefile +6 -0
- data/bin/dopv +4 -0
- data/dopv.gemspec +52 -0
- data/lib/dopv.rb +166 -0
- data/lib/dopv/cli.rb +54 -0
- data/lib/dopv/cli/command_add.rb +37 -0
- data/lib/dopv/cli/command_export.rb +26 -0
- data/lib/dopv/cli/command_import.rb +32 -0
- data/lib/dopv/cli/command_list.rb +18 -0
- data/lib/dopv/cli/command_remove.rb +29 -0
- data/lib/dopv/cli/command_run.rb +38 -0
- data/lib/dopv/cli/command_update.rb +35 -0
- data/lib/dopv/cli/command_validate.rb +30 -0
- data/lib/dopv/infrastructure.rb +40 -0
- data/lib/dopv/infrastructure/providers/baremetal.rb +12 -0
- data/lib/dopv/infrastructure/providers/base.rb +422 -0
- data/lib/dopv/infrastructure/providers/openstack.rb +308 -0
- data/lib/dopv/infrastructure/providers/ovirt.rb +228 -0
- data/lib/dopv/infrastructure/providers/vsphere.rb +322 -0
- data/lib/dopv/log.rb +14 -0
- data/lib/dopv/persistent_disk.rb +128 -0
- data/lib/dopv/plan.rb +17 -0
- data/lib/dopv/state_store.rb +87 -0
- data/lib/dopv/version.rb +3 -0
- data/spec/data/hooks/test_hook_script_1 +9 -0
- data/spec/data/hooks/test_hook_script_2 +10 -0
- data/spec/data/plans/test-plan-1.yaml +140 -0
- data/spec/spec_helper.rb +112 -0
- data/spec/unit/dopv/dopv_spec.rb +7 -0
- data/spec/unit/dopv/persistent_disk_spec.rb +38 -0
- data/spec/unit/dopv/plan_spec.rb +34 -0
- data/spec/unit/dopv/version_spec.rb +17 -0
- metadata +401 -0
data/README.md
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
# Dopv
|
2
|
+
|
3
|
+
Dopv orchestrates deployments of nodes. A node can be a virtual machine or a bare-metal compute node.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'dopv'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install dopv
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
### Library
|
22
|
+
Deploy a plan
|
23
|
+
```ruby
|
24
|
+
require 'dopv'
|
25
|
+
plan = ::Dopv::load_plan(plan_file)
|
26
|
+
data_volumes_db = ::Dopv::load_data_volumes_db(db_file)
|
27
|
+
::Dopv::run_plan(plan, data_volumes_db)
|
28
|
+
```
|
29
|
+
Undeploy a plan while keeping data volumes
|
30
|
+
```ruby
|
31
|
+
require 'dopv'
|
32
|
+
plan = ::Dopv::load_plan(plan_file)
|
33
|
+
data_volumes_db = ::Dopv::load_data_volumes_db(db_file)
|
34
|
+
::Dopv::run_plan(plan, data_volumes_db, :undeploy)
|
35
|
+
```
|
36
|
+
Undeploy a plan and remove data volumes from infrastructure provider (stack) as
|
37
|
+
well as from persistent data volumes DB:
|
38
|
+
```ruby
|
39
|
+
require 'dopv'
|
40
|
+
plan = ::Dopv::load_plan(plan_file)
|
41
|
+
data_volumes_db = ::Dopv::load_data_volumes_db(db_file)
|
42
|
+
::Dopv::run_plan(plan, data_volumes_db, :undeploy, true)
|
43
|
+
```
|
44
|
+
|
45
|
+
### CLI
|
46
|
+
A command line interface utility `dopv` is provided.
|
47
|
+
|
48
|
+
#### Getting help
|
49
|
+
A help can be obtained by calling `dopv --help`:
|
50
|
+
```
|
51
|
+
$ dopv --help
|
52
|
+
NAME
|
53
|
+
dopv - DOPv command line tool
|
54
|
+
|
55
|
+
SYNOPSIS
|
56
|
+
dopv [global options] command [command options] [arguments...]
|
57
|
+
|
58
|
+
VERSION
|
59
|
+
0.7.0
|
60
|
+
|
61
|
+
GLOBAL OPTIONS
|
62
|
+
--help - Show this message
|
63
|
+
--logfile, -l path_to_log_file - Log file (default: none)
|
64
|
+
--[no-]trace, -t - Show stacktrace on crash
|
65
|
+
--verbosity, -v level - Verbosity of the command line tool (default: info)
|
66
|
+
--version - Display the program version
|
67
|
+
|
68
|
+
COMMANDS
|
69
|
+
add - Add a new plan file to the plan cache
|
70
|
+
deploy - Deploy a plan
|
71
|
+
export - Export the internal disk state into a local diskdb file
|
72
|
+
help - Shows a list of commands or help for one command
|
73
|
+
import - Import a diskdb file into the internal state store
|
74
|
+
list - Show the list of plans in the plan store
|
75
|
+
remove - Remove an existing plan from the plan cache
|
76
|
+
undeploy - Undeploy a plan
|
77
|
+
update - Update the plan and/or the plan state for a given plan yaml or plan name.
|
78
|
+
validate - Validate plan file
|
79
|
+
```
|
80
|
+
|
81
|
+
#### Validating a plan
|
82
|
+
The deployment plan `/tmp/foo_plan.yml` could be validated by issuing:
|
83
|
+
```
|
84
|
+
$ dopv validate -p /tmp/foo_plan.yml
|
85
|
+
Plan valid.
|
86
|
+
```
|
87
|
+
|
88
|
+
Please note that the plan is always validated before any action takes place.
|
89
|
+
|
90
|
+
#### Adding a plan
|
91
|
+
In order to add a plan to plan cache, use `dopv` `add` command:
|
92
|
+
```
|
93
|
+
$ dopv add /tmp/bar_plan.yml
|
94
|
+
```
|
95
|
+
|
96
|
+
Please note that this feature is considered experimental and should be used with extreme care.
|
97
|
+
|
98
|
+
#### Updating a plan
|
99
|
+
In order to update a plan in the cache after some local changes have been introduced, use `dopv`
|
100
|
+
`update` command:
|
101
|
+
```
|
102
|
+
$ dopv update /tmp/bar_plan.yml
|
103
|
+
```
|
104
|
+
|
105
|
+
One may use `-c` or `-i` in order to remove the existing disk information and start with a clean
|
106
|
+
state or to ignore the update and to merely set it to the latest version.
|
107
|
+
|
108
|
+
Please note that this feature is considered experimental and should be used with extreme care.
|
109
|
+
|
110
|
+
#### Listing plans in cache
|
111
|
+
One may use the `list` command to check which plans are stored in the plan cache.
|
112
|
+
|
113
|
+
#### Deploying a plan
|
114
|
+
To get a help on deploy CLI options launch `dopv help deploy` argument:
|
115
|
+
```
|
116
|
+
$ dopv help deploy
|
117
|
+
NAME
|
118
|
+
deploy - Deploy a plan
|
119
|
+
|
120
|
+
SYNOPSIS
|
121
|
+
dopv [global options] deploy [command options]
|
122
|
+
|
123
|
+
COMMAND OPTIONS
|
124
|
+
--diskdb, -d path_to_db_file - Use a local diskdb file and import/export it automatically (default: none)
|
125
|
+
--exclude_nodes=node01.example.com,node02.example.com,/example\.com$/ - Exclude this nodes from the run (default: )
|
126
|
+
--exclude_nodes_by_config='{"var1": ["val1", "/val2/"], "var2": "val2"}' - Exclude nodes with this config from the run (You have to specify a JSON hash here) (default: {})
|
127
|
+
--exclude_roles=role01,role01,/^rolepattern/ - Exclude this roles from the run (default: )
|
128
|
+
--nodes=node01.example.com,node02.example.com,/example\.com$/ - Run plans for this nodes only (default: )
|
129
|
+
--nodes_by_config='{"var1": ["val1", "/val2/"], "var2": "val2"}' - Run plans for this nodes with this config only (You have to specify a JSON hash here) (default: {})
|
130
|
+
--plan, -p path_to_plan_file - plan name from the store or plan file to deploy. If a plan file is given DOPv will run in oneshot mode and add/remove
|
131
|
+
the plan automatically to the plan store (required, default: none)
|
132
|
+
--roles=role01,role01,/^rolepattern/ - Run plans for this roles only (default: )
|
133
|
+
```
|
134
|
+
To deploy a plan located at `/tmp/plan.yaml` and store and/or load persistent disks database located at `/tmp/pdisks.yaml` one can launch `dopv` with following options:
|
135
|
+
```
|
136
|
+
$ dopv deploy -p /tmp/pdisks.yaml -d /tmp/pdisks.yaml
|
137
|
+
```
|
138
|
+
|
139
|
+
To deploy only nodes matching a regular expression `^foo-[1-9]+\.bar\.baz$` that are defined in a plan called `/tmp/plan.yaml` and store and/or load persistent disks database located at `/tmp/pdisks.yaml` one can launch `dopv` with following options:
|
140
|
+
```
|
141
|
+
$ dopv deploy -p /tmp/pdisks.yaml -d /tmp/pdisks.yaml --nodes=/^foo-[1-9]+\.bar\.baz$/
|
142
|
+
```
|
143
|
+
|
144
|
+
Please note that disk database file is created if it does not exist.
|
145
|
+
|
146
|
+
#### Undeploying a plan
|
147
|
+
To get a help on undeploy CLI options launch `dopv` `help undeploy` argument:
|
148
|
+
```
|
149
|
+
$ dopv help undeploy
|
150
|
+
NAME
|
151
|
+
undeploy - Undeploy a plan
|
152
|
+
|
153
|
+
SYNOPSIS
|
154
|
+
dopv [global options] undeploy [command options]
|
155
|
+
|
156
|
+
COMMAND OPTIONS
|
157
|
+
--diskdb, -d path_to_db_file - (default: none)
|
158
|
+
--plan, -p path_to_plan_file - (required, default: none)
|
159
|
+
ME
|
160
|
+
undeploy - Undeploy a plan
|
161
|
+
|
162
|
+
SYNOPSIS
|
163
|
+
dopv [global options] undeploy [command options]
|
164
|
+
|
165
|
+
COMMAND OPTIONS
|
166
|
+
--diskdb, -d path_to_db_file - Use a local diskdb file and import/export it automatically (default: none)
|
167
|
+
--exclude_nodes=node01.example.com,node02.example.com,/example\.com$/ - Exclude this nodes from the run (default: )
|
168
|
+
--exclude_nodes_by_config='{"var1": ["val1", "/val2/"], "var2": "val2"}' - Exclude nodes with this config from the run (You have to specify a JSON hash here) (default: {})
|
169
|
+
--exclude_roles=role01,role01,/^rolepattern/ - Exclude this roles from the run (default: )
|
170
|
+
--nodes=node01.example.com,node02.example.com,/example\.com$/ - Run plans for this nodes only (default: )
|
171
|
+
--nodes_by_config='{"var1": ["val1", "/val2/"], "var2": "val2"}' - Run plans for this nodes with this config only (You have to specify a JSON hash here) (default: {})
|
172
|
+
--plan, -p path_to_plan_file - plan name from the store or plan file to undeploy. If a plan file is given DOPv will run in oneshot mode and
|
173
|
+
add/remove the plan automatically to the plan store (required, default: none)
|
174
|
+
--[no-]rmdisk, -r - Remove the disks
|
175
|
+
--roles=role01,role01,/^rolepattern/ - Run plans for this roles only (default: ) --[no-]rmdisk, -r -
|
176
|
+
```
|
177
|
+
|
178
|
+
In order to destroy a deployment specified by a plan located at `/tmp/plan.yaml` and persistent disks database located at `/tmp/pdisks.yaml` one can launch `dopv` with following options:
|
179
|
+
```
|
180
|
+
$ dopv undeploy -p /tmp/pdisks.yaml -d /tmp/pdisks.yaml
|
181
|
+
```
|
182
|
+
If you also want to remove the data volumes of each node and remove their records from persistent data volumes DB, please specify `-r` or `--rmdisk` option as shown bellow:
|
183
|
+
```
|
184
|
+
$ dopv undeploy -p /tmp/pdisks.yaml -d /tmp/pdisks.yaml -r
|
185
|
+
```
|
186
|
+
If you'd like to selectively remove a node called `foo.bar.baz` as well as nodes that match regular expression `^foo[1-5]\.bar\.baz$` and their data disks, you would use `--nodes` filter:
|
187
|
+
```
|
188
|
+
$ dopv undeploy -p /tmp/pdisks.yaml -d /tmp/pdisks.yaml -r --nodes=foo.bar.baz,/^foo[1-5]\.bar\.baz$/
|
189
|
+
```
|
190
|
+
If you'd like to remove all nodes but those matching `foo.bar.baz` as well as nodes that match regular expression `^foo[1-5]\.bar\.baz$` and their data disks, you would use `--exclude_nodes` filter:
|
191
|
+
```
|
192
|
+
$ dopv undeploy -p /tmp/pdisks.yaml -d /tmp/pdisks.yaml -r --exclude_nodes=foo.bar.baz,/^foo[1-5]\.bar\.baz$/
|
193
|
+
```
|
194
|
+
|
195
|
+
#### Logging
|
196
|
+
By default `dopv` logs messages with `INFO` level and higher to standard output. In order to log to a file `-l` can be specified. The `-v` option is used to set a different log threshold. Following is an example of logging everything (`DEBUG` and above) into `/tmp/dopv.log` during plan deployment:
|
197
|
+
```
|
198
|
+
$ dopv -l /tmp/dopv.log -v debug deploy -p /tmp/plan.yaml -d /tmp/disks.yaml
|
199
|
+
```
|
200
|
+
|
201
|
+
## Node Filtering Notes
|
202
|
+
Please note that `dopv` filtering by configuration and roles is not yet supported.
|
203
|
+
|
204
|
+
## Plan
|
205
|
+
A plan format and description can be found [here](https://github.com/swisscom/dop_common/blob/master/doc/plan_format_v0.0.1.md). A plan example can be found [here](https://github.com/swisscom/dop_common/blob/master/doc/plan_format_v0.0.1.md)
|
206
|
+
|
207
|
+
|
208
|
+
## Contributing
|
209
|
+
|
210
|
+
1. Fork it
|
211
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
212
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
213
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
214
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/dopv
ADDED
data/dopv.gemspec
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dopv/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "dopv"
|
8
|
+
spec.version = Dopv::VERSION
|
9
|
+
spec.authors = ["Pavol Dilung", "Andreas Zuber"]
|
10
|
+
spec.email = ["pavol.dilung@swisscom.com", "azuber@puzzle.ch"]
|
11
|
+
spec.description = %q{Deployment orchestrator for VMs}
|
12
|
+
spec.summary = %q{Deployment orchestrator for VMs}
|
13
|
+
spec.homepage = "https://github.com/swisscom/dopv"
|
14
|
+
spec.license = "Apache-2.0"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_development_dependency "rspec-mocks"
|
25
|
+
spec.add_development_dependency "rspec-command"
|
26
|
+
spec.add_development_dependency "simplecov"
|
27
|
+
spec.add_development_dependency "pry"
|
28
|
+
if RUBY_VERSION < "2"
|
29
|
+
spec.add_development_dependency "pry-debugger"
|
30
|
+
else
|
31
|
+
spec.add_development_dependency "pry-byebug"
|
32
|
+
end
|
33
|
+
# Newer guard listen versions do not work properly with RB <= 2.2.2
|
34
|
+
spec.add_development_dependency "listen", "~> 3.0.8"
|
35
|
+
spec.add_development_dependency "guard-ctags-bundler"
|
36
|
+
|
37
|
+
spec.add_dependency "json", "~> 1.8"
|
38
|
+
spec.add_dependency 'logger-colors', '~> 1'
|
39
|
+
#spec.add_dependency "rest-client", "~> 1.7"
|
40
|
+
spec.add_dependency "rbovirt", "~> 0.1", '>= 0.1.3'
|
41
|
+
spec.add_dependency "rbvmomi", "~> 1.8.2"
|
42
|
+
spec.add_dependency "net-ssh", "< 3.0" # fog dependcy but net-ssh >= 3.x require ruby 2.x
|
43
|
+
spec.add_dependency "fog-google", "< 0.1.1" # fog dependcy but net-ssh >= 3.x require ruby 2.x
|
44
|
+
spec.add_dependency "fog-profitbricks", "~> 0.0.5" # fog dependency but fog-profitbricks > 0.5 requires ruby 2.x
|
45
|
+
spec.add_dependency "fog", "~> 1.36.0"
|
46
|
+
spec.add_dependency "gli", "~> 2.13.1"
|
47
|
+
spec.add_dependency "dop_common", "~> 0.13", '>= 0.13.0'
|
48
|
+
spec.add_dependency 'parallel', '~> 1'
|
49
|
+
if RUBY_VERSION < "2"
|
50
|
+
spec.add_dependency "rest-client", "< 2.0"
|
51
|
+
end
|
52
|
+
end
|
data/lib/dopv.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'dopv/version'
|
2
|
+
require 'dopv/log'
|
3
|
+
require 'dopv/persistent_disk'
|
4
|
+
require 'dopv/plan'
|
5
|
+
require 'dopv/infrastructure'
|
6
|
+
require 'dopv/state_store'
|
7
|
+
require 'dop_common'
|
8
|
+
require 'etc'
|
9
|
+
require 'parallel'
|
10
|
+
|
11
|
+
module Dopv
|
12
|
+
extend DopCommon::NodeFilter
|
13
|
+
|
14
|
+
DEFAULT_MAX_IN_FLIGHT = 5
|
15
|
+
|
16
|
+
def self.valid?(plan_file)
|
17
|
+
hash, _ = plan_store.read_plan_file(plan_file)
|
18
|
+
plan = DopCommon::Plan.new(hash)
|
19
|
+
plan.valid?
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.add(plan_file)
|
23
|
+
raise StandardError, 'Plan not valid; did not add' unless valid?(plan_file)
|
24
|
+
plan_name = plan_store.add(plan_file)
|
25
|
+
Dopv.update_state(plan_name)
|
26
|
+
plan_name
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.update_plan(plan_file, options = {})
|
30
|
+
raise StandardError, 'Plan not valid; did not add' unless valid?(plan_file)
|
31
|
+
plan_name = plan_store.update(plan_file)
|
32
|
+
update_state(plan_name, options)
|
33
|
+
plan_name
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.update_state(plan_name, options = {})
|
37
|
+
plan_store.run_lock(plan_name) do
|
38
|
+
state_store = Dopv::StateStore.new(plan_name, plan_store)
|
39
|
+
state_store.update(options)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.remove(plan_name, remove_dopi_state = true, remove_dopv_state = false)
|
44
|
+
plan_store.remove(plan_name, remove_dopi_state, remove_dopv_state)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.list
|
48
|
+
plan_store.list
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.deploy(plan_name, options = {})
|
52
|
+
run(:deploy, plan_name, options)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.undeploy(plan_name, options = {})
|
56
|
+
run(:undeploy, plan_name, options)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.refresh(plan_name, options = {})
|
60
|
+
run(:refresh, plan_name, options)
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.export_state(plan_name)
|
64
|
+
ensure_plan_exists(plan_name)
|
65
|
+
state_store = Dopv::StateStore.new(plan_name, plan_store)
|
66
|
+
state_store.export
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.export_state_file(plan_name, state_file)
|
70
|
+
ensure_plan_exists(plan_name)
|
71
|
+
File.open(state_file, 'w+') do |diskdb|
|
72
|
+
diskdb << YAML.dump(Dopv.export_state(plan_name))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.import_state(plan_name, data_volumes_db)
|
77
|
+
ensure_plan_exists(plan_name)
|
78
|
+
plan_store.run_lock(plan_name) do
|
79
|
+
state_store = Dopv::StateStore.new(plan_name, plan_store)
|
80
|
+
state_store.import(data_volumes_db)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.import_state_file(plan_name, state_file)
|
85
|
+
ensure_plan_exists(plan_name)
|
86
|
+
Dopv.import_state(plan_name, YAML.load_file(state_file))
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def self.plan_store
|
92
|
+
@plan_store ||= DopCommon::PlanStore.new(DopCommon.config.plan_store_dir)
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.ensure_plan_exists(plan_name)
|
96
|
+
unless plan_store.list.include?(plan_name)
|
97
|
+
raise StandardError, "The plan #{plan_name} does not exist in the plan store"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.get_plan(plan_name)
|
102
|
+
raise StandardError, 'Please update the plan state, there are pending updates' if pending_updates?(plan_name)
|
103
|
+
plan_parser = plan_store.get_plan(plan_name)
|
104
|
+
Dopv::Plan.new(plan_parser)
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.pending_updates?(plan_name)
|
108
|
+
state_store = Dopv::StateStore.new(plan_name, plan_store)
|
109
|
+
state_store.pending_updates?
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.run(operation, plan_name, options)
|
113
|
+
ensure_plan_exists(plan_name)
|
114
|
+
update_state(plan_name)
|
115
|
+
plan = get_plan(plan_name)
|
116
|
+
run_options = merge_default_options(options)
|
117
|
+
nodes = filter_nodes(plan.nodes, run_options[:run_for_nodes])
|
118
|
+
|
119
|
+
context_log_path = File.join(DopCommon.config.log_dir, "#{run_options[:run_id]}-#{plan_name}")
|
120
|
+
node_names = nodes.map{|n| n.name}
|
121
|
+
context_logger = DopCommon::ThreadContextLogger.new(context_log_path, node_names)
|
122
|
+
|
123
|
+
plan_store.run_lock(plan_name) do
|
124
|
+
state_store = Dopv::StateStore.new(plan_name, plan_store)
|
125
|
+
in_parallel(plan, nodes) do |node|
|
126
|
+
context_logger.log_context = node.name
|
127
|
+
case operation
|
128
|
+
when :deploy then Dopv::Infrastructure::bootstrap_node(node, state_store)
|
129
|
+
when :undeploy then Dopv::Infrastructure::destroy_node(node, state_store, run_options[:rmdisk])
|
130
|
+
when :refresh then Dopv::Infrastructure::refresh_node(node, state_store)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.merge_default_options(options)
|
137
|
+
{
|
138
|
+
:run_for_nodes => :all,
|
139
|
+
:rmdisk => false,
|
140
|
+
:run_id => Time.now.strftime('%Y%m%d-%H%M%S'),
|
141
|
+
}.merge(options)
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.in_parallel(plan, nodes)
|
145
|
+
errors = false
|
146
|
+
infras = nodes.group_by {|node| node.infrastructure}
|
147
|
+
Parallel.each(infras.keys, :in_threads => infras.keys.length) do |infra|
|
148
|
+
Dopv.log.debug("Spawning control thread for infra #{infra.name}")
|
149
|
+
max_in_flight = infra.max_in_flight || plan.max_in_flight || DEFAULT_MAX_IN_FLIGHT
|
150
|
+
Dopv.log.debug("Threads for infra #{infra.name}: #{max_in_flight}")
|
151
|
+
Parallel.each(infras[infra], :in_threads => max_in_flight) do |node|
|
152
|
+
Dopv.log.debug("Spawning thread for node #{node.name}.")
|
153
|
+
begin
|
154
|
+
Dopv.log.debug("Yielding node #{node.name}.")
|
155
|
+
yield(node)
|
156
|
+
rescue => e
|
157
|
+
errors = true
|
158
|
+
Dopv.log.error("There was an error while processing node #{node.name}: #{e}")
|
159
|
+
raise Parallel::Break
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
raise "Errors detected during plan run" if errors
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
data/lib/dopv/cli.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#
|
2
|
+
# DOPv command line main module
|
3
|
+
#
|
4
|
+
|
5
|
+
require 'gli'
|
6
|
+
require 'dop_common/cli/node_selection'
|
7
|
+
require 'dop_common/cli/log'
|
8
|
+
require 'dop_common/cli/global_options'
|
9
|
+
require 'dopv'
|
10
|
+
require 'dopv/cli/command_validate'
|
11
|
+
require 'dopv/cli/command_add'
|
12
|
+
require 'dopv/cli/command_remove'
|
13
|
+
require 'dopv/cli/command_list'
|
14
|
+
require 'dopv/cli/command_update'
|
15
|
+
require 'dopv/cli/command_import'
|
16
|
+
require 'dopv/cli/command_export'
|
17
|
+
require 'dopv/cli/command_run'
|
18
|
+
require 'logger/colors'
|
19
|
+
|
20
|
+
module Dopv
|
21
|
+
module Cli
|
22
|
+
include GLI::App
|
23
|
+
extend self
|
24
|
+
|
25
|
+
trace = false
|
26
|
+
|
27
|
+
program_desc 'DOPv command line tool'
|
28
|
+
version Dopv::VERSION
|
29
|
+
|
30
|
+
subcommand_option_handling :normal
|
31
|
+
arguments :strict
|
32
|
+
|
33
|
+
DopCommon::Cli.global_options(self)
|
34
|
+
|
35
|
+
pre do |global,command,options,args|
|
36
|
+
DopCommon.configure = global
|
37
|
+
ENV['GLI_DEBUG'] = 'true' if global[:trace] == true
|
38
|
+
DopCommon::Cli.initialize_logger('dopv.log', global[:log_level], global[:verbosity], global[:trace])
|
39
|
+
true
|
40
|
+
end
|
41
|
+
|
42
|
+
command_validate(self)
|
43
|
+
command_add(self)
|
44
|
+
command_remove(self)
|
45
|
+
command_list(self)
|
46
|
+
command_update(self)
|
47
|
+
command_import(self)
|
48
|
+
command_export(self)
|
49
|
+
command_run(self, :deploy)
|
50
|
+
command_run(self, :undeploy)
|
51
|
+
command_run(self, :refresh)
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|