Recently, I’ve been on a search for interactive runbooks. My team has several use-cases for such a tool including:
- repeatable, runnable procedures
- a REST book that can be used to query and validate APIs
- to document complex API integrations
First, a bit about my team. We’re globally-distributed, and maintain a growing number of microservices built mostly using Mulesoft, but with some AWS services, Drupal, and Symfony in the mix. We’ve been transitioning to Mulesoft and API-led strategy from a mostly PHP-based fleet of apps. This means there’s a good deal of PHP knowledge, along with several other languages and technologies (Go, Java, Dataweave, JavaScript, SQL, Python, BASH).
Available Tools
There are a growing number of tools that provide runbook functionality, and there are tradeoffs with each option. Some of the current tools in the runbook category include VS Code Custom Notebooks, Elixir Livebook, Jupyter Notebook, and Emacs org-mode. Below is a table comparing some of the characteristics of each option.
Trait / Tool | VS Code Custom Notebooks | Elixir Livebook | Jupyter Notebook | Emacs org-mode |
---|---|---|---|---|
Supported Tech | Pluggable | Elixir/Erlang | Python | Polyglot |
Format | JSON | Markdown | JSON | Org Markup |
Human Readable | No | Yes | No | Yes |
GitHub Readable | No | Yes | Yes | Yes |
Software | VS Code Insiders + Plugin | Elixir Livebook | Jupyter Notebook | Emacs |
Criteria Breakdown
The criteria that are most important to my team (not necessarily in this order):
- readability as plain text
- ease of install and setup
- minimal friction to adopt
- can execute the technologies we use
Readability as plain text
This means we don’t need to rely on any special technology to use a runbook - we can easily read the runbook and perform the necessary steps to fulfill the requirements of a procedure. Elixir Livebook and Emacs org-mode both meet this criteria.
Ease of install and setup
VS Code Custom Notebooks requires installing the Insiders release (inherent instability), plus a separate plugin for each type of notebook. We would need to develop custom plugins to cover some of our procedures. Custom Notebooks is also heavily reliant on the JavaScript packaging ecosystem, which we are using infrequently these days.
Elixir Livebook requires installing Elixir. We would need to assemble a custom solution for running our automatable tasks.
Jupyter Notebook requires Python and Pip. We would need to assemble a custom solution for running our automatable tasks.
Emacs with org-mode requires installing Emacs.
Minimal friction to adopt
VS Code Custom Notebooks would involve friction around lack of guarantees with stability, the requirement to create custom notebook plugins, and maintaining NPM dependencies.
Elixir Livebook would require learning a new programming language, and creating a custom solution to run our tasks.
Jupyter Notebook would require many team members to learn a new programming language, and we’d need to create a custom solution to run our tasks.
Emacs org-mode would require learning some basic Emacs conventions and maybe a bit of lisp.
Can execute the technologies we use
While any of these options is capable of executing technologies we use, Emacs org-mode is the most capable out of the box. Org-mode is also mature and there is a wide ecosystem of plugins.
Emacs org-mode
Given the current team context, Emacs org-mode seems like a good choice. If we were working more with Python, JavaScript, Elixir, and/or machine learning, one of the other options would rank higher.
Below is an org file that demonstrates a basic runbook implementation with a code block dependency chain.
* Hello World
This is a hello world notebook.
To execute any of the code blocks, place the cursor in the block and type CTRL-C CTRL-C.
** Hello World Setup
The below code block adds shell execution capability to the org babel session (default is emacs-lisp only). This block has been added as a dependency for subsequent code blocks.
#+NAME: setup
#+BEGIN_SRC emacs-lisp
(org-babel-do-load-languages
'org-babel-load-languages
'((shell . t)))
#+END_SRC
#+RESULTS: setup
** Hello World Shell
The below code block prints the current Unix timestamp.
#+NAME: hello-shell
#+BEGIN_SRC shell :var preflight=setup
date +%s
#+END_SRC
#+RESULTS: hello-shell
: 1649002346
** Hello World REST
The below code block executes a cURL command to convert the current Unix timestamp (from the above code block) to a date-time via a public API (contrived, but useful as a demonstration).
#+NAME: hello-rest
#+BEGIN_SRC shell :var shellstamp=hello-shell
curl "https://showcase.api.linx.twenty57.net/UnixTime/fromunix?timestamp=$shellstamp"
#+END_SRC
#+RESULTS: hello-rest
: 2022-04-03 16:16:45
And here’s a link to the same document as a GitHub Gist (note the results sections are not printed but can be viewed in the raw document):