Improved hooks and scripts

* Invoke hooks before and after updating
* Scripts can now be run --before and --after
This commit is contained in:
Chris 2022-03-19 23:22:08 +01:00
parent e77e61d0b0
commit 35f88303fa
2 changed files with 53 additions and 12 deletions

View File

@ -1,7 +1,18 @@
# Fresh: Keeping your docker stacks up to date # Fresh: Keeping your docker stacks up to date
Fresh was written to scratch an itch. It works by querying the respective repositories Fresh was written to scratch an itch. It works by querying the respective repositories
returning for the various manifests in order to determine if the images have been changed. If so
it can do a combination of things:
- Set the exitcode to indicate the freshness, `0` means up-to-date and `1` outdated.
- Pull the updated images with docker-compose, and optionally recreate the containers
with `docker-compose up`.
- Run a script before and after updating, f.ex. to enable maintenance mode or update
permission on volumes.
- Notify webhooks when updating. Currently only Slack and Mattermost are supported.
Fresh is designed to be invoked using cron or systemd timers, and as such provides
a light-weight easy-to-use alternative to more complex toolkits.
## Building ## Building
@ -13,6 +24,8 @@ Build using NoccyLabs Pharlite:
Download the latest version (or build it yourself) and move it into `/usr/bin`. Download the latest version (or build it yourself) and move it into `/usr/bin`.
Go grab it at [https://dev.noccylabs.info/noccy/fresh/releases](https://dev.noccylabs.info/noccy/fresh/releases)
## Usage ## Usage
To check for updates, pull updated images and recreate any containers defined in the To check for updates, pull updated images and recreate any containers defined in the
@ -20,6 +33,15 @@ To check for updates, pull updated images and recreate any containers defined in
$ fresh.phar $ fresh.phar
Specify a directory to chdir into; very useful with cron:
$ fresh.phar --dir /srv/docker/mystack
To invoke scripts or webhooks:
$ fresh.phar --before scripts/sitedown.sh --after scripts/siteup.sh \
--slack https://my.slack.or/mattermost/webhook
For all available options, use the `--help` flag. For all available options, use the `--help` flag.
## Known Issues ## Known Issues
@ -37,6 +59,8 @@ For all available options, use the `--help` flag.
- **What are these hashes?** Fresh grabs the manifest for the image from the registry - **What are these hashes?** Fresh grabs the manifest for the image from the registry
and proceeds to hash a concatenation of all the various build layer hashes. This and proceeds to hash a concatenation of all the various build layer hashes. This
should mean if the image is new but the layers are the same nothing will be updated. should mean if the image is new but the layers are the same nothing will be updated.
- **How do I notify a Mattermost webook?** Mattermost webhooks are compatible with
Slack webhooks, so simply use the `--slack` flag.
## Changes ## Changes
@ -54,3 +78,8 @@ For all available options, use the `--help` flag.
- The `--image` option finally works. - The `--image` option finally works.
- Added a `--write-state`/`-w` option to write updated hashes to the state file. - Added a `--write-state`/`-w` option to write updated hashes to the state file.
- Implemented `--config` and `--config-type`options. - Implemented `--config` and `--config-type`options.
**0.1.3**
- Added a `--before` script hook, to complement the `--after` hook.
- Hooks now invoked both before and after deploy.

View File

@ -30,7 +30,8 @@ class Refresher
], ],
'Hooks' => [ 'Hooks' => [
'slack' => [ null, 'slack:', "Notify a slack webhook when updating", "FRESH_SLACK" ], 'slack' => [ null, 'slack:', "Notify a slack webhook when updating", "FRESH_SLACK" ],
'script' => [ null, 'after:', "Invoke script after updating", "FRESH_AFTER" ], 'script-after' => [ null, 'after:', "Invoke script after updating", "FRESH_AFTER" ],
'script-before' => [ null, 'before:', "Invoke script before updating", "FRESH_BEFORE" ],
], ],
'Config' => [ 'Config' => [
'config' => [ 'c:', 'config:', "Use custom configuration file", "FRESH_CONFIG" ], 'config' => [ 'c:', 'config:', "Use custom configuration file", "FRESH_CONFIG" ],
@ -175,9 +176,11 @@ class Refresher
} }
if ($updated !== null) { if ($updated !== null) {
$this->callHooks($updated); $this->callHooks($updated, 'before');
$this->doUpdate($updated); $this->callScript('before');
$this->callScript(); $this->doUpdate();
$this->callHooks($updated, 'after');
$this->callScript('after');
} }
exit(($updated === null) ? 0 : 1); exit(($updated === null) ? 0 : 1);
@ -362,13 +365,22 @@ class Refresher
} }
} }
private function callHooks(array $updated) private function callHooks(array $updated, string $event)
{ {
$images = []; switch ($event) {
foreach ($updated as $u) { case 'before':
$images[] = sprintf("%s/%s:%s", $u->ref->getRegistry(), $u->ref->getImage(), $u->ref->getTag()); $images = [];
foreach ($updated as $u) {
$images[] = sprintf("%s/%s:%s", $u->ref->getRegistry(), $u->ref->getImage(), $u->ref->getTag());
}
$msg = "Deploying updated containers:\n* ".join("\n* ", $images);
break;
case 'after':
$msg = "Deploy complete";
break;
default:
return;
} }
$msg = "Deploying updated containers:\n* ".join("\n* ", $images);
foreach ($this->hooks as $hook) { foreach ($this->hooks as $hook) {
$hook->sendMessage($msg, []); $hook->sendMessage($msg, []);
@ -376,9 +388,9 @@ class Refresher
} }
private function callScript() private function callScript(string $event)
{ {
$script = $this->options['script']; $script = $this->options["script-{$event}"] ?? null;
if ($script) { if ($script) {
$this->exec($script); $this->exec($script);
} }