Skip to content

Service

Service describes whether a service is running now and whether it starts at boot.

datum: v1alpha1
type: Service

name: nginx

requires:
  - Package[nginx]
  - File[nginx-config]

restartOn:
  - File[nginx-config]

desired:
  state: running
  enabled: true

Target identity is the unit name, taken from name. The only candidate provider is systemd.

Fields

Field Type Required Meaning
state running, stopped Yes Whether the service should be running now.
enabled boolean Yes Whether the service should start at boot.
restartOn list of resource references No Resources whose change should restart the service.
reloadOn list of resource references No Resources whose change should reload the service.

restartOn and reloadOn behave identically except for the operation they ask the provider for, and declaring both for the same resource is an error. A provider whose unit cannot reload fails the action instead of restarting, because substituting a restart for a reload turns a stated requirement into an outage. The reasoning is on the applications page.

Running and enabled are independent

They describe different things and neither implies the other. A service can be running now and disabled at boot, which is a machine that will come back wrong, and it can be enabled and stopped, which is a machine that is currently wrong and will fix itself on restart.

Both are required, not defaulted, because every plausible default is wrong often enough to be a trap. Making them explicit means a repository states its intention for both, and a service that is enabled on purpose but not running says so.

Datum does not create units

There is no create action. A unit exists because a package installed it or because a File resource wrote it, so a Service resource for a unit that does not exist is an error at apply time and not something to be created.

The usual cause is a missing requires on the package providing the unit. It works on a host where the package is already installed and fails on a fresh one, which is the most common shape of dependency mistake.

Observation

Field Reported
exists Whether the unit is known to the init system.
state running or stopped, from whether the unit is active.
enabled Whether the unit is enabled at boot.

Reporting running from the unit being active rather than from a process existing matters, because a unit can be active while its main process is restarting, and a process can exist while the unit has failed.

Units that cannot be enabled

A unit with no [Install] section cannot be enabled or disabled, which systemd reports as a unit file state of static. systemctl enable on one changes nothing and still exits zero. A masked unit is the same question from the other direction.

For those, enabled is reported as unobservable, not as false, so it is left out of the comparison. Reporting it as false would mean a host declaring enabled: true for a static unit drifted on every pass and never converged, and the action that was supposed to fix it did nothing. A difference that cannot be measured is not drift, and this is one of them.

The unit file state is reported as its own observed field, so datum observe says static instead of leaving somebody to wonder why enabled is absent.

Implementation status

Service is implemented by the systemd provider and tested against a booted systemd. Verification checks immediately after acting, which is the first half of the open question below and not an answer to it.

restartOn

When a resource listed in restartOn has a non-none action in the same plan, the service is given an update whose reason names the trigger.

update   Service[nginx]
         reason   File[nginx-config] changed, restartOn matched

This happens whether or not the service's own fields differ. A service that is already running and enabled still restarts when its configuration changes, which is the entire purpose.

Listing a resource in restartOn also orders it before the service, so a file named there does not need repeating in requires. The example at the top of this page lists File[nginx-config] in both because the intent is clearer that way, and the second mention changes nothing.

Verification

After applying, the unit is checked for being active and enabled as required. This is where the difference between a command succeeding and a state being correct is most visible, because systemctl restart returns successfully as soon as the unit is started and a service that exits on a bad configuration file has usually not failed yet at that point.

Open question

Whether verification should wait, and for how long, before deciding a restarted service is healthy is undecided. Checking immediately reports success for a service that dies a second later, and waiting makes every pass slower and introduces a timeout nobody can choose correctly. A unit's own readiness notification is the better signal where it exists, and it does not exist for most units.

Open questions

Units with instances, such as getty@tty1, are not addressed. The name would work as a target identity, and whether anything else about them needs modelling is unexplored.

Providers other than systemd are not planned. Alpine uses OpenRC by default and is in the list of distributions the design targets, so either an OpenRC provider is needed or Alpine support means containers and images where no init system is running at all. That tension is unresolved.