runbook 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -0
- data/CHANGELOG.md +11 -0
- data/README.md +182 -148
- data/bin/console +2 -0
- data/lib/runbook/cli.rb +15 -4
- data/lib/runbook/configuration.rb +4 -0
- data/lib/runbook/{installer.rb → initializer.rb} +3 -3
- data/lib/runbook/run.rb +3 -2
- data/lib/runbook/util/runbook.rb +10 -0
- data/lib/runbook/version.rb +1 -1
- data/runbook.gemspec +7 -7
- metadata +17 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3cb2a40c659a212a9fda6d78d1e94b07ba51625896cd6e4f4a4b6668e42bbc4e
|
4
|
+
data.tar.gz: 065708ff0b3bd93dfdcc35b60730138053e64af9e78768176282f5dc59236b66
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87559cf0bee8e17052a2639033a96481fba11963e50c596f138e64fc72b54328288202bfbe3576da6417eada36f219123ba54d726ab0cc6b28176f31552d21ae
|
7
|
+
data.tar.gz: a0b414a4f0b8fa499cc46362d03d2dfb814cf65a46decbd796ffc45e7ecbd0f68db7a2a89168a3ace032814893ef649fa3a1d36982315f548688f4ce7e470b3c
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,17 @@ This log maintains a list of all substantive changes to Runbook. The log include
|
|
4
4
|
|
5
5
|
## master
|
6
6
|
|
7
|
+
## `v0.14.0` (2019-08-15)
|
8
|
+
|
9
|
+
### Fixes:
|
10
|
+
|
11
|
+
* Relax gem dependencies to be compatible with gems up to the next major version
|
12
|
+
|
13
|
+
### New Features
|
14
|
+
|
15
|
+
* Alias `install` cli command to `init`
|
16
|
+
* Add `Runbook.config` alias for `Runbook.configuration`
|
17
|
+
|
7
18
|
## `v0.13.0` (2019-07-10)
|
8
19
|
|
9
20
|
### Potentially Breaking Changes:
|
data/README.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# Runbook
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/runbook.svg)](https://badge.fury.io/rb/runbook)
|
4
|
+
[![Build Status](https://travis-ci.org/braintree/runbook.svg?branch=master)](https://travis-ci.org/braintree/runbook)
|
5
|
+
|
6
|
+
_See our [blog post](https://medium.com/braintree-product-technology/https-medium-com-braintree-product-technology-runbook-be6f072cfc0d) for the philosophy behind Runbook and an overview of its features._
|
4
7
|
|
5
8
|
Runbook provides a DSL for specifying a series of steps to execute an operation. Once your runbook is specified, you can use it to generate a formatted representation of the book or to execute the runbook interactively. For example, you can export your runbook to markdown or use the same runbook to execute commands on remote servers.
|
6
9
|
|
@@ -26,7 +29,7 @@ Lastly, Runbook provides an extendable interface for augmenting the DSL and defi
|
|
26
29
|
* **Dynamic Control Flow** - Runbooks can start execution at any step and can skip steps based on user input.
|
27
30
|
* **Resumable** - Runbooks save their state at each step. If your runbook encounters an error, you can resume your runbook at the previous step after addressing the error.
|
28
31
|
* **Noop and Auto Modes** - Runbooks can be executed in noop mode. This allows you to see what a runbook will do before it executes. Runbooks can be run in auto mode to eliminate the need for human interaction.
|
29
|
-
* **Execution Lifecycle Hooks** - Runbook provides before, after, around hooks to augment its execution behavior.
|
32
|
+
* **Execution Lifecycle Hooks** - Runbook provides before, after, and around hooks to augment its execution behavior.
|
30
33
|
* **Tmux Integration** - Runbook integrates with [tmux](https://github.com/tmux/tmux). You can define terminal pane layouts and send commands to terminal panes.
|
31
34
|
* **Generators** - Runbook provides commands to generate runbooks, extensions, and runbook projects. You can define your own generators for easy, customized runbook creation.
|
32
35
|
* **Extendable DSL** - Runbook's DSL is designed to be extendable. You can extend its DSL to add your own behavior.
|
@@ -107,9 +110,9 @@ Install the Runbook gem:
|
|
107
110
|
|
108
111
|
$ bundle install
|
109
112
|
|
110
|
-
|
113
|
+
Initialize Runbook in your project:
|
111
114
|
|
112
|
-
$ bundle exec runbook
|
115
|
+
$ bundle exec runbook init
|
113
116
|
|
114
117
|
## Contents
|
115
118
|
|
@@ -137,38 +140,40 @@ Install Runbook into your project:
|
|
137
140
|
* [1.1.2.15 Wait](#wait)
|
138
141
|
* [1.1.2.16 Tmux Layouts](#tmux-layouts)
|
139
142
|
* [1.1.3 Setters](#setters)
|
140
|
-
* [2.
|
141
|
-
* [2.1
|
142
|
-
* [
|
143
|
-
* [3
|
144
|
-
|
145
|
-
* [3.
|
143
|
+
* [2. Working With Runbooks](#working-with-runbooks)
|
144
|
+
* [2.1 Via The Command Line](#via-the-command-line)
|
145
|
+
* [2.2 From Within Your Project](#from-within-your-project)
|
146
|
+
* [2.3 Self-executable](#self-executable)
|
147
|
+
* [3. Configuration](#configuration)
|
148
|
+
* [3.1 Configuration Files](#configuration-files)
|
146
149
|
* [4. Best Practices](#best-practices)
|
147
150
|
* [4.1 Iterative Automation](#iterative-automation)
|
148
151
|
* [4.2 Parameterizing Runbooks](#parameterizing-runbooks)
|
149
|
-
* [4.3
|
150
|
-
* [4.4
|
151
|
-
* [4.5
|
152
|
-
* [4.6
|
153
|
-
* [4.7
|
152
|
+
* [4.3 Passing State](#passing-state)
|
153
|
+
* [4.4 Execution Best Practices](#execution-best-practices)
|
154
|
+
* [4.5 Remote Command Execution](#remote-command-execution)
|
155
|
+
* [4.6 Composing Runbooks](#composing-runbooks)
|
156
|
+
* [4.7 Deep Nesting](#deep-nesting)
|
157
|
+
* [4.8 Load Vs. Eval](#load-vs-eval)
|
154
158
|
* [5. Generators](#generators)
|
155
159
|
* [5.1 Predefined Generators](#predefined-generators)
|
156
160
|
* [5.2 Custom Generators](#custom-generators)
|
157
161
|
* [6. Extending Runbook](#extending-runbook)
|
158
|
-
* [6.1 Adding
|
159
|
-
* [6.2
|
160
|
-
* [6.3
|
161
|
-
* [6.4 Adding
|
162
|
+
* [6.1 Adding New Statements](#adding-new-statements)
|
163
|
+
* [6.2 Adding Run and View Functionality](#adding-run-and-view-functionality)
|
164
|
+
* [6.3 DSL Extensions](#dsl-extensions)
|
165
|
+
* [6.4 Adding Runs and Views](#adding-runs-and-views)
|
162
166
|
* [6.5 Augmenting Functionality With Hooks](#augmenting-functionality-with-hooks)
|
163
167
|
* [6.6 Adding New Run Behaviors](#adding-new-run-behaviors)
|
164
168
|
* [6.7 Adding to Runbook's Run Metadata](#adding-to-runbooks-run-metadata)
|
165
169
|
* [6.8 Adding to Runbook's Configuration](#adding-to-runbooks-configuration)
|
166
|
-
* [7.
|
167
|
-
* [8.
|
168
|
-
* [9.
|
169
|
-
* [10.
|
170
|
-
* [11.
|
171
|
-
* [12.
|
170
|
+
* [7. Testing](#testing)
|
171
|
+
* [8. Known Issues](#known-issues)
|
172
|
+
* [9. Development](#development)
|
173
|
+
* [10. Contributing](#contributing)
|
174
|
+
* [11. Feature Requests](#feature-requests)
|
175
|
+
* [12. License](#license)
|
176
|
+
* [13. Code of Conduct](#code-of-conduct)
|
172
177
|
|
173
178
|
## Runbook Anatomy
|
174
179
|
|
@@ -539,51 +544,10 @@ step do
|
|
539
544
|
end
|
540
545
|
```
|
541
546
|
|
542
|
-
## Configuration
|
543
|
-
|
544
|
-
Runbook is configured using its configuration object. Below is an example of how to configure Runbook.
|
545
|
-
|
546
|
-
```ruby
|
547
|
-
Runbook.configure do |config|
|
548
|
-
config.ssh_kit.umask = "077"
|
549
|
-
config.ssh_kit.default_runner_config = {in: :groups, limit: 5}
|
550
|
-
config.ssh_kit.default_env = {rails_env: :staging}
|
551
|
-
|
552
|
-
config.enable_sudo_prompt = true
|
553
|
-
config.use_same_sudo_password = true
|
554
|
-
end
|
555
|
-
```
|
556
|
-
|
557
|
-
If the `ssh_kit` configuration looks familiar, that's because it's an SSHKit Configuration object. Any configuration options set on `SSHKit.config` can be set on `config.ssh_kit`.
|
558
|
-
|
559
|
-
### Configuration Files
|
560
|
-
|
561
|
-
Runbook loads configuration from a number of predefined files. Runbook will attempt to load configuration from the following locations on startup: `/etc/runbook.conf`, a `Runbookfile` in a parent directory from the current directory, a `.runbook.conf` file in the current user's home directory, a file specified with `--config` on the command line, any configuration specified in a runbook. Runbook will also load configuration from these files in this order of preference, respectively. That is, configuration values specified at the project level (`Runbookfile`) will override configuration values set at the global level (`/etc/runbook.conf`), etc.
|
562
|
-
|
563
547
|
## Working With Runbooks
|
564
548
|
|
565
549
|
You can integrate with Runbook in several different ways. You can create your own project or incorporate Runbook into your existing projects. You can use Runbook via the command line. And you can even create self-executing runbooks.
|
566
550
|
|
567
|
-
### From Within Your Project
|
568
|
-
|
569
|
-
Runbooks can be executed using the `Runbook::Viewer` and `Runbook::Runner` classes.
|
570
|
-
|
571
|
-
#### Executing a runbook using `Runbook::Viewer`
|
572
|
-
|
573
|
-
```ruby
|
574
|
-
Runbook::Viewer.new(book).generate(view: :markdown)
|
575
|
-
```
|
576
|
-
|
577
|
-
In this case book is a `Runbook::Entities::Book` and `:markdown` refers to the specific view type (`Runbook::Views::Markdown`).
|
578
|
-
|
579
|
-
#### Executing a runbook using `Runbook::Runner`
|
580
|
-
|
581
|
-
```ruby
|
582
|
-
Runbook::Runner.new(book).run(run: :ssh_kit, noop: false, auto: false, paranoid: true, start_at: "0")
|
583
|
-
```
|
584
|
-
|
585
|
-
This will execute `book` using the `Runbook::Runs::SSHKit` run type. It will not run the book in `noop` mode. It will not run the book in `auto` mode. It will run the book in `paranoid` mode. And it will start at the beginning of the book. Noop mode runs the book without side-effects outside of printing what it will execute. Auto mode will skip any prompts in the runbook. If there are any required prompts in the runbook (such as the `ask` statement), then the run will fail. Paranoid mode will prompt the user for whether they should continue at every step. Finally `start_at` can be used to skip parts of the runbook or to restart at a certain point in the event of failures, stopping and starting the runbook, etc.
|
586
|
-
|
587
551
|
### Via The Command Line
|
588
552
|
|
589
553
|
Runbook can be used to write stand-alone runbook files that can be executed via the command line. Below is a list of examples of how to use Runbook via the command line.
|
@@ -637,6 +601,26 @@ the runbook at runtime.
|
|
637
601
|
$ HOSTS="appbox{01..30}.prod" ENV="production" runbook exec --start-at 1.2.1 my_runbook.rb
|
638
602
|
```
|
639
603
|
|
604
|
+
### From Within Your Project
|
605
|
+
|
606
|
+
Runbooks can be executed using the `Runbook::Viewer` and `Runbook::Runner` classes. Using these classes, you can invoke runbooks from within your existing codebase. This could be ideal for several reasons. It allows you to maintain a consistent interface with other system tasks such as rake tasks or cap tasks. It allows you to perform setup or sanity check functionality before executing your runbooks. And it allows you to load an environment to be accessed within your runbooks, such as providing access to a canonical list of servers or shared business logic.
|
607
|
+
|
608
|
+
#### Executing a runbook using `Runbook::Viewer`
|
609
|
+
|
610
|
+
```ruby
|
611
|
+
Runbook::Viewer.new(book).generate(view: :markdown)
|
612
|
+
```
|
613
|
+
|
614
|
+
In this case book is a `Runbook::Entities::Book` and `:markdown` refers to the specific view type (`Runbook::Views::Markdown`).
|
615
|
+
|
616
|
+
#### Executing a runbook using `Runbook::Runner`
|
617
|
+
|
618
|
+
```ruby
|
619
|
+
Runbook::Runner.new(book).run(run: :ssh_kit, noop: false, auto: false, paranoid: true, start_at: "0")
|
620
|
+
```
|
621
|
+
|
622
|
+
This will execute `book` using the `Runbook::Runs::SSHKit` run type. It will not run the book in `noop` mode. It will not run the book in `auto` mode. It will run the book in `paranoid` mode. And it will start at the beginning of the book. Noop mode runs the book without side-effects outside of printing what it will execute. Auto mode will skip any prompts in the runbook. If there are any required prompts in the runbook (such as the `ask` statement), then the run will fail. Paranoid mode will prompt the user for whether they should continue at every step. Finally `start_at` can be used to skip parts of the runbook or to restart at a certain point in the event of failures, stopping and starting the runbook, etc.
|
623
|
+
|
640
624
|
### Self-executable
|
641
625
|
|
642
626
|
Runbooks can be written to be self-executable
|
@@ -673,6 +657,27 @@ runbook = Runbook.books.last # Runbooks register themselves to Runbook.books whe
|
|
673
657
|
Runbook::Runner.new(runbook).run(auto: true)
|
674
658
|
```
|
675
659
|
|
660
|
+
## Configuration
|
661
|
+
|
662
|
+
Runbook is configured using its configuration object. Below is an example of how to configure Runbook.
|
663
|
+
|
664
|
+
```ruby
|
665
|
+
Runbook.configure do |config|
|
666
|
+
config.ssh_kit.umask = "077"
|
667
|
+
config.ssh_kit.default_runner_config = {in: :groups, limit: 5}
|
668
|
+
config.ssh_kit.default_env = {rails_env: :staging}
|
669
|
+
|
670
|
+
config.enable_sudo_prompt = true
|
671
|
+
config.use_same_sudo_password = true
|
672
|
+
end
|
673
|
+
```
|
674
|
+
|
675
|
+
If the `ssh_kit` configuration looks familiar, that's because it's an SSHKit Configuration object. Any configuration options set on `SSHKit.config` can be set on `config.ssh_kit`.
|
676
|
+
|
677
|
+
### Configuration Files
|
678
|
+
|
679
|
+
Runbook loads configuration from a number of predefined files. Runbook will attempt to load configuration from the following locations on startup: `/etc/runbook.conf`, a `Runbookfile` in a parent directory from the current directory, a `.runbook.conf` file in the current user's home directory, a file specified with `--config` on the command line, any configuration specified in a runbook. Runbook will also load configuration from these files in this order of preference, respectively. That is, configuration values specified at the project level (`Runbookfile`) will override configuration values set at the global level (`/etc/runbook.conf`), etc.
|
680
|
+
|
676
681
|
## Best Practices
|
677
682
|
|
678
683
|
The following are best practices when developing your own runbooks.
|
@@ -695,12 +700,60 @@ rails_env = `facter rails_env`
|
|
695
700
|
customer_list = File.read("/tmp/customer_list.txt")
|
696
701
|
```
|
697
702
|
|
703
|
+
### Passing State
|
704
|
+
|
705
|
+
Runbook provides a number of different mechanisms for passing state throughout a runbook. For any data that is known at compile time, local variables can be used because Runbooks are lexically scoped.
|
706
|
+
|
707
|
+
```ruby
|
708
|
+
home_planet = "Krypton"
|
709
|
+
Runbook.book "Book Using Local Variables" do
|
710
|
+
hometown = "Smallville"
|
711
|
+
|
712
|
+
section "My Biography" do
|
713
|
+
step do
|
714
|
+
note "Home Planet: #{home_planet}"
|
715
|
+
note "Home Town: #{hometown}"
|
716
|
+
end
|
717
|
+
end
|
718
|
+
end
|
719
|
+
```
|
720
|
+
|
721
|
+
When looking to pass data generated at runtime, for example data from `ruby_command`, `ask`, or `capture` statements, Runbook persists and synchronizes instance variables for these commands.
|
722
|
+
|
723
|
+
```ruby
|
724
|
+
Runbook.book "Book Using Instance Variables" do
|
725
|
+
section "The Transported Man" do
|
726
|
+
step do
|
727
|
+
ask "Who's the greatest magician?", into: :greatest, default: "Alfred Borden"
|
728
|
+
ruby_command { @magician = "Robert Angier" }
|
729
|
+
end
|
730
|
+
|
731
|
+
step do
|
732
|
+
ruby_command {
|
733
|
+
note "Magician: #{@magician}"
|
734
|
+
note "Greatest Magician: #{@greatest}"
|
735
|
+
}
|
736
|
+
end
|
737
|
+
end
|
738
|
+
end
|
739
|
+
```
|
740
|
+
|
741
|
+
Instance variables are only passed between statements such as `ruby_command`. They should not be set on entities such as steps, sections, or books. Instance variables are persisted using `metadata[:repo]`. They are copied to the repo after each statement finishes executing and copied from the repo before each statement starts executing. Because instance variables utilize the repo, they are persisted if the runbook is stopped and restarted at the same step.
|
742
|
+
|
743
|
+
Be careful with your naming of instance variables as it is possible to clobber the step's DSL methods because they share the same namespace.
|
744
|
+
|
698
745
|
### Execution Best Practices
|
699
746
|
|
700
747
|
As a best practice, Runbooks should always be nooped before they are run. This will allow you to catch runtime errors such as using the ask statement when running in auto mode, typos in your runbooks, and to visually confirm what will be executed.
|
701
748
|
|
702
749
|
Additionally, it can be nice to have a generated view of the runbook you are executing to have a good high-level overview of the steps in the runbook.
|
703
750
|
|
751
|
+
### Remote Command Execution
|
752
|
+
|
753
|
+
Runbook uses [SSHKit](https://github.com/capistrano/sshkit) for remote command execution. When specifying `servers`, you are specifying the target host to execute the command. If you want to use a non-standard port or login using a different user than your current user, then you can specify the `server` as `lucy@host1.prod:2345`. Alternatively, you can use an ssh config file such as `~/.ssh/config` to specify the user and port used to ssh to a given host. See [Capistrano's SSH setup instructions](https://capistranorb.com/documentation/getting-started/installation/#ssh) for further support on setting up SSH to execute commands on remote hosts.
|
754
|
+
|
755
|
+
The `user` setter designates the user you will sudo as once sshed to the remote host. Runbook supports password-protected sudo execution. That is, if your server requires a password to execute commands as another user, Runbook will allow you to enter your password when prompted. The `enable_sudo_prompt` configuration value controls this behavior. Enabling the sudo password prompt requires that your commands execute using a tty, which can lead to unexpected behavior when executing certain commands. Enabling `use_same_sudo_password` will use the same password accross different hosts and users instead of re-prompting for each unique user/host combo.
|
756
|
+
|
704
757
|
### Composing Runbooks
|
705
758
|
|
706
759
|
Runbooks can be composed using the `add` keyword. Below is an example of composing a runbook from smaller, reusable components.
|
@@ -720,6 +773,8 @@ Runbook.book "Update configuration" do
|
|
720
773
|
end
|
721
774
|
```
|
722
775
|
|
776
|
+
If you want to parameterize these runbook snippets, you can place them in a ruby function that takes arguments and generates the desired entity or statement. If these snippets set information that is used by the runbook, such as with `capture` statements, it is a good practice to parameterize where the result is stored. This lets the snippet fit different contexts and makes clear what data is being returned from the snippet.
|
777
|
+
|
723
778
|
### Deep Nesting
|
724
779
|
|
725
780
|
Because the Runbook DSL is declarative, it is generally discouraged to develop elaborate nested decision trees. For example, it is discouraged to use the `ask` statement to gather user feedback, branch on this information in a `ruby_command`, and follow completely separate sets of steps. This is because deep nesting eliminates the benefits of the declarative DSL. You can no longer noop the deeply nested structure for example.
|
@@ -759,48 +814,6 @@ runbook = eval(File.read("my_runbook.rb"))
|
|
759
814
|
|
760
815
|
Loading your runbook file is more ideal, but adds slight complexity. This method is prefered because the Ruby mechanism for retrieving source code does not work for code that has been `eval`ed. This means that you will not see `ruby_command` code blocks in view and noop output when using the `eval` method. You will see an "Unable to retrieve source code" message instead.
|
761
816
|
|
762
|
-
### Passing State
|
763
|
-
|
764
|
-
Runbook provides a number of different mechanisms for passing state throughout a runbook. For any data that is known at compile time, local variables can be used because Runbooks are lexically scoped.
|
765
|
-
|
766
|
-
```ruby
|
767
|
-
home_planet = "Krypton"
|
768
|
-
Runbook.book "Book Using Local Variables" do
|
769
|
-
hometown = "Smallville"
|
770
|
-
|
771
|
-
section "My Biography" do
|
772
|
-
step do
|
773
|
-
note "Home Planet: #{home_planet}"
|
774
|
-
note "Home Town: #{hometown}"
|
775
|
-
end
|
776
|
-
end
|
777
|
-
end
|
778
|
-
```
|
779
|
-
|
780
|
-
When looking to pass data generated at runtime, for example data from `ruby_command`, `ask`, or `capture` statements, Runbook persists and synchronizes instance variables for these commands.
|
781
|
-
|
782
|
-
```ruby
|
783
|
-
Runbook.book "Book Using Instance Variables" do
|
784
|
-
section "The Transported Man" do
|
785
|
-
step do
|
786
|
-
ask "Who's the greatest magician?", into: :greatest, default: "Alfred Borden"
|
787
|
-
ruby_command { @magician = "Robert Angier" }
|
788
|
-
end
|
789
|
-
|
790
|
-
step do
|
791
|
-
ruby_command {
|
792
|
-
note "Magician: #{@magician}"
|
793
|
-
note "Greatest Magician: #{@greatest}"
|
794
|
-
}
|
795
|
-
end
|
796
|
-
end
|
797
|
-
end
|
798
|
-
```
|
799
|
-
|
800
|
-
Instance variables are only passed between statements such as `ruby_command`. They should not be set on entities such as steps, sections, or books. Instance variables are persisted using `metadata[:repo]`. They are copied to the repo after each statement finishes executing and copied from the repo before each statement starts executing. Because instance variables utilize the repo, they are persisted if the runbook is stopped and restarted at the same step.
|
801
|
-
|
802
|
-
Be careful with your naming of instance variables as it is possible to clobber the step's DSL methods because they share the same namespace.
|
803
|
-
|
804
817
|
## Generators
|
805
818
|
|
806
819
|
Runbook provides a number of generators accessible via the command line that can be used to generate code for new runbooks, Runbook projects, and Runbook extensions. Additionally, Runbook provides a generator generator so you can define your own custom generators.
|
@@ -849,28 +862,47 @@ Generate your own generator using the `generate generator` command
|
|
849
862
|
|
850
863
|
Runbook can be extended to add custom functionality.
|
851
864
|
|
852
|
-
### Adding
|
865
|
+
### Adding New Statements
|
853
866
|
|
854
|
-
|
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 interpretted in each context.
|
855
868
|
|
856
869
|
```ruby
|
857
|
-
module Runbook::
|
858
|
-
|
859
|
-
|
870
|
+
module Runbook::Statements
|
871
|
+
class Diagram < Runbook::Statement
|
872
|
+
attr_reader :alt_text, :url
|
860
873
|
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
output << "---\n"
|
865
|
-
output << "book:\n"
|
866
|
-
output << " title: #{object.title}\n"
|
874
|
+
def initialize(alt_text, url)
|
875
|
+
@alt_text = alt_text
|
876
|
+
@url = url
|
867
877
|
end
|
878
|
+
end
|
879
|
+
end
|
880
|
+
```
|
868
881
|
|
869
|
-
|
882
|
+
In the above example a keyword `diagram` will be added to the step dsl and its arguments will be used to initialize the Diagram object.
|
883
|
+
|
884
|
+
New statements can be generated using the statement generator.
|
885
|
+
|
886
|
+
$ runbook generate statement diagram --root lib/runbook/extensions
|
887
|
+
|
888
|
+
### Adding Run and View Functionality
|
889
|
+
|
890
|
+
You can add handlers for new statements and entities to your runs and views by prepending the modules with the new desired functionality.
|
891
|
+
|
892
|
+
```ruby
|
893
|
+
module MyRunbook::Extensions
|
894
|
+
module Diagram
|
895
|
+
def self.runbook__entities__diagram(object, output, metadata)
|
896
|
+
output << "![#{object.alt_text}](#{object.url})"
|
897
|
+
end
|
870
898
|
end
|
899
|
+
|
900
|
+
Runbook::Views::Markdown.prepend(Diagram)
|
871
901
|
end
|
872
902
|
```
|
873
903
|
|
904
|
+
If you are not modifying existing methods, you can simply re-open the module to add new methods.
|
905
|
+
|
874
906
|
### DSL Extensions
|
875
907
|
|
876
908
|
You can add arbitrary keywords to your entity DSLs. For example, you could add an alias to Runbook's Book DSL as follows:
|
@@ -889,43 +921,32 @@ module MyRunbook::Extensions
|
|
889
921
|
end
|
890
922
|
```
|
891
923
|
|
892
|
-
|
893
|
-
|
894
|
-
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 interpretted in each context.
|
895
|
-
|
896
|
-
```ruby
|
897
|
-
module Runbook::Statements
|
898
|
-
class Diagram < Runbook::Statement
|
899
|
-
attr_reader :alt_text, :url
|
900
|
-
|
901
|
-
def initialize(alt_text, url)
|
902
|
-
@alt_text = alt_text
|
903
|
-
@url = url
|
904
|
-
end
|
905
|
-
end
|
906
|
-
end
|
907
|
-
```
|
924
|
+
DSL extensions can be generated using the dsl_extension generator.
|
908
925
|
|
909
|
-
|
926
|
+
$ runbook generate dsl_extension aliases --root lib/runbook/extensions
|
910
927
|
|
911
|
-
### Adding
|
928
|
+
### Adding Runs and Views
|
912
929
|
|
913
|
-
You can add
|
930
|
+
You can add new run and view types by defining modules under `Runbook:::Runs` and `Runbook::Views` respectively. They will automatically be accessible from the command line or via the `Runner` and `Viewer` classes. See `lib/runbook/runs/ssh_kit.rb` or `lib/runbook/views/markdown.rb` for examples of how to implement runs and views.
|
914
931
|
|
915
932
|
```ruby
|
916
|
-
module
|
917
|
-
module
|
918
|
-
|
919
|
-
|
933
|
+
module Runbook::Views
|
934
|
+
module Yaml
|
935
|
+
include Runbook::View
|
936
|
+
|
937
|
+
# handler names correspond to the entity or statement class name
|
938
|
+
# Everything is underscored and "::" is replaced by "__"
|
939
|
+
def self.runbook__entities__book(object, output, metadata)
|
940
|
+
output << "---\n"
|
941
|
+
output << "book:\n"
|
942
|
+
output << " title: #{object.title}\n"
|
920
943
|
end
|
921
|
-
end
|
922
944
|
|
923
|
-
|
945
|
+
# Add other handlers here
|
946
|
+
end
|
924
947
|
end
|
925
948
|
```
|
926
949
|
|
927
|
-
If you are not modifying existing methods, you can simply re-open the module to add new methods.
|
928
|
-
|
929
950
|
### Augmenting Functionality With Hooks
|
930
951
|
|
931
952
|
You can add `before`, `after`, or `around` hooks to any statement or entity by defining a hook on a `Run` or `View`.
|
@@ -1024,7 +1045,20 @@ module MyRunbook::Extensions
|
|
1024
1045
|
end
|
1025
1046
|
```
|
1026
1047
|
|
1027
|
-
This will add a `log_level` attribute to Runbook's configuration with a default value of `:info`.
|
1048
|
+
This will add a `log_level` attribute to Runbook's configuration with a default value of `:info`. This configuration value can be accessed via `Runbook.config.log_level`.
|
1049
|
+
|
1050
|
+
## Testing
|
1051
|
+
|
1052
|
+
Runbooks are inherently difficult to test because they are primarily composed of side-effects. That being said, there are a number of strategies you can employ to test your runbooks.
|
1053
|
+
|
1054
|
+
1. Push complex logic to stand-alone Ruby objects that can be tested in isolation
|
1055
|
+
2. Use `TEST` or `DEBUG` environment variables to conditionally disable side-effects during execution
|
1056
|
+
3. Execute your runbooks in staging environments
|
1057
|
+
4. Noop your runbooks to understand what they will be executing before executing them
|
1058
|
+
|
1059
|
+
See Runbook's test suite for more ideas on how to test your runbooks. For example, Runbook uses [aruba](https://github.com/cucumber/aruba) to test Runbook at the CLI level.
|
1060
|
+
|
1061
|
+
Additionally, runbooks should contain their own assertions, sanity checks, monitoring, and alerting to mitigate errors and alert you if intervention is required.
|
1028
1062
|
|
1029
1063
|
## Known Issues
|
1030
1064
|
|
@@ -1094,7 +1128,7 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/braint
|
|
1094
1128
|
|
1095
1129
|
## Feature Requests
|
1096
1130
|
|
1097
|
-
Any feature requests are always welcome and will be considered in accordance with time and need. Additionally, existing feature requests are tracked in TODO.md. If you choose to contribute, your contributions will be greatly appreciated.
|
1131
|
+
Any feature requests are always welcome and will be considered in accordance with time and need. Additionally, existing feature requests are tracked in TODO.md. If you choose to contribute, your contributions will be greatly appreciated. Please reach out before creating any substantial pull requests. A bit of discussion can save a lot of time and increase the chances that your pull request will be accepted.
|
1098
1132
|
|
1099
1133
|
## License
|
1100
1134
|
|
data/bin/console
CHANGED
@@ -6,6 +6,8 @@ require "runbook"
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
8
8
|
|
9
|
+
Runbook::Configuration.load_config
|
10
|
+
|
9
11
|
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
12
|
require "pry"
|
11
13
|
Pry.start
|
data/lib/runbook/cli.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "thor"
|
2
2
|
require "runbook"
|
3
3
|
require "runbook/cli_base"
|
4
|
-
require "runbook/
|
4
|
+
require "runbook/initializer"
|
5
5
|
|
6
6
|
# Needed to load custom generators
|
7
7
|
Runbook::Configuration.load_config
|
@@ -71,15 +71,26 @@ module Runbook
|
|
71
71
|
LONGDESC
|
72
72
|
subcommand "generate", Runbook::Generator
|
73
73
|
|
74
|
-
desc "
|
74
|
+
desc "init", "Initialize Runbook in an existing project"
|
75
75
|
long_desc "Set up Runbook directory structure and Runbookfile in an existing project for executing runbooks."
|
76
|
-
Runbook::
|
76
|
+
Runbook::Initializer.class_options.values.each do |co|
|
77
|
+
method_option co.name, desc: co.description, required: co.required,
|
78
|
+
default: co.default, aliases: co.aliases, type: co.type,
|
79
|
+
banner: co.banner, hide: co.hide
|
80
|
+
end
|
81
|
+
def init
|
82
|
+
invoke(Runbook::Initializer)
|
83
|
+
end
|
84
|
+
|
85
|
+
desc "install", "Install Runbook in an existing project", hide: true
|
86
|
+
Runbook::Initializer.class_options.values.each do |co|
|
77
87
|
method_option co.name, desc: co.description, required: co.required,
|
78
88
|
default: co.default, aliases: co.aliases, type: co.type,
|
79
89
|
banner: co.banner, hide: co.hide
|
80
90
|
end
|
81
91
|
def install
|
82
|
-
|
92
|
+
Runbook.deprecator.deprecation_warning(:install, :init)
|
93
|
+
invoke(Runbook::Initializer)
|
83
94
|
end
|
84
95
|
|
85
96
|
desc "--version", "Print runbook's version"
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Runbook
|
2
|
-
class
|
2
|
+
class Initializer < Thor::Group
|
3
3
|
include Thor::Actions
|
4
4
|
|
5
5
|
source_root File.join(
|
@@ -59,10 +59,10 @@ module Runbook
|
|
59
59
|
_keep_dir(target)
|
60
60
|
end
|
61
61
|
|
62
|
-
def
|
62
|
+
def runbook_initialization_overview
|
63
63
|
msg = [
|
64
64
|
"",
|
65
|
-
"Runbook was successfully
|
65
|
+
"Runbook was successfully initialized.",
|
66
66
|
"Add runbooks to the `runbooks` directory.",
|
67
67
|
"Add shared code to `lib/runbook`.",
|
68
68
|
"Execute runbooks using `bundle exec runbook exec <RUNBOOK_PATH>`",
|
data/lib/runbook/run.rb
CHANGED
@@ -42,7 +42,8 @@ module Runbook
|
|
42
42
|
toolbox.output("Step #{metadata[:position]}:#{title}\n\n")
|
43
43
|
return if metadata[:auto] || metadata[:noop] ||
|
44
44
|
!metadata[:paranoid] || object.title.nil?
|
45
|
-
|
45
|
+
step_choices = _step_choices(object, metadata)
|
46
|
+
continue_result = toolbox.expand("Continue?", step_choices)
|
46
47
|
_handle_continue_result(continue_result, object, metadata)
|
47
48
|
end
|
48
49
|
|
@@ -210,7 +211,7 @@ module Runbook
|
|
210
211
|
object.class.to_s.underscore.gsub("/", "__")
|
211
212
|
end
|
212
213
|
|
213
|
-
def _step_choices
|
214
|
+
def _step_choices(object, metadata)
|
214
215
|
[
|
215
216
|
{key: "c", name: "Continue to execute this step", value: :continue},
|
216
217
|
{key: "s", name: "Skip this step", value: :skip},
|
data/lib/runbook/util/runbook.rb
CHANGED
@@ -15,6 +15,16 @@ module Runbook
|
|
15
15
|
_child_classes(Runbook::Generators)
|
16
16
|
end
|
17
17
|
|
18
|
+
def self.deprecator
|
19
|
+
return @deprecator if @deprecator
|
20
|
+
major_version = Gem::Version.new(Runbook::VERSION).segments[0]
|
21
|
+
next_major_version = major_version + 1
|
22
|
+
@deprecator = ActiveSupport::Deprecation.new(
|
23
|
+
"#{next_major_version}.0",
|
24
|
+
"Runbook"
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
18
28
|
def self._child_classes(mod)
|
19
29
|
mod.constants.map { |const|
|
20
30
|
"#{mod.to_s}::#{const}".constantize
|
data/lib/runbook/version.rb
CHANGED
data/runbook.gemspec
CHANGED
@@ -32,17 +32,17 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.require_paths = ["lib"]
|
33
33
|
|
34
34
|
spec.add_runtime_dependency 'activesupport', '~> 5.0', '>= 5.0.0.1'
|
35
|
-
spec.add_runtime_dependency "method_source", "~> 0.9
|
35
|
+
spec.add_runtime_dependency "method_source", "~> 0.9"
|
36
36
|
spec.add_runtime_dependency "sshkit", "1.16"
|
37
|
-
spec.add_runtime_dependency "sshkit-sudo", "~> 0.1
|
37
|
+
spec.add_runtime_dependency "sshkit-sudo", "~> 0.1"
|
38
38
|
spec.add_runtime_dependency "airbrussh", "~> 1.3"
|
39
|
-
spec.add_runtime_dependency "thor", "~> 0.20
|
40
|
-
spec.add_runtime_dependency "tty-progressbar", "~> 0.14
|
41
|
-
spec.add_runtime_dependency "tty-prompt", "~> 0.16
|
39
|
+
spec.add_runtime_dependency "thor", "~> 0.20"
|
40
|
+
spec.add_runtime_dependency "tty-progressbar", "~> 0.14"
|
41
|
+
spec.add_runtime_dependency "tty-prompt", "~> 0.16"
|
42
42
|
|
43
|
-
spec.add_development_dependency "aruba", "~> 0.14
|
43
|
+
spec.add_development_dependency "aruba", "~> 0.14"
|
44
44
|
spec.add_development_dependency "bundler", "~> 1.15"
|
45
|
-
spec.add_development_dependency "pry", "~> 0.11
|
45
|
+
spec.add_development_dependency "pry", "~> 0.11"
|
46
46
|
spec.add_development_dependency "pry-byebug", "~> 3.6"
|
47
47
|
spec.add_development_dependency "rake", "~> 10.0"
|
48
48
|
spec.add_development_dependency "rspec", "~> 3.0"
|
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.14.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-08-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -36,14 +36,14 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: 0.9
|
39
|
+
version: '0.9'
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: 0.9
|
46
|
+
version: '0.9'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: sshkit
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -64,14 +64,14 @@ dependencies:
|
|
64
64
|
requirements:
|
65
65
|
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version: 0.1
|
67
|
+
version: '0.1'
|
68
68
|
type: :runtime
|
69
69
|
prerelease: false
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
72
|
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version: 0.1
|
74
|
+
version: '0.1'
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
76
|
name: airbrussh
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -92,56 +92,56 @@ dependencies:
|
|
92
92
|
requirements:
|
93
93
|
- - "~>"
|
94
94
|
- !ruby/object:Gem::Version
|
95
|
-
version: 0.20
|
95
|
+
version: '0.20'
|
96
96
|
type: :runtime
|
97
97
|
prerelease: false
|
98
98
|
version_requirements: !ruby/object:Gem::Requirement
|
99
99
|
requirements:
|
100
100
|
- - "~>"
|
101
101
|
- !ruby/object:Gem::Version
|
102
|
-
version: 0.20
|
102
|
+
version: '0.20'
|
103
103
|
- !ruby/object:Gem::Dependency
|
104
104
|
name: tty-progressbar
|
105
105
|
requirement: !ruby/object:Gem::Requirement
|
106
106
|
requirements:
|
107
107
|
- - "~>"
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: 0.14
|
109
|
+
version: '0.14'
|
110
110
|
type: :runtime
|
111
111
|
prerelease: false
|
112
112
|
version_requirements: !ruby/object:Gem::Requirement
|
113
113
|
requirements:
|
114
114
|
- - "~>"
|
115
115
|
- !ruby/object:Gem::Version
|
116
|
-
version: 0.14
|
116
|
+
version: '0.14'
|
117
117
|
- !ruby/object:Gem::Dependency
|
118
118
|
name: tty-prompt
|
119
119
|
requirement: !ruby/object:Gem::Requirement
|
120
120
|
requirements:
|
121
121
|
- - "~>"
|
122
122
|
- !ruby/object:Gem::Version
|
123
|
-
version: 0.16
|
123
|
+
version: '0.16'
|
124
124
|
type: :runtime
|
125
125
|
prerelease: false
|
126
126
|
version_requirements: !ruby/object:Gem::Requirement
|
127
127
|
requirements:
|
128
128
|
- - "~>"
|
129
129
|
- !ruby/object:Gem::Version
|
130
|
-
version: 0.16
|
130
|
+
version: '0.16'
|
131
131
|
- !ruby/object:Gem::Dependency
|
132
132
|
name: aruba
|
133
133
|
requirement: !ruby/object:Gem::Requirement
|
134
134
|
requirements:
|
135
135
|
- - "~>"
|
136
136
|
- !ruby/object:Gem::Version
|
137
|
-
version: 0.14
|
137
|
+
version: '0.14'
|
138
138
|
type: :development
|
139
139
|
prerelease: false
|
140
140
|
version_requirements: !ruby/object:Gem::Requirement
|
141
141
|
requirements:
|
142
142
|
- - "~>"
|
143
143
|
- !ruby/object:Gem::Version
|
144
|
-
version: 0.14
|
144
|
+
version: '0.14'
|
145
145
|
- !ruby/object:Gem::Dependency
|
146
146
|
name: bundler
|
147
147
|
requirement: !ruby/object:Gem::Requirement
|
@@ -162,14 +162,14 @@ dependencies:
|
|
162
162
|
requirements:
|
163
163
|
- - "~>"
|
164
164
|
- !ruby/object:Gem::Version
|
165
|
-
version: 0.11
|
165
|
+
version: '0.11'
|
166
166
|
type: :development
|
167
167
|
prerelease: false
|
168
168
|
version_requirements: !ruby/object:Gem::Requirement
|
169
169
|
requirements:
|
170
170
|
- - "~>"
|
171
171
|
- !ruby/object:Gem::Version
|
172
|
-
version: 0.11
|
172
|
+
version: '0.11'
|
173
173
|
- !ruby/object:Gem::Dependency
|
174
174
|
name: pry-byebug
|
175
175
|
requirement: !ruby/object:Gem::Requirement
|
@@ -278,7 +278,7 @@ files:
|
|
278
278
|
- lib/runbook/helpers/ssh_kit_helper.rb
|
279
279
|
- lib/runbook/helpers/tmux_helper.rb
|
280
280
|
- lib/runbook/hooks.rb
|
281
|
-
- lib/runbook/
|
281
|
+
- lib/runbook/initializer.rb
|
282
282
|
- lib/runbook/node.rb
|
283
283
|
- lib/runbook/run.rb
|
284
284
|
- lib/runbook/runner.rb
|