rebar3 cuttlefish plugin
=====
![Build Status](https://github.com/lrascao/rebar3_scuttler/workflows/CI/badge.svg)
[![Hex version](https://img.shields.io/hexpm/v/rebar3_scuttler.svg "Hex version")](https://hex.pm/packages/rebar3_scuttler)
A rebar3 plugin for [cuttlefish](https://github.com/Kyorai/cuttlefish) schema handling with a slightly different approach than [rebar3_cuttlefish](https://github.com/vernemq/rebar3_cuttlefish).
It departs from the assumption that your Erlang release is already making use of `sys.config` and other `.config` files and you simply want to expose a few specific parameters
in a non-Erlanger `.conf` file for your application users to tweak.
A cuttlefish recap
-----
[Basho's original cuttlefish project](https://github.com/basho/cuttlefish) came up with the idea of allowing non-Erlanger users to tweak any Erlang application's parameters without
having to understand the complicated proplist syntax. A user simply needs to edit a human readable `.conf` file (like `sysctl.conf`, hence the `cuttlefish` name) and run the application.
Requirements
-----
For the plugin to work you'll need to enable [extended start scripts](http://rebar3.org/docs/deployment/releases/#extended-start-script), `rebar3_scuttler` relies on
[hooks](http://rebar3.org/docs/deployment/releases/#hooks) in order to generate the cuttlefish schema `.config` output files.
Integration
-----
In order to integrate and make use of this plugin the following steps are needed:
* Include the `rebar3_scuttler` plugin in your project
* Write a [cuttlefish schema](https://github.com/basho/cuttlefish/wiki/Cuttlefish-for-Erlang-Developers) that exposes the application parameters
you'll allow your users to change.
* Configure the `rebar3_scuttler` plugin
* Add the cuttlefish pre start hook to your release's hooks
* Include the generated `.config` files from your `sys.config`
### Including the plugin
Add the plugin to your project's rebar.config:
```
% this informs rebar3 that the rebar3_scuttler plugin will take over
% the release generation process, this is necessary so that it is able
% to inject the cuttlefish invocation to the pre-start release hook
{project_plugins, [
{rebar3_scuttler,
{git, "https://github.com/lrascao/rebar3_scuttler",
{branch, "master"}}}
]}.
```
### Writing the cuttlefish schema
Basho's original [cuttlefish project documentation](https://github.com/basho/cuttlefish/wiki/Cuttlefish-for-Erlang-Developers) has everything needed.
Here is an example of configuration for the `lhttpc` application:
```
%% @doc Number of default workers for each lhttpc pool
{mapping, "lhttpc.pool_size", "lhttpc.pool_size", [
{default, 10},
{datatype, integer}
]}.
```
Files containing cuttlefish schemas should have the `.schema` extension, you should source control them along with your application
(a typical place to store them is beneath the `priv` dir).
### Configuring the plugin
`rebar3_scuttler` has the following `rebar.config` options:
```
% scuttler plugin opts
{scuttler, [
% this is the human readable .conf file that the users of your application
% will understand and edit in order to change configuration parameters,
% it's location is relative to the root dir of the release
% (ie. alongside bin, releases, etc)
{conf_file, "etc/simple_web_server.conf"},
% a list of cuttlefish schemas to find in your project and it's
% dependencies and the corresponding output file, this is a list of tuples
% that can the following forms:
%
% `{vm_args, OutputFile}`
% A heavily annotated .schema file maintained by the plugin with up to date
% Erlang VM parameters. This vm.args schema is copied to the release directory
% to the `releases/{{release_version}}/erlang.vm.args.schema`
%
% Generated vm.args files can be included from the main vm.args file
% using the `-args_file` parameter
% eg. vm.args
% -cookie somecookie
% -name nodename
% -args_file vm.generated.args
%
% `{Discovery :: auto_discover | string(),
% ReleaseSchemaDir :: string(),
% OutputFile :: string()}`
%
% Schema ::
% auto_discover: finds *.schema files in:
% priv/*.schema
% priv/schema/*.schema
% priv/schemas/*.schema
% schema/*.schema
% schemas/*.schema
% "<dir>": find all *.schema in dir
%
% ReleaseSchemaDir::
% Specifies the location relative to the release dir where the referred schemas will be
% copied to.
%
% OutputFile:
% Specifies the .config or vm.args filename that cuttlefish generates
% out of each schema.
%
% Config files are then intended to be
% included in your sys.config file.
% eg. sys.config
% [
% {myapp, [
% {my_conf1, value}
% ]},
%
% "releases/{{release_version}}/config/generated/user_defined.config"
% ].
%
{schemas, [
{vm_args, "releases/{{release_version}}/vm.generated.args"},
{"priv/schemas", "releases/{{release_version}}/schema",
"releases/{{release_version}}/config/generated/user_defined.config"}
]},
% Specifies where you'd like rebar3_scuttler to generate
% the pre start hook to. This is intended to be then added
% to the extended_start_script_hooks/pre_start relx entry list
% for it to be invoked prior to the release start
% This script will take care of processing `.schema` and `.conf`
% files in order to output `.config` files that you will be able
% to include from your own.
{pre_start_hook, "bin/hooks/pre_start_cuttlefish"}
]}.
```
### Adding the pre start hook
Create or add the `extended_start_script_hooks` entry to `rebar.config` `relx`'s section, if you were already
using it's just a matter of adding another `custom` entry to `pre_start`.
```
% start script hooks
{extended_start_script_hooks, [
{pre_start, [
% besides our own pre start script, we're here adding
% the one that was generated out of rebar3_scuttler,
% this script will pick up any .schema file in share/schema
% and generate a same named .config file in `output_dir`
%
% notice that the name here matches the one we defined above in
% scuttler.pre_start_hook, it's just missing the `bin` prefix because
% start script hooks are relative to the extended start script location.
{custom, "hooks/pre_start_cuttlefish"}
]}
]}
```
### Including generated files
Finally, in your `sys.config` file you can include the generated `.config` file as [per the OTP doc](https://erlang.org/doc/man/config.html).
```
[
{myapp, [
{my_conf1, value}
]},
"releases/{{release_version}}/config/generated/user_defined.config"
].
```
The same can be applied to your `vm.args` file, that is being templated in `relx`'s `overlay` section:
```
{overlay, [
...
{template, "config/vm.args", "releases/{{release_version}}/vm.args"}
...
]}
```
Your developer maintained `vm.args` can now include the runtime generated args file
by using `args_file`.
```
-name nodename
-setcookie cookie
-args_file releases/{{release_version}}/vm.generated.args
```
Copyright and License
-----
Copyright (c) 2020 Luis Rascão
**rebar3_scuttler** source code is licensed under [MIT](LICENSE).