runbook 0.15.0 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.dockerignore +17 -0
- data/.ruby-version +1 -1
- data/.travis.yml +6 -2
- data/CHANGELOG.md +15 -1
- data/README.md +144 -12
- data/Rakefile +7 -1
- data/TODO.md +39 -2
- data/dockerfiles/Dockerfile-runbook +18 -0
- data/{samples → examples}/hooks_runbook.rb +0 -0
- data/{samples → examples}/layout_runbook.rb +0 -0
- data/{samples → examples}/restart_nginx.rb +0 -0
- data/{samples → examples}/simple_runbook.rb +0 -0
- data/lib/runbook.rb +26 -6
- data/lib/runbook/airbrussh_context.rb +25 -0
- data/lib/runbook/cli.rb +17 -2
- data/lib/runbook/configuration.rb +7 -1
- data/lib/runbook/entities/book.rb +2 -2
- data/lib/runbook/entities/section.rb +2 -2
- data/lib/runbook/entities/setup.rb +7 -0
- data/lib/runbook/entities/step.rb +2 -2
- data/lib/runbook/entity.rb +6 -3
- data/lib/runbook/extensions/add.rb +1 -0
- data/lib/runbook/extensions/sections.rb +6 -2
- data/lib/runbook/extensions/setup.rb +17 -0
- data/lib/runbook/extensions/ssh_config.rb +2 -0
- data/lib/runbook/extensions/statements.rb +5 -0
- data/lib/runbook/extensions/steps.rb +11 -2
- data/lib/runbook/run.rb +6 -1
- data/lib/runbook/runs/ssh_kit.rb +6 -0
- data/lib/runbook/util/runbook.rb +4 -0
- data/lib/runbook/version.rb +1 -1
- data/lib/runbook/views/markdown.rb +11 -3
- data/runbook.gemspec +1 -1
- metadata +13 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8094ea43f8e96a2c1ccaf981248b84bef276b714460cd0b5c3fa1795f736e3a
|
4
|
+
data.tar.gz: 229c3d600c9bcd985451333027ac639a87e922547fa74e6688cef3db96373931
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be0ebd6c86a3ccaf34af851fe20d660a70752d7c4e32bbae9c14f6406e841ff230971e7c95f206da670594528af36ea3a97b4481e9981ca41753ede34b305fb8
|
7
|
+
data.tar.gz: f5b4f2b9d0c043e1eb10242f09892fa5011d1fd36e8325e83f46dccef50db3bd9691677379a82a70cc3697fa41c965c93f924ac8742f20868ce64b097d0aef55
|
data/.dockerignore
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
**/.git
|
2
|
+
/.bundle/
|
3
|
+
/.yardoc
|
4
|
+
/Gemfile.lock
|
5
|
+
/_yardoc/
|
6
|
+
/coverage/
|
7
|
+
/doc/
|
8
|
+
/pkg/
|
9
|
+
/spec/reports/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
# rspec failure tracking
|
13
|
+
.rspec_status
|
14
|
+
|
15
|
+
# recommended:
|
16
|
+
# https://github.com/thoughtbot/appraisal#version-control
|
17
|
+
gemfiles/*.gemfile.lock
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-2.
|
1
|
+
ruby-2.5.5
|
data/.travis.yml
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
|
1
|
+
dist: xenial
|
2
2
|
language: ruby
|
3
|
+
services:
|
4
|
+
- docker
|
3
5
|
rvm:
|
4
|
-
- 2.2.3
|
5
6
|
- 2.2.10
|
6
7
|
- 2.3.8
|
7
8
|
- 2.4.6
|
@@ -22,3 +23,6 @@ matrix:
|
|
22
23
|
gemfile: gemfiles/activesupport_6.gemfile
|
23
24
|
|
24
25
|
before_install: gem install bundler -v 1.15.4
|
26
|
+
|
27
|
+
script:
|
28
|
+
- bundle exec rake spec_all
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,20 @@ This log maintains a list of all substantive changes to Runbook. The log include
|
|
4
4
|
|
5
5
|
## master
|
6
6
|
|
7
|
+
## `v0.16.0` (2019-11-22)
|
8
|
+
|
9
|
+
### Fixes:
|
10
|
+
|
11
|
+
* Add better error messages for runtime values accessed at compile time
|
12
|
+
|
13
|
+
### New Features
|
14
|
+
|
15
|
+
* Add entity tags and labels
|
16
|
+
* Add `setup` entity for initial runbook setup code
|
17
|
+
* Add `Runbook.views` method for accessing an array of all defined views
|
18
|
+
* Add airbrussh context for better ssh_kit output
|
19
|
+
* Backtick "into" targets in markdown view output (Thanks fwolfst!)
|
20
|
+
|
7
21
|
## `v0.15.0` (2019-09-29)
|
8
22
|
|
9
23
|
### Fixes:
|
@@ -11,7 +25,7 @@ This log maintains a list of all substantive changes to Runbook. The log include
|
|
11
25
|
* Halt the project generator if gem generation fails
|
12
26
|
* Replace timeout_statement with abort_statement for assert statements
|
13
27
|
* Make runbook state files only readable by the current user
|
14
|
-
* Allow / characters in the title of a runbook (Thanks brafales)
|
28
|
+
* Allow / characters in the title of a runbook (Thanks brafales!)
|
15
29
|
|
16
30
|
### New Features
|
17
31
|
|
data/README.md
CHANGED
@@ -118,10 +118,12 @@ Initialize Runbook in your project:
|
|
118
118
|
|
119
119
|
* [1. Runbook Anatomy](#runbook-anatomy)
|
120
120
|
* [1.1 Entities, Statements, and Setters](#entities-statements-and-setters)
|
121
|
-
* [1.1.1 Books, Sections, and
|
121
|
+
* [1.1.1 Books, Sections, Steps, and Setup](#books-sections-steps-and-setup)
|
122
122
|
* [1.1.1.1 Books](#books)
|
123
123
|
* [1.1.1.2 Sections](#sections)
|
124
124
|
* [1.1.1.3 Steps](#steps)
|
125
|
+
* [1.1.1.4 Setup](#setup)
|
126
|
+
* [1.1.1.5 Tags and Labels](#tags-and-labels)
|
125
127
|
* [1.1.2 Statements](#statements)
|
126
128
|
* [1.1.2.1 Ask](#ask)
|
127
129
|
* [1.1.2.2 Assert](#assert)
|
@@ -169,11 +171,12 @@ Initialize Runbook in your project:
|
|
169
171
|
* [6.8 Adding to Runbook's Configuration](#adding-to-runbooks-configuration)
|
170
172
|
* [7. Testing](#testing)
|
171
173
|
* [8. Known Issues](#known-issues)
|
172
|
-
* [9.
|
173
|
-
* [10.
|
174
|
-
* [11.
|
175
|
-
* [12.
|
176
|
-
* [13.
|
174
|
+
* [9. FAQ](#faq)
|
175
|
+
* [10. Development](#development)
|
176
|
+
* [11. Contributing](#contributing)
|
177
|
+
* [12. Feature Requests](#feature-requests)
|
178
|
+
* [13. License](#license)
|
179
|
+
* [14. Code of Conduct](#code-of-conduct)
|
177
180
|
|
178
181
|
## Runbook Anatomy
|
179
182
|
|
@@ -220,7 +223,7 @@ Hierarchically, a runbook looks like this:
|
|
220
223
|
|
221
224
|
A runbook is composed of entities, statements, and setters. Runbook entities contain either other entities or statements. Examples of entities include Books, Sections, and Steps. They define the structure of the runbook and can be considered the "nodes" of the tree structure. As entities are the nodes of the tree structure, statements are the "leaves" of the structure and comprise the various behaviors or commands of the runbook. Setters, typically referenced from within steps, associate state with the node, which can be accessed by its children.
|
222
225
|
|
223
|
-
#### Books, Sections, and
|
226
|
+
#### Books, Sections, Steps, and Setup
|
224
227
|
|
225
228
|
Entities are composed of a title and a list of items which are their children. Each entity can be rendered with a specific view or executed with a specific run.
|
226
229
|
|
@@ -243,6 +246,60 @@ A book is broken up into sections. Every section requires a title. Sections can
|
|
243
246
|
|
244
247
|
Steps hold state and group together a set of statements. Steps do not require titles or children. This allows runbooks to be very flexible. You can fill out steps as needed, or be terse when the behavior of the step is self-evident. Steps without titles will not prompt to continue when running in paranoid mode.
|
245
248
|
|
249
|
+
##### Setup
|
250
|
+
|
251
|
+
Setup is a special entity that is always executed. It is not skipped when starting or resuming execution in the middle of a runbook. A prompt is never presented to determine if you should or should not execute the setup section. The setup section is similar to the step entity in that it shares the same DSL. In other words, any keywords available within steps are also available within the setup section.
|
252
|
+
|
253
|
+
The setup section provides two important use cases. First, it allows you ensure any dependent values are defined when executing your runbook. If skipping the initial steps of your runbook and starting in the middle, you can be sure that any initialization steps have been executed. For example, presume you have a runbook that prompts for a list of servers, stops the servers, and then starts them. It would be advantageous to define the prompting server logic in a setup section, so you can start the runbook at the start server step and know that the list of servers is defined.
|
254
|
+
|
255
|
+
Second, if you dynamically define the sections and steps in your runbook based on user input, then doing this in the setup section allows you start the runbook in the middle of the dynamically defined steps.
|
256
|
+
|
257
|
+
Because the setup section is always executed, it's execution should be idempotent. In other words, the setup section should be able to be executed multiple times in a row and produce the same result.
|
258
|
+
|
259
|
+
It may be ideal to ensure user input is only asked for once when executing a setup section.
|
260
|
+
|
261
|
+
```ruby
|
262
|
+
Runbook.book "Make Pizza" do
|
263
|
+
setup do
|
264
|
+
ruby_command do
|
265
|
+
@toppings ||= ENV["TOPPINGS"]
|
266
|
+
ask "What toppings would you like?", into: :toppings, default: "cheese" unless @toppings
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
```
|
271
|
+
|
272
|
+
The above example will set `@toppings` from a passed-in environment variable if present, otherwise it will ask the user to set `@toppings`. If toppings have already has been defined from a previous execution, it will not prompt the user for the value again. Because this logic references a value that is defined at runtime (`@toppings`), it must be wrapped in a `ruby_command`.
|
273
|
+
|
274
|
+
##### Tags and Labels
|
275
|
+
|
276
|
+
Any entity can be associated with arbitrary tags or labels. Once tags or labels are assigned, entity behavior can be modified using [hooks](#augmenting-functionality-with-hooks).
|
277
|
+
|
278
|
+
```ruby
|
279
|
+
Runbook.book "Bounce Nodes", :untested do
|
280
|
+
step "Disable monitoring", :skip do
|
281
|
+
confirm "Have you disabled health monitoring?"
|
282
|
+
end
|
283
|
+
|
284
|
+
step "Restart nodes", :aws_only, :mutator, labels: {rails_env: :production} do
|
285
|
+
confirm "Have you restarted the nodes?"
|
286
|
+
end
|
287
|
+
end
|
288
|
+
```
|
289
|
+
|
290
|
+
```ruby
|
291
|
+
Runbook::Runs::SSHKit.register_hook(:warn_for_untested_runbook, :before, Runbook::Entities::Book) do |object, metadata|
|
292
|
+
warning = "This runbook has not yet been tested. Beware of bugs!"
|
293
|
+
metadata[:toolbox].warn(warning) if object.tags.include?(:untested)
|
294
|
+
end
|
295
|
+
|
296
|
+
Runbook::Runs::SSHKit.register_hook(:skip_skippable_entities, :around, Runbook::Entity) do |object, metadata, block|
|
297
|
+
next if object.tags.include?(:skip)
|
298
|
+
next if object.labels[:rails_env] && object.labels[:rails_env] != ENV["RAILS_ENV"]
|
299
|
+
block.call
|
300
|
+
end
|
301
|
+
```
|
302
|
+
|
246
303
|
#### Statements
|
247
304
|
|
248
305
|
Statements are the workhorses of runbooks. They comprise all the behavior runbooks execute. Runbook comes with the following statements:
|
@@ -253,8 +310,14 @@ Prompts the user for a string and stores its value on the containing step entity
|
|
253
310
|
|
254
311
|
```ruby
|
255
312
|
ask "What percentage of requests are failing?", into: :failing_request_percentage, default: "100", echo: true
|
313
|
+
|
314
|
+
ruby_command do
|
315
|
+
note "Failing request percentage: #{@failing_request_percentage}"
|
316
|
+
end
|
256
317
|
```
|
257
318
|
|
319
|
+
In the above example, the `note` statement must be wrapped in a `ruby_command` statement. Without wrapping `note` in a `ruby_command`, it would be evaluated at compile time but the user will only be asked for input when the runbook is executed (so `@failing_request_percentage` would not have a value). If you find yourself wrapping many or all runbook statements in ruby commands it may make sense to set these values at compile time using environment variables.
|
320
|
+
|
258
321
|
##### Assert
|
259
322
|
|
260
323
|
Runs the provided `cmd` repeatedly until it returns true. A timeout and maximum number of attempts can be set. You can specify a command to be run if a timeout occurs or the maximum number of attempts is hit. Commands can optionally be specified as `raw`. This tells SSHKit to not perform auto-wrapping of the commands, but execute the exact string on the remote server. See SSHKit's documentation for more details.
|
@@ -277,7 +340,7 @@ assert(
|
|
277
340
|
|
278
341
|
##### Capture
|
279
342
|
|
280
|
-
Runs the provided `cmd` and captures its output into `into`. An optional `ssh_config` can be specified to configure how the capture command gets run. Capture commands take an optional `strip` parameter that indicates if the returned output should have leading and trailing whitespace removed. Capture commands also take an optional `raw` parameter that tells SSHKit whether the command should be executed as is, or to include the auto-wrapping of the ssh_config.
|
343
|
+
Runs the provided `cmd` and captures its output into `into`. Once captured, this value can be referenced in later statements such as the `ruby_command` statement. An optional `ssh_config` can be specified to configure how the capture command gets run. Capture commands take an optional `strip` parameter that indicates if the returned output should have leading and trailing whitespace removed. Capture commands also take an optional `raw` parameter that tells SSHKit whether the command should be executed as is, or to include the auto-wrapping of the ssh_config.
|
281
344
|
|
282
345
|
```ruby
|
283
346
|
capture %Q{wc -l file.txt | cut -d " " -f 1}, into: :num_lines, strip: true, ssh_config: {user: "root"}
|
@@ -323,7 +386,7 @@ DESC
|
|
323
386
|
Downloads the specified file to `to`. An optional `ssh_config` can be specified to configure how the download command gets run, for example specifying the remote host and remote directory to download from. Optional `options` can be specified that get passed down to the underlying sshkit implementation
|
324
387
|
|
325
388
|
```ruby
|
326
|
-
download /home/pblesi/rad_file.txt, to: my_rad_file.txt, ssh_config: {servers: ["host1.prod"]}, options: {log_percent: 10}
|
389
|
+
download '/home/pblesi/rad_file.txt', to: my_rad_file.txt, ssh_config: {servers: ["host1.prod"]}, options: {log_percent: 10}
|
327
390
|
```
|
328
391
|
|
329
392
|
##### Layout
|
@@ -789,7 +852,7 @@ step "Inspect plate" do
|
|
789
852
|
when "carrots"
|
790
853
|
add carrots_book
|
791
854
|
when "peas"
|
792
|
-
system("runbook exec
|
855
|
+
system("runbook exec examples/print_peas.rb")
|
793
856
|
else
|
794
857
|
metadata[:toolbox].warn("Found #{veggie}!")
|
795
858
|
end
|
@@ -864,7 +927,7 @@ Runbook can be extended to add custom functionality.
|
|
864
927
|
|
865
928
|
### Adding New Statements
|
866
929
|
|
867
|
-
In order to add a new statement to your DSL, create a class under `Runbook::Statements` that inherits from `Runbook::Statement`. This statement will be initialized with all arguments passed to the corresponding keyword in the DSL. Remember to also add a corresponding method to runs and views so your new statement can be
|
930
|
+
In order to add a new statement to your DSL, create a class under `Runbook::Statements` that inherits from `Runbook::Statement`. This statement will be initialized with all arguments passed to the corresponding keyword in the DSL. Remember to also add a corresponding method to runs and views so your new statement can be interpreted in each context.
|
868
931
|
|
869
932
|
```ruby
|
870
933
|
module Runbook::Statements
|
@@ -969,6 +1032,22 @@ end
|
|
969
1032
|
|
970
1033
|
When registering a hook, you specify the name of the hook, the type, and the statement or entity to add the hook to. `before` and `after` hooks execute the block before and after executing the entity or statement, respectively. `around` hooks take a block which executes the specified entity or statement. When specifying the class that the hook applies to, you can have the hook apply to all entities by specifying `Runbook::Entity`, all statements by specifying `Runbook::Statement`, or all items by specifying `Object`. Additionally, you can specify any specific entity or statement you would like the hook to apply to.
|
971
1034
|
|
1035
|
+
Hooks are defined on the run or view objects themselves. For example, you would register a hook with `Runbook::Runs::SSHKit` to have the hook be applied to the `SSHKit` run. You would register a hook with the `Runbook::Views::Markdown` view to have hooks apply to this view. If you want to apply a hook to all runs or views, you can use the `Runbook.runs` method or `Runbook.views` method to iterate through the runs or views respectively.
|
1036
|
+
|
1037
|
+
```ruby
|
1038
|
+
Runbook.runs.each do |run|
|
1039
|
+
run.register_hook(
|
1040
|
+
:give_words_of_encouragement,
|
1041
|
+
:before,
|
1042
|
+
Runbook::Entities::Book
|
1043
|
+
) do |object, metadata|
|
1044
|
+
metadata[:toolbox].output("You've got this!")
|
1045
|
+
end
|
1046
|
+
end
|
1047
|
+
```
|
1048
|
+
|
1049
|
+
Hooks can be defined anywhere prior to runbook execution. If defining a hook for only a single runbook, it makes sense to define the hook immediately prior to the runbook definition. If you want a hook to apply to all runbooks in your project, it can be defined in a config file such as the `Runbookfile`. If you want to selectively apply the hook to certain runbooks, it may make sense to define it in a file that can be required by runbooks when it is needed.
|
1050
|
+
|
972
1051
|
When starting at a certain position in the runbook, hooks for any preceding sections and steps will be skipped. After hooks will be run for a parent when starting at a child entity of a parent.
|
973
1052
|
|
974
1053
|
### Adding New Run Behaviors
|
@@ -1080,6 +1159,8 @@ command "echo '\\''I love cheese'\\''"
|
|
1080
1159
|
|
1081
1160
|
Alternatively, if you wish to avoid issues with SSHKit command wrapping, you can specify that your commands be executed in raw form, passed directly as written to the specified host.
|
1082
1161
|
|
1162
|
+
`tmux_command` wraps the input passed to it in single quotes. Therefore any single quotes passed to the `tmux_command` should be escaped using `'\\''`. This issue can manifest itself as part of the command not being echoed to the tmux pane.
|
1163
|
+
|
1083
1164
|
### Specifying env values
|
1084
1165
|
|
1085
1166
|
When specifying the `env` for running commands, if you place curly braces `{}` around the env values, it is required to enclose the arguments in parenthesis `()`, otherwise the following syntax error will result:
|
@@ -1106,13 +1187,64 @@ not as
|
|
1106
1187
|
env {rails_env: :production}
|
1107
1188
|
```
|
1108
1189
|
|
1190
|
+
## FAQ
|
1191
|
+
|
1192
|
+
### Are runbooks compiled?
|
1193
|
+
|
1194
|
+
Yes they are. When you define a runbook, a tree data structure is constructed much like an [abstract syntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree). This is important because you do not have to worry about any side-effects such as executing server commands when this data structure is compiled. Once compiled, choosing either the run or view to execute the runbook object determines what behavior is executed at each node.
|
1195
|
+
|
1196
|
+
### Why are runbooks compiled?
|
1197
|
+
|
1198
|
+
Runbook is designed to minimize and mitigate issues that arise when running operations in production enviroments. One way this is accomplished is by compiling all statements in the runbook before execution is started. Validations and assertions can be made to reduce the likelihood that a runbook will encounter an error in the middle of an operation. In other words, Runbook provides some guarantees about proper formatting of a runbook before any commands execute that could affect live systems.
|
1199
|
+
|
1200
|
+
### Why is my variable/method not set?
|
1201
|
+
|
1202
|
+
Because runbooks are compiled, statements that set values such as `ask`, `capture`, and `capture_all` statements (using the `:into` keyword) only expose their values at runtime. This means any references to these methods or variables (specified with `:into`) can only happen within `ruby_command` blocks which are evaluated at runtime. If an argument to a statement references the values set by these statements, then the statement must be wrapped in a `ruby_command` block. See [Passing State](#passing-state) for specific examples.
|
1203
|
+
|
1204
|
+
### How do I define and call methods within a runbook?
|
1205
|
+
|
1206
|
+
When defining and referencing your own functions in a runbook, functions should be wrapped in a module so they can be referenced globally. For example:
|
1207
|
+
|
1208
|
+
```ruby
|
1209
|
+
module Adder
|
1210
|
+
def add(x, y)
|
1211
|
+
x + y
|
1212
|
+
end
|
1213
|
+
end
|
1214
|
+
|
1215
|
+
Runbook.book "Add Two Numbers" do
|
1216
|
+
step "Add numbers" do
|
1217
|
+
ask "X?", into: :x
|
1218
|
+
ask "Y?", into: :y
|
1219
|
+
|
1220
|
+
ruby_command do |rb_cmd, metadata, run|
|
1221
|
+
metadata[:toolbox].output("Result: #{Adder.add(x, y)}")
|
1222
|
+
end
|
1223
|
+
end
|
1224
|
+
end
|
1225
|
+
```
|
1226
|
+
|
1227
|
+
### Why does my command work on the command line but not in runbook?
|
1228
|
+
|
1229
|
+
There are a number of reasons why a command may work directly on your command line, but not when executed using the `command` statement. Some possible things to try include:
|
1230
|
+
|
1231
|
+
* Print the command with any variables substituted
|
1232
|
+
* Ensure the command works outside of runbook
|
1233
|
+
* Use full paths. The `PATH` environment variable may not be set.
|
1234
|
+
* Check for aliases. Aliases are usually not set for non-interactive shells.
|
1235
|
+
* Check for environment variables. Differences between your shell environment variables and those set for the executing shell may modify command behavior.
|
1236
|
+
* Check for differing behavior between the bourne shell (`sh`) and your shell (usually bash).
|
1237
|
+
* Check that quotes are properly being escaped.
|
1238
|
+
* Simplify the command you are executing and then slowly build it back up
|
1239
|
+
* Check for permissions issues that might cause different execution behavior.
|
1240
|
+
|
1109
1241
|
## Development
|
1110
1242
|
|
1111
1243
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
1112
1244
|
|
1113
1245
|
To install this gem onto your local machine, run `bundle exec rake install`.
|
1114
1246
|
|
1115
|
-
To execute runbook using this repo, run `bundle exec exe/runbook exec
|
1247
|
+
To execute runbook using this repo, run `bundle exec exe/runbook exec examples/layout_runbook.rb`.
|
1116
1248
|
|
1117
1249
|
To release a new version:
|
1118
1250
|
|
data/Rakefile
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require "rspec/core/rake_task"
|
3
3
|
|
4
|
-
RSpec::Core::RakeTask.new(:
|
4
|
+
spec_all = RSpec::Core::RakeTask.new(:spec_all)
|
5
|
+
|
6
|
+
spec_task = RSpec::Core::RakeTask.new(:spec)
|
7
|
+
spec_task.exclude_pattern = "spec/fullstack/**{,/*/**}/*_spec.rb"
|
8
|
+
|
9
|
+
spec_fullstack = RSpec::Core::RakeTask.new(:spec_fullstack)
|
10
|
+
spec_fullstack.pattern = "spec/fullstack/**{,/*/**}/*_spec.rb"
|
5
11
|
|
6
12
|
task :default => :spec
|
data/TODO.md
CHANGED
@@ -31,6 +31,7 @@ Runbook is intended to be a light-weight, minimalistic library. This means every
|
|
31
31
|
## Features Outline
|
32
32
|
|
33
33
|
* [Sudo Raw Command Support](#sudo-raw-command-support): Add support for sudo interaction handler for raw commands
|
34
|
+
* [Tmux Command Quote Escaping](#tmux-command-quote-escaping): Eliminate the need to escape single quotes in tmux commands
|
34
35
|
* [Always-executed Setup Section](#always-executed-setup-section): Add support for a section that is never skipped
|
35
36
|
* [Shortened Tmux Layout Keys](#shortened-tmux-layout-keys): Make tmux layout keys easier
|
36
37
|
* [Add Host Aliases for SSH Config](#add-host-aliases-for-ssh-config): Use `host` and `hosts` instead of `server` and `servers`
|
@@ -39,6 +40,7 @@ Runbook is intended to be a light-weight, minimalistic library. This means every
|
|
39
40
|
* [Runbook Logger](#runbook-logger): A logger for Runbook
|
40
41
|
* [Mutation Command Skipping](#mutation-command-skipping): Allow skipping mutation commands
|
41
42
|
* [Revert Section](#revert-section): A section that can be triggered which will revert the changes of the runbook
|
43
|
+
* [Better Error Formatting](#better-error-formatting): More cleanly format errors to aid in troubleshooting issues
|
42
44
|
* [Runbook Versioning](#runbook-versioning): Specify a version in a runbook to allow for supporting backwards incompatible runbook DSL format changes
|
43
45
|
* [Replace Thor CLI](#replace-thor-cli): Replace Thor for Runbook's CLI with something that can be more easily extended and customized
|
44
46
|
* [Goto Statement](#goto-statement): A statement for jumping to a specific step
|
@@ -55,6 +57,7 @@ Runbook is intended to be a light-weight, minimalistic library. This means every
|
|
55
57
|
* [Guard Runbook](#guard-runbook): Automatically update Runbook views when a runbook is saved
|
56
58
|
* [Rake Task Interface](#rake-task-interface): Execute and view runbooks with rake tasks
|
57
59
|
* [Multiple Commands In Groups](#multiple-commands-in-groups): Execute multiple sshkit commands for a group of servers before moving on to a new group of servers
|
60
|
+
* [Command Line Variables](#command-line-variables): Pass arbitrary variables via the command line
|
58
61
|
* [Yaml Specification](#yaml-specification): Define your runbook using yaml instead of Ruby
|
59
62
|
* [Runbook Web Server](#runbook-web-server): Automatically serve up Runbook views via the web
|
60
63
|
* [Interactive Runbook Launcher](#interactive-runbook-launcher): A CLI launcher to review and execute runbooks
|
@@ -73,6 +76,28 @@ when raw is specified, number (!) above is not executed. Thus pty is not set to
|
|
73
76
|
|
74
77
|
An ideal solution for this would allow the user to set pty true for the command to be executed via ssh_config. Additionally, it would be beneficial to set their own interaction handler. It seems safe to assume that if a user specifies that a command be executed with a pty, then we can set the sudo interaction handler by default if `enable_sudo_prompt` is set, but still allow for the interaction_handler to be overridden.
|
75
78
|
|
79
|
+
#### Tmux Command Quote Escaping
|
80
|
+
|
81
|
+
**Difficulty: 1**, **Desireability: 1**, **Conceptual Completeness: 1**
|
82
|
+
|
83
|
+
Using heredocs and command substitution, it is possible to eliminate the need to escape single quotes passed to tmux_commands. This would go a long way to make this command more intuitive and ensure that the string passed by the user gets executed in the desired pane. This can be accomplished by updating the `send_keys` method to the following:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
def send_keys(command, target)
|
87
|
+
`
|
88
|
+
command=$(cat <<'MAGIC_WORD'
|
89
|
+
#{command}
|
90
|
+
MAGIC_WORD
|
91
|
+
)
|
92
|
+
tmux send-keys -t #{target} #{_pager_escape_sequence} "$command" C-m
|
93
|
+
`
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
The two main concerns for this change are (1) is this implementation as widely supported as the current implementation (in terms of shells and their versions) and (2) This would technically be a backwards incompatible change where we would want to provide a deprecation path.
|
98
|
+
|
99
|
+
Additionally, is it worth pursuing a similar pattern for SSHKit?
|
100
|
+
|
76
101
|
#### Always-executed Setup Section
|
77
102
|
|
78
103
|
**Difficulty: 2**, **Desireability: 1**, **Conceptual Completeness: 2**
|
@@ -127,7 +152,7 @@ It would be nice to be able to skip commands that you know will have an effect o
|
|
127
152
|
|
128
153
|
One way to accomplish this is through a tags implementation where entities and statements have a set of tags, and their behavior is controlled based on these tags. I have implemented a spike of adding tags to entities. One complication of skipping mutation commands is that it is not easy to determine if future commands rely on that command executing. This could reduce the overall benefit of flagging and skipping mutation commands. The skipping logic could be implemented using Runbook's hooks feature.
|
129
154
|
|
130
|
-
Skipping mutation commands for the sake of testing may also be accomplished through the use of mocks. This could a testing library or
|
155
|
+
Skipping mutation commands for the sake of testing may also be accomplished through the use of mocks. This could be a testing library or perhaps a mocking solution built out for Runbook. Implementing a mocking pattern could resolve the downstream dependency issue of skipping mutation commands. A mocking solution could also be implemented using Runbook hooks.
|
131
156
|
|
132
157
|
The mutation command skipping behavior could be controlled via an environment variable. It may be controlled via config or other flag, but this feels too specific to be included in the more general config or run options.
|
133
158
|
|
@@ -141,6 +166,12 @@ This functionality could be achieved by adding a new revert entity which respond
|
|
141
166
|
|
142
167
|
A workaround for this is to simply have a separate revert runbook to execute in the event a rollbock is needed.
|
143
168
|
|
169
|
+
#### Better Error Formatting
|
170
|
+
|
171
|
+
**Difficulty: 2**, **Desireability: 1**, **Conceptual Completeness: 3**
|
172
|
+
|
173
|
+
Right now interpretting errors and stacktraces is difficult for people new to Runbook or Ruby. Rspec does a very good job of presenting cleanly formatted errors and helpful error messages for common problems. See their [exception presenter](https://github.com/rspec/rspec-core/blob/6c5628fc0ea83ecf51f1a4d5e0eb2036819a0dab/lib/rspec/core/formatters/exception_presenter.rb) as an example. It would be helpful to examine Rspec's practices around error formatting and providing more helpful error messages to see what can be emulated for Runbook.
|
174
|
+
|
144
175
|
#### Runbook Versioning
|
145
176
|
|
146
177
|
**Difficulty: 1**, **Desireability: 3**, **Conceptual Completeness: 1**
|
@@ -195,7 +226,7 @@ It would be nice to capture output or status codes from an executed tmux command
|
|
195
226
|
|
196
227
|
**Difficulty: 3**, **Desireability: 2**, **Conceptual Completeness: 2**
|
197
228
|
|
198
|
-
In some instances a step may require that a previous step be executed before it can safely execute. It would be nice if these dependencies could be codified, so when a step is skipped, you can still ensure it is executed when executing a step that depends on it. Tracking which steps have been executed would probably want to exist for the life of the execution of the runbook, so
|
229
|
+
In some instances a step may require that a previous step be executed before it can safely execute. It would be nice if these dependencies could be codified, so when a step is skipped, you can still ensure it is executed when executing a step that depends on it. Tracking which steps have been executed would probably want to exist for the life of the execution of the runbook, so surviving restarts. In an extreme case, executing a runbook may boil down to a rake-like execution. Perhaps it would be possible to make steps independently executable, and then they could be weaved into rake.
|
199
230
|
|
200
231
|
#### Update Command Counts
|
201
232
|
|
@@ -256,6 +287,12 @@ When specifying to execute a command against multiple servers in groups using th
|
|
256
287
|
|
257
288
|
I do not have an idea of how to cleanly accomplish this.
|
258
289
|
|
290
|
+
#### Command Line Variables
|
291
|
+
|
292
|
+
**Difficulty: 1**, **Desireability: 3**, **Conceptual Completeness: 2**
|
293
|
+
|
294
|
+
Add a `vars` command-line option for runtime variables passed through the command line. These arbitrary command-line vars would be stored in the metadata and accessible at runtime (for example in a `ruby_command` block). These can be useful for modifying the runbook's behavior within hooks in conjunction with tags and labels. This functionality already exists however with the use of environment variables. Environment variables are also available at compile time, where as these command line variables are not. In order to make the command line variables available at compile time, they would have to be set in a global context. It is not clear if these values would persist between runs. It may be best practice to save them and overwrite them if re-defined on the command line, but it is not clear if this is intuitive.
|
295
|
+
|
259
296
|
#### Yaml Specification
|
260
297
|
|
261
298
|
**Difficulty: 2**, **Desireability: 2**, **Conceptual Completeness: 1**
|
@@ -0,0 +1,18 @@
|
|
1
|
+
FROM ruby:2.5
|
2
|
+
RUN apt-get update -qq && apt-get install -y build-essential tmux
|
3
|
+
|
4
|
+
RUN mkdir /runbook
|
5
|
+
WORKDIR /runbook
|
6
|
+
|
7
|
+
RUN mkdir /runbook/bin
|
8
|
+
ADD bin/setup /runbook/bin/setup
|
9
|
+
|
10
|
+
ADD runbook.gemspec /runbook/runbook.gemspec
|
11
|
+
ADD Gemfile /runbook/Gemfile
|
12
|
+
|
13
|
+
RUN mkdir -p /runbook/lib/runbook
|
14
|
+
ADD lib/runbook/version.rb /runbook/lib/runbook/version.rb
|
15
|
+
|
16
|
+
RUN bin/setup
|
17
|
+
|
18
|
+
ADD . /runbook
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/lib/runbook.rb
CHANGED
@@ -12,6 +12,8 @@ require "tty-progressbar"
|
|
12
12
|
require "tty-prompt"
|
13
13
|
require "thor/group"
|
14
14
|
|
15
|
+
require "runbook/airbrussh_context"
|
16
|
+
|
15
17
|
require "runbook/configuration"
|
16
18
|
|
17
19
|
require "hacks/ssh_kit"
|
@@ -30,6 +32,7 @@ require "runbook/node"
|
|
30
32
|
require "runbook/entity"
|
31
33
|
require "runbook/entities/book"
|
32
34
|
require "runbook/entities/section"
|
35
|
+
require "runbook/entities/setup"
|
33
36
|
require "runbook/entities/step"
|
34
37
|
|
35
38
|
require "runbook/statement"
|
@@ -74,6 +77,7 @@ require "runbook/extensions/add"
|
|
74
77
|
require "runbook/extensions/description"
|
75
78
|
require "runbook/extensions/shared_variables"
|
76
79
|
require "runbook/extensions/sections"
|
80
|
+
require "runbook/extensions/setup"
|
77
81
|
require "runbook/extensions/ssh_config"
|
78
82
|
require "runbook/extensions/statements"
|
79
83
|
require "runbook/extensions/steps"
|
@@ -86,24 +90,36 @@ ActiveSupport::Inflector.inflections(:en) do |inflect|
|
|
86
90
|
end
|
87
91
|
|
88
92
|
module Runbook
|
89
|
-
def self.book(title, &block)
|
93
|
+
def self.book(title, *tags, labels: {}, &block)
|
90
94
|
Configuration.load_config
|
91
|
-
Entities::Book.new(title).tap do |book|
|
95
|
+
Entities::Book.new(title, tags: tags, labels: labels).tap do |book|
|
92
96
|
book.dsl.instance_eval(&block)
|
93
97
|
register(book)
|
94
98
|
end
|
95
99
|
end
|
96
100
|
|
97
|
-
def self.section(title, &block)
|
101
|
+
def self.section(title, *tags, labels: {}, &block)
|
98
102
|
Configuration.load_config
|
99
|
-
Entities::Section.new(title).tap do |section|
|
103
|
+
Entities::Section.new(title, tags: tags, labels: labels).tap do |section|
|
100
104
|
section.dsl.instance_eval(&block)
|
101
105
|
end
|
102
106
|
end
|
103
107
|
|
104
|
-
def self.
|
108
|
+
def self.setup(*tags, labels: {}, &block)
|
105
109
|
Configuration.load_config
|
106
|
-
Entities::
|
110
|
+
Entities::Setup.new(tags: tags, labels: labels).tap do |setup|
|
111
|
+
setup.dsl.instance_eval(&block)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.step(title=nil, *tags, labels: {}, &block)
|
116
|
+
if title.is_a?(Symbol)
|
117
|
+
tags.unshift(title)
|
118
|
+
title = nil
|
119
|
+
end
|
120
|
+
|
121
|
+
Configuration.load_config
|
122
|
+
Entities::Step.new(title, tags: tags, labels: labels).tap do |step|
|
107
123
|
step.dsl.instance_eval(&block) if block
|
108
124
|
end
|
109
125
|
end
|
@@ -115,4 +131,8 @@ module Runbook
|
|
115
131
|
def self.books
|
116
132
|
@books ||= []
|
117
133
|
end
|
134
|
+
|
135
|
+
def self.runtime_methods
|
136
|
+
@runtime_methods ||= []
|
137
|
+
end
|
118
138
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Runbook
|
2
|
+
class AirbrusshContext
|
3
|
+
attr_reader :history, :current_task_name
|
4
|
+
|
5
|
+
def initialize(config=Airbrussh.configuration)
|
6
|
+
@history = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def register_new_command(command)
|
10
|
+
hist_entry = command.to_s
|
11
|
+
first_execution = history.last != hist_entry
|
12
|
+
history << hist_entry if first_execution
|
13
|
+
first_execution
|
14
|
+
end
|
15
|
+
|
16
|
+
def position(command)
|
17
|
+
history.rindex(command.to_s)
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_current_task_name(task_name)
|
21
|
+
@current_task_name = task_name
|
22
|
+
history.clear
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/runbook/cli.rb
CHANGED
@@ -104,8 +104,23 @@ module Runbook
|
|
104
104
|
unless File.exist?(runbook)
|
105
105
|
raise Thor::InvocationError, "#{cmd}: cannot access #{runbook}: No such file or directory"
|
106
106
|
end
|
107
|
-
|
108
|
-
|
107
|
+
|
108
|
+
begin
|
109
|
+
load(runbook)
|
110
|
+
Runbook.books.last || eval(File.read(runbook))
|
111
|
+
rescue NameError => e
|
112
|
+
if Runbook.runtime_methods.include?(e.name)
|
113
|
+
message = (
|
114
|
+
"Runtime method `#{e.name}` cannot be referenced at " \
|
115
|
+
"compile time. Wrap statements referencing it in a " \
|
116
|
+
"`ruby_command` block in order to invoke the code at " \
|
117
|
+
"runtime."
|
118
|
+
)
|
119
|
+
raise e, message, e.backtrace
|
120
|
+
end
|
121
|
+
|
122
|
+
raise e
|
123
|
+
end
|
109
124
|
end
|
110
125
|
end
|
111
126
|
end
|
@@ -19,6 +19,7 @@ module Runbook
|
|
19
19
|
end
|
20
20
|
|
21
21
|
class Configuration
|
22
|
+
attr_accessor :_airbrussh_context
|
22
23
|
attr_accessor :ssh_kit
|
23
24
|
attr_accessor :enable_sudo_prompt
|
24
25
|
attr_reader :use_same_sudo_password
|
@@ -89,11 +90,16 @@ module Runbook
|
|
89
90
|
|
90
91
|
def initialize
|
91
92
|
self.ssh_kit = SSHKit.config
|
92
|
-
|
93
|
+
formatter = Airbrussh::Formatter.new(
|
93
94
|
$stdout,
|
94
95
|
banner: nil,
|
95
96
|
command_output: true,
|
97
|
+
context: AirbrusshContext,
|
96
98
|
)
|
99
|
+
ssh_kit.output = formatter
|
100
|
+
self._airbrussh_context = formatter.formatters.find do |fmt|
|
101
|
+
fmt.is_a?(Airbrussh::ConsoleFormatter)
|
102
|
+
end.context
|
97
103
|
self.enable_sudo_prompt = true
|
98
104
|
self.use_same_sudo_password = true
|
99
105
|
end
|
data/lib/runbook/entity.rb
CHANGED
@@ -8,10 +8,12 @@ module Runbook
|
|
8
8
|
end
|
9
9
|
|
10
10
|
attr_accessor :parent
|
11
|
-
attr_reader :title, :dsl
|
11
|
+
attr_reader :title, :tags, :labels, :dsl
|
12
12
|
|
13
|
-
def initialize(title, parent: nil)
|
13
|
+
def initialize(title, tags: [], labels: {}, parent: nil)
|
14
14
|
@title = title
|
15
|
+
@tags = tags
|
16
|
+
@labels = labels
|
15
17
|
@parent = parent
|
16
18
|
@dsl = "#{self.class}::DSL".constantize.new(self)
|
17
19
|
end
|
@@ -92,7 +94,8 @@ module Runbook
|
|
92
94
|
|
93
95
|
def _run_metadata(items, item, metadata, index)
|
94
96
|
pos_index = items.select do |item|
|
95
|
-
item.is_a?(Entity)
|
97
|
+
item.is_a?(Entity) &&
|
98
|
+
!item.is_a?(Runbook::Entities::Setup)
|
96
99
|
end.index(item)
|
97
100
|
|
98
101
|
if pos_index
|
@@ -1,8 +1,12 @@
|
|
1
1
|
module Runbook::Extensions
|
2
2
|
module Sections
|
3
3
|
module DSL
|
4
|
-
def section(title, &block)
|
5
|
-
Runbook::Entities::Section.new(
|
4
|
+
def section(title, *tags, labels: {}, &block)
|
5
|
+
Runbook::Entities::Section.new(
|
6
|
+
title,
|
7
|
+
tags: tags,
|
8
|
+
labels: labels,
|
9
|
+
).tap do |section|
|
6
10
|
parent.add(section)
|
7
11
|
section.dsl.instance_eval(&block)
|
8
12
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Runbook::Extensions
|
2
|
+
module Setup
|
3
|
+
module DSL
|
4
|
+
def setup(*tags, labels: {}, &block)
|
5
|
+
Runbook::Entities::Setup.new(
|
6
|
+
tags: tags,
|
7
|
+
labels: labels,
|
8
|
+
).tap do |setup|
|
9
|
+
parent.add(setup)
|
10
|
+
setup.dsl.instance_eval(&block) if block
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Runbook::Entities::Book::DSL.prepend(Setup::DSL)
|
17
|
+
end
|
@@ -71,6 +71,8 @@ module Runbook::Extensions
|
|
71
71
|
Runbook::Entities::Step::DSL.prepend(SSHConfig::DSL)
|
72
72
|
Runbook::Entities::Section.prepend(SSHConfig)
|
73
73
|
Runbook::Entities::Section::DSL.prepend(SSHConfig::DSL)
|
74
|
+
Runbook::Entities::Setup.prepend(SSHConfig)
|
75
|
+
Runbook::Entities::Setup::DSL.prepend(SSHConfig::DSL)
|
74
76
|
Runbook::Entities::Book.prepend(SSHConfig)
|
75
77
|
Runbook::Entities::Book::DSL.prepend(SSHConfig::DSL)
|
76
78
|
end
|
@@ -5,6 +5,10 @@ module Runbook::Extensions
|
|
5
5
|
if (klass = Statements::DSL._statement_class(name))
|
6
6
|
klass.new(*args, &block).tap do |statement|
|
7
7
|
parent.add(statement)
|
8
|
+
|
9
|
+
if statement.respond_to?(:into)
|
10
|
+
Runbook.runtime_methods << statement.into
|
11
|
+
end
|
8
12
|
end
|
9
13
|
else
|
10
14
|
super
|
@@ -22,5 +26,6 @@ module Runbook::Extensions
|
|
22
26
|
end
|
23
27
|
end
|
24
28
|
|
29
|
+
Runbook::Entities::Setup::DSL.prepend(Statements::DSL)
|
25
30
|
Runbook::Entities::Step::DSL.prepend(Statements::DSL)
|
26
31
|
end
|
@@ -1,8 +1,17 @@
|
|
1
1
|
module Runbook::Extensions
|
2
2
|
module Steps
|
3
3
|
module DSL
|
4
|
-
def step(title=nil, &block)
|
5
|
-
|
4
|
+
def step(title=nil, *tags, labels: {}, &block)
|
5
|
+
if title.is_a?(Symbol)
|
6
|
+
tags.unshift(title)
|
7
|
+
title = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
Runbook::Entities::Step.new(
|
11
|
+
title,
|
12
|
+
tags: tags,
|
13
|
+
labels: labels,
|
14
|
+
).tap do |step|
|
6
15
|
parent.add(step)
|
7
16
|
step.dsl.instance_eval(&block) if block
|
8
17
|
end
|
data/lib/runbook/run.rb
CHANGED
@@ -36,6 +36,10 @@ module Runbook
|
|
36
36
|
metadata[:toolbox].output("Section #{metadata[:position]}: #{object.title}\n\n")
|
37
37
|
end
|
38
38
|
|
39
|
+
def runbook__entities__setup(object, metadata)
|
40
|
+
metadata[:toolbox].output("Setup:\n\n")
|
41
|
+
end
|
42
|
+
|
39
43
|
def runbook__entities__step(object, metadata)
|
40
44
|
toolbox = metadata[:toolbox]
|
41
45
|
title = " #{object.title}".rstrip
|
@@ -274,7 +278,8 @@ module Runbook
|
|
274
278
|
:after,
|
275
279
|
Runbook::Statement,
|
276
280
|
) do |object, metadata|
|
277
|
-
if object.parent.is_a?(Runbook::Entities::Step)
|
281
|
+
if object.parent.is_a?(Runbook::Entities::Step) ||
|
282
|
+
object.parent.is_a?(Runbook::Entities::Setup)
|
278
283
|
if object.parent.items.last == object
|
279
284
|
metadata[:toolbox].output("\n")
|
280
285
|
end
|
data/lib/runbook/runs/ssh_kit.rb
CHANGED
@@ -9,6 +9,12 @@ module Runbook::Runs
|
|
9
9
|
module ClassMethods
|
10
10
|
include Runbook::Helpers::SSHKitHelper
|
11
11
|
|
12
|
+
def runbook__entities__step(object, metadata)
|
13
|
+
airbrussh_context = Runbook.configuration._airbrussh_context
|
14
|
+
airbrussh_context.set_current_task_name(object.title)
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
12
18
|
def runbook__statements__assert(object, metadata)
|
13
19
|
cmd_ssh_config = find_ssh_config(object, :cmd_ssh_config)
|
14
20
|
|
data/lib/runbook/util/runbook.rb
CHANGED
data/lib/runbook/version.rb
CHANGED
@@ -13,6 +13,14 @@ module Runbook::Views
|
|
13
13
|
output << "#{heading} #{metadata[:index]+1}. #{object.title}\n\n"
|
14
14
|
end
|
15
15
|
|
16
|
+
def self.runbook__entities__setup(object, output, metadata)
|
17
|
+
output << "[] #{object.title}\n\n"
|
18
|
+
|
19
|
+
ssh_config = find_ssh_config(object)
|
20
|
+
ssh_config_output = render_ssh_config_output(ssh_config)
|
21
|
+
output << "#{ssh_config_output}\n" unless ssh_config_output.empty?
|
22
|
+
end
|
23
|
+
|
16
24
|
def self.runbook__entities__step(object, output, metadata)
|
17
25
|
output << "#{metadata[:index]+1}. [] #{object.title}\n\n"
|
18
26
|
|
@@ -23,7 +31,7 @@ module Runbook::Views
|
|
23
31
|
|
24
32
|
def self.runbook__statements__ask(object, output, metadata)
|
25
33
|
default_msg = object.default ? " (default: #{object.default})" : ""
|
26
|
-
output << " #{object.prompt} into
|
34
|
+
output << " #{object.prompt} into `#{object.into}`#{default_msg}\n\n"
|
27
35
|
end
|
28
36
|
|
29
37
|
def self.runbook__statements__assert(object, output, metadata)
|
@@ -41,11 +49,11 @@ module Runbook::Views
|
|
41
49
|
end
|
42
50
|
|
43
51
|
def self.runbook__statements__capture(object, output, metadata)
|
44
|
-
output << " capture: `#{object.cmd}` into
|
52
|
+
output << " capture: `#{object.cmd}` into `#{object.into}`\n\n"
|
45
53
|
end
|
46
54
|
|
47
55
|
def self.runbook__statements__capture_all(object, output, metadata)
|
48
|
-
output << " capture_all: `#{object.cmd}` into
|
56
|
+
output << " capture_all: `#{object.cmd}` into `#{object.into}`\n\n"
|
49
57
|
end
|
50
58
|
|
51
59
|
def self.runbook__statements__command(object, output, metadata)
|
data/runbook.gemspec
CHANGED
@@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.add_runtime_dependency "method_source", "~> 0.9"
|
36
36
|
spec.add_runtime_dependency "sshkit", "1.16"
|
37
37
|
spec.add_runtime_dependency "sshkit-sudo", "~> 0.1"
|
38
|
-
spec.add_runtime_dependency "airbrussh", "~> 1.
|
38
|
+
spec.add_runtime_dependency "airbrussh", "~> 1.4"
|
39
39
|
spec.add_runtime_dependency "thor", "~> 0.20"
|
40
40
|
spec.add_runtime_dependency "tty-progressbar", "~> 0.14"
|
41
41
|
spec.add_runtime_dependency "tty-prompt", "~> 0.16"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: runbook
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- pblesi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-11-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -78,14 +78,14 @@ dependencies:
|
|
78
78
|
requirements:
|
79
79
|
- - "~>"
|
80
80
|
- !ruby/object:Gem::Version
|
81
|
-
version: '1.
|
81
|
+
version: '1.4'
|
82
82
|
type: :runtime
|
83
83
|
prerelease: false
|
84
84
|
version_requirements: !ruby/object:Gem::Requirement
|
85
85
|
requirements:
|
86
86
|
- - "~>"
|
87
87
|
- !ruby/object:Gem::Version
|
88
|
-
version: '1.
|
88
|
+
version: '1.4'
|
89
89
|
- !ruby/object:Gem::Dependency
|
90
90
|
name: thor
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
@@ -236,6 +236,7 @@ executables:
|
|
236
236
|
extensions: []
|
237
237
|
extra_rdoc_files: []
|
238
238
|
files:
|
239
|
+
- ".dockerignore"
|
239
240
|
- ".gitignore"
|
240
241
|
- ".rspec"
|
241
242
|
- ".ruby-gemset"
|
@@ -251,6 +252,11 @@ files:
|
|
251
252
|
- TODO.md
|
252
253
|
- bin/console
|
253
254
|
- bin/setup
|
255
|
+
- dockerfiles/Dockerfile-runbook
|
256
|
+
- examples/hooks_runbook.rb
|
257
|
+
- examples/layout_runbook.rb
|
258
|
+
- examples/restart_nginx.rb
|
259
|
+
- examples/simple_runbook.rb
|
254
260
|
- exe/runbook
|
255
261
|
- gemfiles/.bundle/config
|
256
262
|
- gemfiles/activesupport_5.gemfile
|
@@ -260,18 +266,21 @@ files:
|
|
260
266
|
- images/runbook_execution_modes.png
|
261
267
|
- lib/hacks/ssh_kit.rb
|
262
268
|
- lib/runbook.rb
|
269
|
+
- lib/runbook/airbrussh_context.rb
|
263
270
|
- lib/runbook/cli.rb
|
264
271
|
- lib/runbook/cli_base.rb
|
265
272
|
- lib/runbook/configuration.rb
|
266
273
|
- lib/runbook/dsl.rb
|
267
274
|
- lib/runbook/entities/book.rb
|
268
275
|
- lib/runbook/entities/section.rb
|
276
|
+
- lib/runbook/entities/setup.rb
|
269
277
|
- lib/runbook/entities/step.rb
|
270
278
|
- lib/runbook/entity.rb
|
271
279
|
- lib/runbook/errors.rb
|
272
280
|
- lib/runbook/extensions/add.rb
|
273
281
|
- lib/runbook/extensions/description.rb
|
274
282
|
- lib/runbook/extensions/sections.rb
|
283
|
+
- lib/runbook/extensions/setup.rb
|
275
284
|
- lib/runbook/extensions/shared_variables.rb
|
276
285
|
- lib/runbook/extensions/ssh_config.rb
|
277
286
|
- lib/runbook/extensions/statements.rb
|
@@ -327,10 +336,6 @@ files:
|
|
327
336
|
- lib/runbook/viewer.rb
|
328
337
|
- lib/runbook/views/markdown.rb
|
329
338
|
- runbook.gemspec
|
330
|
-
- samples/hooks_runbook.rb
|
331
|
-
- samples/layout_runbook.rb
|
332
|
-
- samples/restart_nginx.rb
|
333
|
-
- samples/simple_runbook.rb
|
334
339
|
homepage: https://github.com/braintree/runbook/
|
335
340
|
licenses:
|
336
341
|
- MIT
|