dopi 0.17.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 +20 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +322 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +102 -0
- data/LICENSE.txt +177 -0
- data/README.md +309 -0
- data/Rakefile +44 -0
- data/Vagrantfile +64 -0
- data/bin/dopi +4 -0
- data/doc/getting_started.md +247 -0
- data/doc/getting_started_examples/001_hello_world.yaml +17 -0
- data/doc/getting_started_examples/002_connecting_over_ssh.yaml +35 -0
- data/doc/plugins/custom.md +88 -0
- data/doc/plugins/mco/rpc.md +82 -0
- data/doc/plugins/ssh/custom.md +141 -0
- data/doc/plugins/ssh/file_contains.md +37 -0
- data/doc/plugins/ssh/file_deploy.md +52 -0
- data/doc/plugins/ssh/file_exists.md +31 -0
- data/doc/plugins/ssh/file_replace.md +37 -0
- data/doc/plugins/ssh/puppet_agent_run.md +50 -0
- data/doc/plugins/ssh/reboot.md +22 -0
- data/doc/plugins/ssh/wait_for_login.md +53 -0
- data/doc/plugins/winrm/cmd.md +161 -0
- data/doc/plugins/winrm/file_contains.md +39 -0
- data/doc/plugins/winrm/file_exists.md +31 -0
- data/doc/plugins/winrm/powershell.md +27 -0
- data/doc/plugins/winrm/puppet_agent_run.md +49 -0
- data/doc/plugins/winrm/reboot.md +17 -0
- data/doc/plugins/winrm/wait_for_login.md +55 -0
- data/dopi.gemspec +42 -0
- data/lib/dopi/cli/command_add.rb +35 -0
- data/lib/dopi/cli/command_list.rb +19 -0
- data/lib/dopi/cli/command_remove.rb +31 -0
- data/lib/dopi/cli/command_reset.rb +27 -0
- data/lib/dopi/cli/command_run.rb +68 -0
- data/lib/dopi/cli/command_show.rb +109 -0
- data/lib/dopi/cli/command_update.rb +37 -0
- data/lib/dopi/cli/command_validate.rb +27 -0
- data/lib/dopi/cli/global_options.rb +55 -0
- data/lib/dopi/cli/log.rb +33 -0
- data/lib/dopi/cli.rb +57 -0
- data/lib/dopi/command/custom.rb +52 -0
- data/lib/dopi/command/dummy.rb +27 -0
- data/lib/dopi/command/mco/rpc.rb +158 -0
- data/lib/dopi/command/ssh/custom.rb +48 -0
- data/lib/dopi/command/ssh/file_contains.rb +70 -0
- data/lib/dopi/command/ssh/file_deploy.rb +71 -0
- data/lib/dopi/command/ssh/file_exists.rb +54 -0
- data/lib/dopi/command/ssh/file_replace.rb +96 -0
- data/lib/dopi/command/ssh/puppet_agent_run.rb +63 -0
- data/lib/dopi/command/ssh/reboot.rb +50 -0
- data/lib/dopi/command/ssh/wait_for_login.rb +68 -0
- data/lib/dopi/command/winrm/cmd.rb +44 -0
- data/lib/dopi/command/winrm/file_contains.rb +66 -0
- data/lib/dopi/command/winrm/file_exists.rb +51 -0
- data/lib/dopi/command/winrm/powershell.rb +16 -0
- data/lib/dopi/command/winrm/puppet_agent_run.rb +61 -0
- data/lib/dopi/command/winrm/reboot.rb +33 -0
- data/lib/dopi/command/winrm/wait_for_login.rb +49 -0
- data/lib/dopi/command.rb +239 -0
- data/lib/dopi/command_parser/arguments.rb +38 -0
- data/lib/dopi/command_parser/credentials.rb +59 -0
- data/lib/dopi/command_parser/env.rb +37 -0
- data/lib/dopi/command_parser/exec.rb +27 -0
- data/lib/dopi/command_parser/exit_code.rb +73 -0
- data/lib/dopi/command_parser/output.rb +126 -0
- data/lib/dopi/command_set.rb +66 -0
- data/lib/dopi/connector/local.rb +77 -0
- data/lib/dopi/connector/ssh.rb +170 -0
- data/lib/dopi/connector/winrm.rb +167 -0
- data/lib/dopi/error.rb +43 -0
- data/lib/dopi/log.rb +18 -0
- data/lib/dopi/node.rb +70 -0
- data/lib/dopi/plan.rb +99 -0
- data/lib/dopi/pluginmanager.rb +62 -0
- data/lib/dopi/state.rb +226 -0
- data/lib/dopi/state_store.rb +155 -0
- data/lib/dopi/step.rb +227 -0
- data/lib/dopi/step_set.rb +70 -0
- data/lib/dopi/version.rb +3 -0
- data/lib/dopi.rb +165 -0
- data/spec/command_helper.rb +11 -0
- data/spec/fixtures/mco_client.cfg +26 -0
- data/spec/fixtures/plans/fail_on_timeout.yaml +20 -0
- data/spec/fixtures/plans/hello_world.yaml +34 -0
- data/spec/fixtures/plans/non_existing_node.yaml +26 -0
- data/spec/fixtures/plans/test_role_variable.yaml +29 -0
- data/spec/fixtures/puppet/Puppetfile +8 -0
- data/spec/fixtures/puppet/Puppetfile.lock +57 -0
- data/spec/fixtures/puppet/hiera.yaml +6 -0
- data/spec/fixtures/puppet/manifests/site.pp +52 -0
- data/spec/fixtures/test_configuration.yaml +54 -0
- data/spec/fixtures/test_credentials.yaml +11 -0
- data/spec/fixtures/test_deloyed_file.txt +5 -0
- data/spec/fixtures/test_infrastructure.yaml +12 -0
- data/spec/fixtures/test_nodes.yaml +45 -0
- data/spec/fixtures/testenv_plan.yaml +159 -0
- data/spec/integration/dopi/addrun_spec.rb +31 -0
- data/spec/integration/dopi/cli/command_run_spec.rb +38 -0
- data/spec/integration/dopi/cli/global_options_spec.rb +128 -0
- data/spec/integration/dopi/command_spec.rb +66 -0
- data/spec/integration/dopi/fail_check_plans/file_exists_fails.yaml +38 -0
- data/spec/integration/dopi/fail_check_plans/output_parser.yaml +39 -0
- data/spec/integration/dopi/fail_check_plans/powershell_fail.yaml +25 -0
- data/spec/integration/dopi/fail_check_plans/timeout.yaml +29 -0
- data/spec/integration/dopi/fail_check_plans/verify_commands.yaml +33 -0
- data/spec/integration/dopi/failplan.rb +27 -0
- data/spec/integration/dopi/plan.rb +27 -0
- data/spec/integration/dopi/plans/dummy.yaml +29 -0
- data/spec/integration/dopi/plans/max_per_role.yaml +55 -0
- data/spec/integration/dopi/plans/no_timeout.yaml +29 -0
- data/spec/integration/dopi/plans/node_and_role_patterns.yaml +58 -0
- data/spec/integration/dopi/plans/node_by_config.yaml +116 -0
- data/spec/integration/dopi/plans/plugin_defaults.yaml +86 -0
- data/spec/integration/dopi/plans/plugins/mco/rpc.yaml +33 -0
- data/spec/integration/dopi/plans/plugins/ssh/custom.yaml +97 -0
- data/spec/integration/dopi/plans/plugins/ssh/file_contains.yaml +51 -0
- data/spec/integration/dopi/plans/plugins/ssh/file_deploy.yaml +82 -0
- data/spec/integration/dopi/plans/plugins/ssh/file_exists.yaml +69 -0
- data/spec/integration/dopi/plans/plugins/ssh/file_replace.yaml +55 -0
- data/spec/integration/dopi/plans/plugins/ssh/puppet_agent_run.yaml +45 -0
- data/spec/integration/dopi/plans/plugins/ssh/reboot.yaml +43 -0
- data/spec/integration/dopi/plans/plugins/ssh/wait_for_login.yaml +45 -0
- data/spec/integration/dopi/plans/plugins/winrm/cmd.yaml +39 -0
- data/spec/integration/dopi/plans/plugins/winrm/file_contains.yaml +51 -0
- data/spec/integration/dopi/plans/plugins/winrm/file_exists.yaml +69 -0
- data/spec/integration/dopi/plans/plugins/winrm/reboot.yaml +31 -0
- data/spec/integration/dopi/plans/resolve_roles_on_validate.yaml +23 -0
- data/spec/integration/dopi/plans/ssh_parallel.yaml +37 -0
- data/spec/integration/dopi/plans/verify_commands.yaml +49 -0
- data/spec/spec_helper.rb +104 -0
- data/spec/unit/dopi/command/custom_spec.rb +58 -0
- data/spec/unit/dopi/command/mco/rpc_spec.rb +157 -0
- data/spec/unit/dopi/command/ssh/custom_spec.rb +30 -0
- data/spec/unit/dopi/command/ssh/file_deploy_spec.rb +42 -0
- data/spec/unit/dopi/command/ssh/file_replace_spec.rb +35 -0
- data/spec/unit/dopi/command_parser/credentials_spec.rb +53 -0
- data/spec/unit/dopi/command_parser/exit_code_spec.rb +63 -0
- data/spec/unit/dopi/command_parser/output_spec.rb +129 -0
- data/spec/unit/dopi/command_spec.rb +14 -0
- data/spec/unit/dopi/connector/winrm_spec.rb +111 -0
- data/spec/unit/dopi/node_spec.rb +24 -0
- data/spec/unit/dopi/plan_spec.rb +31 -0
- data/spec/unit/dopi/state_spec.rb +109 -0
- data/spec/unit/dopi/step_spec.rb +13 -0
- metadata +448 -0
data/README.md
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# Dopi
|
|
2
|
+
|
|
3
|
+
DOPi is the "inner" part of the Deployment Orchestrater for Puppet (DOP).
|
|
4
|
+
It is the part that connects into your nodes and runs commands in a defined
|
|
5
|
+
order.
|
|
6
|
+
|
|
7
|
+
The main purpose of DOPi is to get your nodes into a state where they can
|
|
8
|
+
run Puppet or any other config management. It will also allows you to
|
|
9
|
+
orchestrate this Puppet runs so you can setup your nodes in the desired order.
|
|
10
|
+
|
|
11
|
+
DOPi orchestrates puppet runs, mco calls and custom commands over different nodes
|
|
12
|
+
|
|
13
|
+
DOPi uses a DOP plan file to find out what it has to run in what order on
|
|
14
|
+
which nodes. To learn more about the syntax of this DOP plan file make sure
|
|
15
|
+
you checkout the Documentation in [dop_common](https://github.com/swisscom/dop_common).
|
|
16
|
+
|
|
17
|
+
If you are new to DOPi make sure you check out the [getting started guide](doc/getting_started.md).
|
|
18
|
+
|
|
19
|
+
## Change Log
|
|
20
|
+
|
|
21
|
+
Dopi is currently under heavy development and should not be considered stable. If you are
|
|
22
|
+
upgrading make sure you carefully ready the [Change Log](CHANGELOG.md)
|
|
23
|
+
|
|
24
|
+
## DOPi as a library
|
|
25
|
+
|
|
26
|
+
### Install
|
|
27
|
+
|
|
28
|
+
Add this line to your application's Gemfile:
|
|
29
|
+
|
|
30
|
+
gem 'dopi'
|
|
31
|
+
|
|
32
|
+
And then execute:
|
|
33
|
+
|
|
34
|
+
$ bundle
|
|
35
|
+
|
|
36
|
+
### Usage Example
|
|
37
|
+
|
|
38
|
+
require 'dopi'
|
|
39
|
+
|
|
40
|
+
Dopi.configure do |config|
|
|
41
|
+
config.role_variable = 'my_role'
|
|
42
|
+
config.role_default = 'base'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
plan_parser = DopCommon::Plan.new(YAML.load_file(plan_file))
|
|
46
|
+
plan = Dopi::Plan.new(plan_parser)
|
|
47
|
+
plan.run
|
|
48
|
+
|
|
49
|
+
puts "Plan status: #{plan.state.to_s}"
|
|
50
|
+
plan.steps.each do |step|
|
|
51
|
+
puts "[#{step.state.to_s}] #{step.name}"
|
|
52
|
+
step.commands.each do |command|
|
|
53
|
+
puts " [#{command.state.to_s}] #{command.node.fqdn}"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
#### With DOP plan cache
|
|
58
|
+
|
|
59
|
+
This will persist the plan in the DOP plan cache.
|
|
60
|
+
|
|
61
|
+
require 'dopi'
|
|
62
|
+
|
|
63
|
+
Dopi.configure do |config|
|
|
64
|
+
config.role_variable = 'my_role'
|
|
65
|
+
config.role_default = 'base'
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
plan = Dopi.add_plan(plan_file)
|
|
69
|
+
Dopi.run_plan(plan)
|
|
70
|
+
|
|
71
|
+
puts "Plan status: #{plan.state.to_s}"
|
|
72
|
+
plan.steps.each do |step|
|
|
73
|
+
puts "[#{step.state.to_s}] #{step.name}"
|
|
74
|
+
step.commands.each do |command|
|
|
75
|
+
puts " [#{command.state.to_s}] #{command.node.fqdn}"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
### DOPi as a CLI
|
|
80
|
+
|
|
81
|
+
### Install
|
|
82
|
+
|
|
83
|
+
Install the gem
|
|
84
|
+
|
|
85
|
+
$ gem install dopi
|
|
86
|
+
|
|
87
|
+
Help on all available options
|
|
88
|
+
|
|
89
|
+
$ dopi help
|
|
90
|
+
|
|
91
|
+
### Usage Example
|
|
92
|
+
|
|
93
|
+
First you have to add a plan to the plan cache:
|
|
94
|
+
|
|
95
|
+
$ dopi add spec/data/plan/example_deploment_plan_test.yaml
|
|
96
|
+
example_deploment_plan_test
|
|
97
|
+
|
|
98
|
+
This will return the plan name which can be used to run other
|
|
99
|
+
commands on that plan. You can get a list of all the plans in the
|
|
100
|
+
cache by running:
|
|
101
|
+
|
|
102
|
+
$ dopi list
|
|
103
|
+
example_deploment_plan_test
|
|
104
|
+
|
|
105
|
+
You can get information about the state of a plan with the show command
|
|
106
|
+
and the name of the plan:
|
|
107
|
+
|
|
108
|
+
$ dopi show example_deploment_plan_test
|
|
109
|
+
[ready] test_run
|
|
110
|
+
[ready] mysql01.example.com
|
|
111
|
+
[ready] web01.example.com
|
|
112
|
+
[ready] web02.example.com
|
|
113
|
+
[ready] haproxy01.example.com
|
|
114
|
+
[ready] haproxy02.example.com
|
|
115
|
+
[ready] Make sure we can login to all nodes
|
|
116
|
+
[ready] mysql01.example.com
|
|
117
|
+
[ready] web01.example.com
|
|
118
|
+
[ready] web02.example.com
|
|
119
|
+
[ready] haproxy01.example.com
|
|
120
|
+
[ready] haproxy02.example.com
|
|
121
|
+
[ready] ssh_test_run
|
|
122
|
+
[ready] mysql01.example.com
|
|
123
|
+
[ready] run_puppet
|
|
124
|
+
[ready] mysql01.example.com
|
|
125
|
+
[ready] web01.example.com
|
|
126
|
+
[ready] web02.example.com
|
|
127
|
+
[ready] haproxy01.example.com
|
|
128
|
+
[ready] haproxy02.example.com
|
|
129
|
+
[ready] run_puppet2
|
|
130
|
+
[ready] mysql01.example.com
|
|
131
|
+
[ready] web01.example.com
|
|
132
|
+
[ready] web02.example.com
|
|
133
|
+
[ready] haproxy01.example.com
|
|
134
|
+
[ready] haproxy02.example.com
|
|
135
|
+
|
|
136
|
+
You can run the plan with the run command and the name:
|
|
137
|
+
|
|
138
|
+
$ dopi run example_deploment_plan_test
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
## Plan File Format
|
|
142
|
+
|
|
143
|
+
For a general description of the DOP plan file format, please see the
|
|
144
|
+
[dop_common](https://github.com/swisscom/dop_common/blob/master/README.md)
|
|
145
|
+
documentation. The documentation in this gem will focus on the command hashes for all
|
|
146
|
+
the basic plugins which are shipped with DOPi and on how to create your own custom plugins.
|
|
147
|
+
|
|
148
|
+
### How to use Plugins
|
|
149
|
+
|
|
150
|
+
DOPi uses plugins to run commands on the nodes. Each step in the plan has one
|
|
151
|
+
command and as many verify_commands as needed. DOPi will run all the verify_commands
|
|
152
|
+
before the command and will run the command only if one of them fails.
|
|
153
|
+
|
|
154
|
+
In general a plugin is specified like this:
|
|
155
|
+
|
|
156
|
+
```YAML
|
|
157
|
+
- name "My new Step"
|
|
158
|
+
nodes: 'all'
|
|
159
|
+
command:
|
|
160
|
+
plugin: 'my_plugin_name'
|
|
161
|
+
parameter1: 'foo'
|
|
162
|
+
parameter2: 'bar'
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Some of the Plugins don't actually need parameters, so they can be called with the short form:
|
|
166
|
+
|
|
167
|
+
```YAML
|
|
168
|
+
- name "My new Step"
|
|
169
|
+
nodes: 'all'
|
|
170
|
+
command: 'my_simple_plugin'
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Verify Commands
|
|
174
|
+
|
|
175
|
+
It is usually a good idea to check if a step is required to run. This way you can make your
|
|
176
|
+
plans idempotent. You can define any number of verify commands. If they all are successful
|
|
177
|
+
DOPi will skip the run. There are a hand full of plugins who are written exactly for this
|
|
178
|
+
purpose.
|
|
179
|
+
|
|
180
|
+
```YAML
|
|
181
|
+
- name "Create file if it does not exist"
|
|
182
|
+
command:
|
|
183
|
+
verify_commands:
|
|
184
|
+
- plugin; 'ssh/file_exists'
|
|
185
|
+
file: '/tmp/somefile'
|
|
186
|
+
plugin: 'ssh/custom'
|
|
187
|
+
exec: 'echo'
|
|
188
|
+
arguments: "'Hello World' > /tmp/somefile"
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Generic Plugin Parameters
|
|
192
|
+
|
|
193
|
+
There are some generic parameters every plugin supports:
|
|
194
|
+
|
|
195
|
+
#### plugin_timeout (optional)
|
|
196
|
+
|
|
197
|
+
`default: 300`
|
|
198
|
+
|
|
199
|
+
The time in seconds after which DOPi will kill the thread and mark the step as failed.
|
|
200
|
+
|
|
201
|
+
#### verify_after_run (optional)
|
|
202
|
+
|
|
203
|
+
`default: false`
|
|
204
|
+
|
|
205
|
+
The verify commands will be executed again after the command run and the step will
|
|
206
|
+
only succeed if the verify commands all successful.
|
|
207
|
+
|
|
208
|
+
### Command Execution Plugins
|
|
209
|
+
|
|
210
|
+
This are the plugins generally used in steps as commands
|
|
211
|
+
|
|
212
|
+
[custom](doc/plugins/custom.md)
|
|
213
|
+
|
|
214
|
+
[ssh/custom](doc/plugins/ssh/custom.md)
|
|
215
|
+
|
|
216
|
+
[ssh/wait_for_login](doc/plugins/ssh/wait_for_login.md)
|
|
217
|
+
|
|
218
|
+
[ssh/reboot](doc/plugins/ssh/reboot.md)
|
|
219
|
+
|
|
220
|
+
[ssh/puppet_agent_run](doc/plugins/ssh/puppet_agent_run.md)
|
|
221
|
+
|
|
222
|
+
[ssh/file_replace](doc/plugins/ssh/file_replace.md)
|
|
223
|
+
|
|
224
|
+
[ssh/file_deploy](doc/plugins/ssh/file_deploy.md)
|
|
225
|
+
|
|
226
|
+
[mco/rpc](doc/plugins/mco/rpc.md)
|
|
227
|
+
|
|
228
|
+
[winrm/cmd](doc/plugins/winrm/cmd.md)
|
|
229
|
+
|
|
230
|
+
[winrm/powershell](doc/plugins/winrm/powershell.md)
|
|
231
|
+
|
|
232
|
+
[winrm/wait_for_login](doc/plugins/winrm/wait_for_login.md)
|
|
233
|
+
|
|
234
|
+
[winrm/reboot](doc/plugins/winrm/reboot.md)
|
|
235
|
+
|
|
236
|
+
[winrm/puppet_agent_run](doc/plugins/winrm/puppet_agent_run.md)
|
|
237
|
+
|
|
238
|
+
### Verification Plugins
|
|
239
|
+
|
|
240
|
+
This are some helper plugins that check stuff on the nodes. They are
|
|
241
|
+
usefull for verify_commands. However, every normal plugin can be used
|
|
242
|
+
as a verify_command and vice versa.
|
|
243
|
+
|
|
244
|
+
[ssh/file_contains](doc/plugins/ssh/file_contains.md)
|
|
245
|
+
|
|
246
|
+
[ssh/file_exists](doc/plugins/ssh/file_exists.md)
|
|
247
|
+
|
|
248
|
+
[winrm/file_contains](doc/plugins/winrm/file_contains.md)
|
|
249
|
+
|
|
250
|
+
[winrm/file_exists](doc/plugins/winrm/file_exists.md)
|
|
251
|
+
|
|
252
|
+
## Example Plans
|
|
253
|
+
|
|
254
|
+
There are some examples for DOPi in the sources which are also used for tests
|
|
255
|
+
|
|
256
|
+
[DOPi test environment setup](spec/integration/dopi/build_dop_test_environment.yaml)
|
|
257
|
+
|
|
258
|
+
More can be found in the plans directory.
|
|
259
|
+
|
|
260
|
+
## Contributing
|
|
261
|
+
|
|
262
|
+
1. Fork it
|
|
263
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
264
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
265
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
266
|
+
5. Create new Pull Request
|
|
267
|
+
|
|
268
|
+
### Run the test suit
|
|
269
|
+
|
|
270
|
+
Most of the tests depend on Vagrant to create an actual test environment where the DOPi
|
|
271
|
+
plugins can be tested under real conditions.
|
|
272
|
+
|
|
273
|
+
To setup the test suit you need a working vagrant (https://www.vagrantup.com/) installation
|
|
274
|
+
with the dop_common gem added as a plugin:
|
|
275
|
+
|
|
276
|
+
cd /tmp
|
|
277
|
+
git clone https://github.com/swisscom/dop_common.git
|
|
278
|
+
cd dop_common
|
|
279
|
+
gem build dop_common.gemspec
|
|
280
|
+
vagrant plugin install ./dop_common-*.gem
|
|
281
|
+
|
|
282
|
+
After you install the plugin you have to setup the test machines with the rake task:
|
|
283
|
+
|
|
284
|
+
cd /path/to/dopi/
|
|
285
|
+
bundle install --path .bundle
|
|
286
|
+
bundle exec rake spec:prep
|
|
287
|
+
|
|
288
|
+
You should always rerun 'spec:prep' to make sure your test environment is started
|
|
289
|
+
and setup correctly.
|
|
290
|
+
|
|
291
|
+
The tests will connect to the machines and for now you require some hosts file entries
|
|
292
|
+
to work correctly. Add the following lines to your /etc/hosts:
|
|
293
|
+
|
|
294
|
+
# Host entries for DOPi test environment
|
|
295
|
+
192.168.56.101 puppetmaster.example.com
|
|
296
|
+
192.168.56.102 broker.example.com
|
|
297
|
+
192.168.56.103 linux01.example.com
|
|
298
|
+
192.168.56.104 linux02.example.com
|
|
299
|
+
192.168.56.105 linux03.example.com
|
|
300
|
+
192.168.56.106 windows01.example.com
|
|
301
|
+
|
|
302
|
+
Now you are ready to run the test suit:
|
|
303
|
+
|
|
304
|
+
bundle exec rake
|
|
305
|
+
|
|
306
|
+
If you reboot your machine or stop the test machines you can make sure the test
|
|
307
|
+
environment is ready and built by simply running the setup again:
|
|
308
|
+
|
|
309
|
+
bundle exec rake testenv:setup
|
data/Rakefile
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'rspec/core/rake_task'
|
|
2
|
+
|
|
3
|
+
namespace :spec do
|
|
4
|
+
desc 'setup the test environment (this builds multiple virtual machines with vagrant and virtualbox)'
|
|
5
|
+
task :prep do
|
|
6
|
+
Bundler.with_clean_env do
|
|
7
|
+
sh('vagrant up')
|
|
8
|
+
hiera = 'spec/fixtures/puppet/hiera.yaml'
|
|
9
|
+
plan = 'spec/fixtures/testenv_plan.yaml'
|
|
10
|
+
sh('bundle package --all')
|
|
11
|
+
sh("bundle exec bin/dopi --verbosity debug --trace --hiera_yaml #{hiera} oneshot #{plan}")
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
desc 'destory the test environment'
|
|
16
|
+
task :clean do
|
|
17
|
+
Bundler.with_clean_env do
|
|
18
|
+
sh('vagrant destroy')
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
RSpec::Core::RakeTask.new(:unit) do |t|
|
|
23
|
+
t.pattern = 'spec/unit/**/*_spec.rb'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
RSpec::Core::RakeTask.new(:integration) do |t|
|
|
27
|
+
t.pattern = 'spec/integration/**/*_spec.rb'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
desc 'Run single plan file from spec/integration/dopi/plans/<name>.yaml, <name> is taken from env DOPI_TEST_PLAN'
|
|
31
|
+
RSpec::Core::RakeTask.new(:plan) do |t|
|
|
32
|
+
t.pattern = 'spec/integration/dopi/plan.rb'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
desc 'Run single plan file from spec/integration/dopi/fail_check_plans/<name>.yaml and expect it to fail, <name> is taken from env DOPI_TEST_PLAN'
|
|
36
|
+
RSpec::Core::RakeTask.new(:failplan) do |t|
|
|
37
|
+
t.pattern = 'spec/integration/dopi/failplan.rb'
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
42
|
+
|
|
43
|
+
task :default => :spec
|
|
44
|
+
|
data/Vagrantfile
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# -*- mode: ruby -*-
|
|
2
|
+
# vi: set ft=ruby :
|
|
3
|
+
|
|
4
|
+
# This will create the dop test machines with from a dop plan
|
|
5
|
+
# Please make sure you have installed dop_common as a Vagrant plugin
|
|
6
|
+
#
|
|
7
|
+
# $ vagrant plugin install path/to/dop_common-x.x.x.gem
|
|
8
|
+
#
|
|
9
|
+
require 'dop_common'
|
|
10
|
+
|
|
11
|
+
DOP_PLAN = 'spec/fixtures/testenv_plan.yaml'
|
|
12
|
+
|
|
13
|
+
hash = YAML.load(DopCommon::PreProcessor.load_plan(DOP_PLAN))
|
|
14
|
+
plan = DopCommon::Plan.new(hash)
|
|
15
|
+
|
|
16
|
+
Vagrant.configure(2) do |config|
|
|
17
|
+
|
|
18
|
+
# Create vagrant boxes from the plan file
|
|
19
|
+
plan.nodes.each do |node|
|
|
20
|
+
|
|
21
|
+
config.vm.define node.name do |machine|
|
|
22
|
+
machine.vm.box = node.image
|
|
23
|
+
|
|
24
|
+
interface = node.interfaces.first
|
|
25
|
+
machine.vm.network "private_network", ip: interface.ip
|
|
26
|
+
|
|
27
|
+
# windows/linux specific settings
|
|
28
|
+
if node.name[/^windows/, 0]
|
|
29
|
+
machine.vm.guest = :windows
|
|
30
|
+
machine.vm.hostname = node.name.split('.', 2)[0]
|
|
31
|
+
else
|
|
32
|
+
machine.vm.hostname = node.name
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# disable the default folder sync on the nodes
|
|
36
|
+
# and rsync all the stuff to the puppetmaster
|
|
37
|
+
if node.name == 'puppetmaster.example.com'
|
|
38
|
+
config.vm.synced_folder ".", "/vagrant", type: "rsync", rsync__exclude: ".bundle/"
|
|
39
|
+
else
|
|
40
|
+
config.vm.synced_folder ".", "/vagrant", disabled: true
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# Test run nodes
|
|
47
|
+
config.vm.define 'rhel6.example.com' do |machine|
|
|
48
|
+
machine.vm.box = 'puppetlabs/centos-6.6-64-nocm'
|
|
49
|
+
machine.vm.synced_folder ".", "/vagrant", type: "rsync", rsync__exclude: ".bundle/"
|
|
50
|
+
machine.vm.provision 'shell', inline: 'yum install -y gcc git epel-release centos-release-scl'
|
|
51
|
+
machine.vm.provision 'shell', inline: 'yum install -y ncurses-devel sshpass'
|
|
52
|
+
machine.vm.provision 'shell', inline: 'yum install -y rh-ruby22 rh-ruby22-ruby-devel rh-ruby22-rubygem-bundler'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
config.vm.define 'rhel7.example.com' do |machine|
|
|
56
|
+
machine.vm.box = 'puppetlabs/centos-7.0-64-nocm'
|
|
57
|
+
machine.vm.synced_folder ".", "/vagrant", type: "rsync", rsync__exclude: ".bundle/"
|
|
58
|
+
machine.vm.provision 'shell', inline: 'yum install -y gcc git centos-release-scl'
|
|
59
|
+
machine.vm.provision 'shell', inline: 'yum install -y ncurses-devel sshpass'
|
|
60
|
+
machine.vm.provision 'shell', inline: 'yum install -y rh-ruby22 rh-ruby22-ruby-devel rh-ruby22-rubygem-bundler'
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
|
data/bin/dopi
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# Getting started with DOPi
|
|
2
|
+
|
|
3
|
+
This guide is a good starting point if you are new to DOPi and want to
|
|
4
|
+
learn how to use it to automate your node provisioning.
|
|
5
|
+
|
|
6
|
+
To start make sure you installed DOPi according to the instructions in
|
|
7
|
+
the [README](README.md).
|
|
8
|
+
|
|
9
|
+
You will find all the examples written in this tutorial in the example
|
|
10
|
+
directory next to this file.
|
|
11
|
+
|
|
12
|
+
## Hello World
|
|
13
|
+
|
|
14
|
+
Let's start with a typical hello world plan file and analyze what
|
|
15
|
+
parts are required to actually use DOPi. Use your favored editor to
|
|
16
|
+
create a file called 'hello_world.yaml' with the following content:
|
|
17
|
+
|
|
18
|
+
name: 'hello_world'
|
|
19
|
+
|
|
20
|
+
infrastructures:
|
|
21
|
+
'test':
|
|
22
|
+
type: 'baremetal'
|
|
23
|
+
|
|
24
|
+
nodes:
|
|
25
|
+
'testlinux.example.com':
|
|
26
|
+
infrastructure: 'test'
|
|
27
|
+
|
|
28
|
+
steps:
|
|
29
|
+
- name: 'write hello world'
|
|
30
|
+
nodes: 'all'
|
|
31
|
+
command:
|
|
32
|
+
plugin: 'custom'
|
|
33
|
+
exec: 'echo'
|
|
34
|
+
arguments: '"hello world"'
|
|
35
|
+
|
|
36
|
+
Now let's try to use DOPi to run that plan. There are usually a
|
|
37
|
+
few steps required to run a plan. Here is what you have to do:
|
|
38
|
+
|
|
39
|
+
$ dopi add hello_world.yaml
|
|
40
|
+
New plan hello_world was added
|
|
41
|
+
hello_world
|
|
42
|
+
|
|
43
|
+
We just added the 'hello_world' plan to our plan cache. DOPi tells
|
|
44
|
+
us that this was successful and returns the handle 'hello_world'.
|
|
45
|
+
We will require this handle to do other stuff with the plan we
|
|
46
|
+
just added. The handle is in fact the same as the 'name' attribute
|
|
47
|
+
at the very top of the plan file. It is always good to chose a name
|
|
48
|
+
which describes best what the content is. You can use letters,
|
|
49
|
+
numbers, '-' and '_' but no spaces or any other kind of character in
|
|
50
|
+
the name.
|
|
51
|
+
|
|
52
|
+
The plan cache is just a directory which holds all your added plans
|
|
53
|
+
and some files for the state of the plans. This cache will also be
|
|
54
|
+
used by the dop-hiera plugin if you have any configuration data in
|
|
55
|
+
your plans (more on this later).
|
|
56
|
+
|
|
57
|
+
The standard directory for the plan cache is ~/.dop/cache if you run
|
|
58
|
+
DOPi as user or /var/lib/dop/plans if you run it as root. You can also
|
|
59
|
+
overwrite this with the global '--plan_cache_dir' option.
|
|
60
|
+
|
|
61
|
+
To list what plans are already added in your plan cache you can simply
|
|
62
|
+
list them with DOPi:
|
|
63
|
+
|
|
64
|
+
$ dopi list
|
|
65
|
+
hello_world
|
|
66
|
+
|
|
67
|
+
We can see that it contains our 'hello_world' plan file. To see what
|
|
68
|
+
the state of the plan is and what steps are defined we can show
|
|
69
|
+
the content of the plan with DOPi:
|
|
70
|
+
|
|
71
|
+
$ dopi show hello_world
|
|
72
|
+
[ready] hello_world
|
|
73
|
+
[ready] default
|
|
74
|
+
[ready] write hello world
|
|
75
|
+
[ready] testlinux.example.com
|
|
76
|
+
|
|
77
|
+
Now we see a whole hierarchy with every part in the state 'ready'.
|
|
78
|
+
The first line represents the state of the whole plan. You can only
|
|
79
|
+
run a plan which is in the state ready. If part of the plan is in
|
|
80
|
+
the state 'failed' it will reflect that in the plan state.
|
|
81
|
+
|
|
82
|
+
The second line represents the step set. You can separate your steps
|
|
83
|
+
in your plan into different sets, so they can be executed independendly
|
|
84
|
+
of eachother (more on that later). We did not specify a step set in our
|
|
85
|
+
hello_world.yaml, so DOPi will create a default step set for us.
|
|
86
|
+
|
|
87
|
+
The third line represents the step and it is named after the name
|
|
88
|
+
attribute we specified in the first step in the hello_world.yaml file.
|
|
89
|
+
A step is executed on a number of nodes and they are listed under each
|
|
90
|
+
step with their state, which represents the last line in the output.
|
|
91
|
+
|
|
92
|
+
So now that we know that our plan is ready we can execute it for the
|
|
93
|
+
first time. But maybe we want to check first what it actually does.
|
|
94
|
+
To accomplish this we run the plan in 'noop' mode first to see
|
|
95
|
+
exactly what commands get executed:
|
|
96
|
+
|
|
97
|
+
$ dopi run --noop hello_world
|
|
98
|
+
Starting signal handling
|
|
99
|
+
Starting to run step 'write hello world'
|
|
100
|
+
[Command] testlinux.example.com : Running command custom
|
|
101
|
+
[Command] testlinux.example.com : (NOOP) Executing 'echo "hello world"' for command custom
|
|
102
|
+
[Command] testlinux.example.com : (NOOP) Environment: {"DOP_NODE_FQDN"=>"testlinux.example.com"}
|
|
103
|
+
[ready] hello_world
|
|
104
|
+
[ready] default
|
|
105
|
+
[ready] write hello world
|
|
106
|
+
[ready] testlinux.example.com
|
|
107
|
+
|
|
108
|
+
Now you can see that DOPi will run the command 'echo "hello world"' as
|
|
109
|
+
we have specified in the plan file. Now let's remove the 'noop' option
|
|
110
|
+
and actually run it:
|
|
111
|
+
|
|
112
|
+
$ dopi run hello_world
|
|
113
|
+
Starting signal handling
|
|
114
|
+
Starting to run step 'write hello world'
|
|
115
|
+
[Command] testlinux.example.com : Running command custom
|
|
116
|
+
[Command] testlinux.example.com : custom [OK]
|
|
117
|
+
Step 'write hello world' successfully finished.
|
|
118
|
+
[done] hello_world
|
|
119
|
+
[done] default
|
|
120
|
+
[done] write hello world
|
|
121
|
+
[done] testlinux.example.com
|
|
122
|
+
|
|
123
|
+
DOPi successfully executed the plan and the state changed from 'ready'
|
|
124
|
+
to 'done'.
|
|
125
|
+
|
|
126
|
+
## Connecting over SSH
|
|
127
|
+
|
|
128
|
+
Until now we only executed commands on the local machine. But the main
|
|
129
|
+
purpose of DOPi is to connect to a machine and execute some commands
|
|
130
|
+
to make it ready or execute a configuration management tool like Puppet.
|
|
131
|
+
|
|
132
|
+
To make it easy to demonstrate this we will use the ssh plugin like you
|
|
133
|
+
normaly would to connect to a remote machine, but we will configure DOPi
|
|
134
|
+
so it actually connect to localhost.
|
|
135
|
+
|
|
136
|
+
First we add a network to the infrastructures hash:
|
|
137
|
+
|
|
138
|
+
infrastructures:
|
|
139
|
+
'test':
|
|
140
|
+
type: 'baremetal'
|
|
141
|
+
networks:
|
|
142
|
+
'localhost':
|
|
143
|
+
ip_pool:
|
|
144
|
+
from: '127.0.0.2'
|
|
145
|
+
to: '127.0.0.250'
|
|
146
|
+
ip_netmask: '255.255.255.0'
|
|
147
|
+
ip_defgw: '127.0.0.1'
|
|
148
|
+
|
|
149
|
+
We defined the network 'localhost' and a range of IPs. Now we have to
|
|
150
|
+
add our existing machine into this network by adding a network interface:
|
|
151
|
+
|
|
152
|
+
nodes:
|
|
153
|
+
'testlinux.example.com':
|
|
154
|
+
infrastructure: 'test'
|
|
155
|
+
interfaces:
|
|
156
|
+
'eth0':
|
|
157
|
+
network: 'localhost'
|
|
158
|
+
ip: '127.0.0.2'
|
|
159
|
+
|
|
160
|
+
Then we need to make sure we can access the local machine with SSH. We
|
|
161
|
+
have to provide some credentials to login to the machine. This is done
|
|
162
|
+
in the credentials hash:
|
|
163
|
+
|
|
164
|
+
credentials:
|
|
165
|
+
'test-credentials':
|
|
166
|
+
type: 'ssh_key'
|
|
167
|
+
username: 'myuser'
|
|
168
|
+
private_key: '/home/myuser/.ssh/id_rsa'
|
|
169
|
+
|
|
170
|
+
In this case we will use an SSH private key to connect to local host.
|
|
171
|
+
Make sure your public key is in your '~/.ssh/authorized_keys' file.
|
|
172
|
+
You can also define a username/password pair if you don't want to use
|
|
173
|
+
a private key, make sure you check the syntax in the documentation.
|
|
174
|
+
|
|
175
|
+
Now we change the plugin in the step and use the 'ssh/custom' plugin
|
|
176
|
+
instead of 'custom'. DOPi will now connect to the node and execute
|
|
177
|
+
the command via SSH. We also need to tell the plugin what credentials
|
|
178
|
+
it should use. Make sure the step looks like this now:
|
|
179
|
+
|
|
180
|
+
steps:
|
|
181
|
+
- name: 'write hello world'
|
|
182
|
+
nodes: 'all'
|
|
183
|
+
command:
|
|
184
|
+
plugin: 'ssh/custom'
|
|
185
|
+
credentials: 'test-credentials'
|
|
186
|
+
exec: 'echo'
|
|
187
|
+
arguments: '"hello world"'
|
|
188
|
+
|
|
189
|
+
This tells DOPi to use the previously defined credentials to login to
|
|
190
|
+
the machine. Let's update the plan:
|
|
191
|
+
|
|
192
|
+
$ bundle exec dopi update --plan hello_world.yaml hello_world
|
|
193
|
+
Updating plan hello_world
|
|
194
|
+
Plan hello_world was removed
|
|
195
|
+
New plan hello_world was added
|
|
196
|
+
hello_world
|
|
197
|
+
|
|
198
|
+
Updating the plan will always reset the state of the the steps since
|
|
199
|
+
we may completely change them and there is no way for DOPi to know
|
|
200
|
+
what states should be preserves (This may change in the future).
|
|
201
|
+
|
|
202
|
+
Let's run in noop mode:
|
|
203
|
+
|
|
204
|
+
$ bundle exec dopi run --noop hello_world
|
|
205
|
+
Starting signal handling
|
|
206
|
+
Starting to run step 'write hello world'
|
|
207
|
+
[Command] testlinux.example.com : Running command ssh/custom
|
|
208
|
+
[Command] testlinux.example.com : (NOOP) Executing 'ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -q -o ChallengeResponseAuthentication=no -o PasswordAuthentication=no -i /home/myuser/.ssh/id_rsa myuser@127.0.0.2 "DOP_NODE_FQDN=testlinux.example.com echo \"hello world\""' for command ssh/custom
|
|
209
|
+
[Command] testlinux.example.com : (NOOP) Environment: {"DOP_NODE_FQDN"=>"testlinux.example.com"}
|
|
210
|
+
[ready] hello_world
|
|
211
|
+
[ready] default
|
|
212
|
+
[ready] write hello world
|
|
213
|
+
[ready] testlinux.example.com
|
|
214
|
+
|
|
215
|
+
We see that DOPi will actually use ssh to connect to the node and
|
|
216
|
+
execute the step.
|
|
217
|
+
|
|
218
|
+
$ bundle exec dopi run hello_world
|
|
219
|
+
Starting signal handling
|
|
220
|
+
Starting to run step 'write hello world'
|
|
221
|
+
[Command] testlinux.example.com : Running command ssh/custom
|
|
222
|
+
[Command] testlinux.example.com : ssh/custom [OK]
|
|
223
|
+
Step 'write hello world' successfully finished.
|
|
224
|
+
[done] hello_world
|
|
225
|
+
[done] default
|
|
226
|
+
[done] write hello world
|
|
227
|
+
[done] testlinux.example.com
|
|
228
|
+
|
|
229
|
+
We can successfully run the step.
|
|
230
|
+
|
|
231
|
+
## Idempotency
|
|
232
|
+
|
|
233
|
+
As we have seen before if we update a plan we lose the state and
|
|
234
|
+
have to rerun all the steps. Sometimes this may not be what we want.
|
|
235
|
+
In any case, it is always good practice to write your steps in a way
|
|
236
|
+
so you can rerun them as many times as you want.
|
|
237
|
+
|
|
238
|
+
In DOPi this is made easy with verification commands which run prior
|
|
239
|
+
to the actual command and check if we can skip the step or not.
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
DOPi oneshot adds the plan to the plan cache, runs it and at the
|
|
244
|
+
end removes it from the cache again. We will learn more about the
|
|
245
|
+
different methods to run a plan later, for now we will use the
|
|
246
|
+
oneshot command because it is useful to test or if you don't care
|
|
247
|
+
about the state of a plan.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
name: 'hello_world'
|
|
2
|
+
|
|
3
|
+
infrastructures:
|
|
4
|
+
'test':
|
|
5
|
+
type: 'baremetal'
|
|
6
|
+
|
|
7
|
+
nodes:
|
|
8
|
+
'testlinux.example.com':
|
|
9
|
+
infrastructure: 'test'
|
|
10
|
+
|
|
11
|
+
steps:
|
|
12
|
+
- name: 'write hello world'
|
|
13
|
+
nodes: 'all'
|
|
14
|
+
command:
|
|
15
|
+
plugin: 'custom'
|
|
16
|
+
exec: 'echo'
|
|
17
|
+
arguments: '"hello world"'
|