Introduction to Realbook

Realbook is a simple, imperative DSL that helps you provision and set up linux-based servers.

If you have a linux based machine, you can use Realbook to make sure that the required software and soft assets are properly installed and configured on this machine. Because Realbook uses the BEAM under the hood, it is possible to provision multiple machines concurrently, which is a desirable feature for on-metal deployments.

Realbook is also useful for other deployments (like VMs), since it can produce reproducible environments (potentially across time) via its self-validation scheme.

Example

Amy wants to provision an Ubuntu 18.04 machine that will serve as a DHCP server. To do this, she creates some realbook scripts in her ~/realbook-scripts directory.

install_dhcp.exs

verify do
  # verifies that isc-dhcp-server software exists by checking
  # the existence of the software in the apt repository db
  run!("apt list isc-dhcp-server", tty: true, stdout: :stream) =~ "installed"
end

play do
  sudo_run! "apt-get install isc-dhcp-server"
end

configure_dhcp.exs

requires "install_dhcp"

@dhcp_conf_path "/etc/dhcp/dhcpd.conf"

# templates the /etc/dhcp/dhcpd.conf file to match the specifications
# for isc-dhcp-server.  A more advanced example would use EEx templates
# to achieve this.
def dhcpd_conf do
  """
  default-lease-time 600;
  max-lease-time 7200;
  option subnet-mask 255.255.255.0;
  option broadcast-address #{get :broadcast};
  option routers #{get :router};
  # give the client either cloudflare or google DNS
  option domain-name-servers 1.1.1.1 8.8.8.8;
  option domain-name "amysdomain.local";

  subnet #{get :subnet} netmask 255.255.255.0 {
  range #{get :range_start} #{get :range_end};
  }
  """
end

verify do
  # checks that the system configuration matches the supplied
  # configuration by comparing sha256sum.  By doing this we
  # can come back to the system later and use the same script
  # to overwrite the configuration settings if they should change.
  shasum = :sha256
  |> :crypto.hash(dhcpd_conf())
  |> Base.encode16(case: :lower)

  run!("sha256sum #{@dhcp_conf_path}") =~ shasum
end

play do
  sudo_run! "rm -rf #{@dhcp_conf_path}"
  sudo_send! dhcpd_conf(), @dhcp_conf_path
end

enable_dhcp.exs

requires "configure_dhcp"

verify do
  # try, five times, over 5 seconds, to see if the dhcp server
  # is active.  This is necessary because the systemctl command
  # performs some things asynchronously.
  wait_till count: 5 do
    run! "systemctl is-enabled --quiet isc-dhcp-server"
  end
end

play do
  sudo_run! "systemctl enable isc-dhcp-server"
end

reset_dhcp.exs

requires "reset_dhcp"

# always reset the dhcp server (this is for the case when we didn't
# have to enable the dhcp server)
verify false

play do
  sudo_run! "systemctl restart isc-dhcp-server"
end

Running the realbooks

Having defined the realbooks, Amy now needs to execute them on her remote server. In this example, she will simply use the iex shell to achieve this.

iex> Application.put_env(:realbook, :script_dir, "~/realbook-scripts")
iex> Realbook.connect!(:ssh, host: "amys.host.ip", user: "admin", identity: "~/my_key.pem")
iex> Realbook.set(
       broadcast: "192.168.1.255",
       router: "192.168.1.1",
       subnet: "192.168.1.0",
       range_start: "192.168.1.10",
       range_end: "192.168.1.64")
iex> import Realbook
iex> ~B"requires ~w(install_dhcp configure_dhcp enable_dhcp reset_dhcp)"

If Amy had forgotten any of the required variables, then the script would not run. If Amy would like to change the settings later, this particular script's strategy lets her simply input different settings in the Realbook.set command and it will redo the dhcp configuration.