Skip to navigation

Manage an application

This example installs a systemd service with a JSON config file. The config is checked before it replaces the old one, and the service restarts when the config changes. The files are in the repository at examples/service/: main.hcl, config.json, and rivet-example.service. The validator needs Python 3 on the host.

file "directory" {
path = "/var/lib/rivet-example"
ensure = "directory"
}
file "configuration" {
path = "/var/lib/rivet-example/config.json"
source = "config.json"
validate = ["/usr/bin/python3", "-m", "json.tool", "{candidate}"]
meta {
depends_on = [file.directory]
notify = [service.example]
}
}
file "unit" {
path = "/etc/systemd/system/rivet-example.service"
source = "rivet-example.service"
}
service "example" {
name = "rivet-example"
ensure = "running"
enabled = false
masked = false
on_change = "restart"
daemon_reload = "auto"
meta {
timeout = "30s"
}
}

source paths are relative to the configuration directory. Their content is copied into the bundle, so the host doesn’t need the original files.

Compile and apply

On the disposable Ubuntu host from the first walkthrough:

umask 077
rivet facts --local > facts.json
rivet compile examples/service --facts facts.json --out service.bundle
rivet graph service.bundle
Compiled 4 resources, digest a9b6b676f1371cdf4c3857fbb6c895a11fff5c78808493bf19f8c22fe1b6391e
file.directory
file.configuration
file.unit
service.example
file.configuration -> service.example (Notify)
file.directory -> file.configuration (DependsOn)
file.directory -> file.configuration (Expression)
file.unit -> service.example (Action("systemd.daemon_reload.v1"))
sudo rivet apply service.bundle --local
Unchanged file.directory []
Changed file.configuration [ensure]
Changed file.unit [ensure]
Changed service.example [state]
Action: daemon_reload

The directory already exists from the first walkthrough. You can also compile on another machine: copy facts.json there, compile, and copy the bundle back.

What happened

  • Validation before replacement. Rivet wrote the new JSON to a temporary file next to its destination and ran the validator on it, replacing {candidate} with that file’s path. Only after the validator succeeded was the file moved into place. If validation fails, the old file stays untouched.
  • Daemon reload. Because the unit file lives in /etc/systemd/system and the service uses daemon_reload = "auto", Rivet ordered the unit file before the service and ran systemctl daemon-reload once before starting it. That’s the Action: daemon_reload line.
  • No redundant restart. The config change queued a restart, but the service was starting for the first time, so the start satisfied it. Later config changes restart the service.

If the run had been interrupted after the config changed but before the restart, the next apply would still restart the service. See recovery.

Extend it

Add a package for the application’s dependencies, and a user and group for a service account. Add depends_on where order matters, for example a service that needs an installed package. Naming an account in a command’s user field does not by itself order the command after the account. See relationships.