View Source Castle

Hot-code upgrade support for Elixir Releases.

Castle provides build and runtime support for the generation of releases that correctly support hot-code upgrades. This includes:

  • Generation of runtime configuration into sys.config prior to system boot.
  • Creation of the RELEASES file on first boot.
  • Support for appup and relup files.
  • Shell-script support for managing upgrades.

installation

Installation

The package can be installed by adding castle to your list of dependencies in mix.exs:

def deps do
  [
    {:castle, "~> 0.2.0"}
  ]
end

integration

Integration

Castle integrates into the steps of the release assembly process. It requires that the Castle.pre_assemble/1 and Castle.post_assemble/1 functions are placed around the :assemble step, e.g.:

defp releases do
  [
    myapp: [
      include_executables_for: [:unix],
      steps: [&Castle.pre_assemble/1, :assemble, &Castle.post_assemble/1, :tar]
    ]
  ]
end

build-time-support

Build Time Support

The following steps shape the release at build-time:

pre-assembly

Pre-assembly

In the pre-assembly step:

  • The default evaluation of runtime configuration is disabled. Castle will do its own equivalent expansion into sys.config prior to system start, first with runtime.exs (if it exists) and then with any Config Providers.
  • A 'preboot' boot script is created that starts only Castle and its dependencies. This is used only during the aforementioned expansion.

The system is then assembled under the :assemble step as normal.

post-assembly

Post-assembly

In the post-assembly step:

  • The sys.config generated from build-time configuration is copied to build.config.
  • The shell-script in the bin folder is renamed from name to .name, and a new script called name is created in its place. This new script will ensure that the sys.config is correctly generated before the system is started.
  • Any runtime.exs is copied into the version path of the release.
  • The generated name.rel is copied into the releases folder as name-vsn.rel.
  • Any relup file is copied into the version path of the release.

runtime-support

Runtime Support

At runtime, the script in the bin folder will intercept any calls to start, start_iex, daemon and daemon_iex and bring up an ephemeral node to generate sys.config by merging build.config with the results of evaluating runtime.exs and any Config Providers.

Additionally, this ephemeral node will create the RELEASES file if it does not already exist.

release-management

Release Management

The script in the bin folder supports some extra commands to manage upgrades. Releases, in their tarred-gzipped form, should first be copied to the releases subfolder on the target system. The following commands can be used to manage them:

  • releases - Lists the releases on the system and their status. Status can be one of the following:
    • permanent - the release the system will boot into on next restart.
    • current - if it exists, represents the current running release. Will be different from the permanent version if a new release has been installed but not yet committed. If no version is listed as current, the permanent version is the currently running version.
    • old - if it exists, a previously installed version.
    • unpacked - an unpacked version, but not yet installed.
  • unpack <vsn> - Unpacks the release called <name>-<vsn>.tar.gz.
  • install <vsn> - Installs the new release. This makes the release the current one, but not yet the permanent one. Prior to running the relup, Castle generates the version specific sys.config for the new version.
  • commit <vsn> - Makes the specified release the one the permanent one.
  • remove <vsn> - Remove an old version from the filesystem. Any files shared with remaining releases are left untouched.

the-appup-compiler

The Appup Compiler

You are responsible for writing the appup scripts for your application, but Castle will copy the appup into the ebin folder for you. The steps are as follows:

  1. Write a file, in Elixir form, describing the application upgrade. e.g.:
       # You can call the file what you like, e.g. appup.ex, 
       # but you should # keep it away from the compiler paths.
       {
        '0.1.1',
         [
          {'0.1.0', [
            {:update, MyApp.Server, {:advanced, []}}
          ]}
         ],
         [
          {'0.1.0', [
            {:update, MyApp.Server, {:advanced, []}}
          ]}
         ]
       }
    This file will typically be checked in to SCM.
  2. Add the appup file to the Mix project definition in mix.exs and add the :appup compiler.
       # Mix.exs
       def project do
         [
           appup: "appup.ex", # Relative to the project root.
           compilers: Mix.compilers() ++ [:appup]
         ]
       end

relup-generation

Relup Generation

Castle contains a mix task, castle.relup, that simplifies the generation of the relup file. Assuming you have two unpacked releases e.g. 0.1.0 and 0.1.1 and you wish to generate a relup between them:

> mix castle.relup --target myapp/releases/0.1.1/myapp --fromto myapp/releases/0.1.0/myapp

If the generated file is in the project root, it will be copied during post-assembly to the release.