Realbook Basics

A Realbook is a fundamentally a shorthand way of specifying an Elixir Module. Anything you could write inside a Kernel.defmodule/2 clause you can write inside of a realbook, and in fact your realbook script will wrapped inside of a defmodule statement.

A realbook (or set of realbooks) executes linearly in a single BEAM process.

Bridging the imperative with declarative

The realbook script itself should be considered a unit of declarative provisioning. In order to bridge imperative code and declarative Realbook provides three pre-imported macros:

  • Realbook.Macros.requires/1 (optional) lets you declare a list of other realbook scripts which must be run prior to the current one to guarantee successful execution.

  • Realbook.Macros.verify/1 (required) specifies instructions which are run prior to execution; if verify passes, the Realbook.Macros.play/1 contents will not be executed. After executing the play contents, verify will be rerun to assess the overall success of the provision.

  • Realbook.Macros.play/1 (required) specifies instructions to actually be run.

Checking variable existence prior to running.

Realbook scripts provide way of sharing configuration variables between scripts. It may also be the case that a script could optionally define a variable to be used by a downstream script. Two pre-imported macros help you share configuration variables:

Realbook modules perform code analysis at compile time, and remember which configuration variables must be set prior to running. If a necessary configuration variable has not been set, then the script will not enter the first verify, and will raise with an error warning that the variable hasn't been set.

To set a variable prior to executing the module, use the Realbook.set/1 function.

Note that Realbook variables are threadsafe, they aren't shared between concurrently running Realbook processes. That also means that you must set them on a process-by-process basis.

Provisioning connections and commands

A process running a realbook script is associated with a provisioning conn. This is a connection value representing the communication between the provisioning host (that is running realbook) and the provisioning target. Use Realbook.connect!/1 (typically outside of the realbook script). See running a realbook.

Once you are in, the following pre-imported commands can be used to perform imperative functions on the target (these should typically be in either the verify or the ):

Note that the bang! versions of the functions will raise if a non-zero return code (failure) is emitted by the program. If you are expecting a non-zero code or need to take decisions based on more detailed information, use the non-bang versions, which will return {:ok, stdout} or {:error, stderr, return_code}. The non-bang functions will still raise if there's a connection error between the host and the target.