dopi 0.17.0
Sign up to get free protection for your applications and to get access to all the features.
- 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"'
|