Howtos
This commit is contained in:
parent
38bef75093
commit
7041a1ea76
|
@ -21,15 +21,13 @@
|
|||
- [Configuration watcher](./operation/builtin/config-watcher.md)
|
||||
- [Daemons and external programs](./operation/builtin/daemon.md)
|
||||
- [Configuration files and directories](./operation/synit-config.md)
|
||||
- [Defining services and service classes]()
|
||||
- [Scheduling tasks]()
|
||||
- [Timer tolerances]()
|
||||
- [One-off tasks]()
|
||||
- [Repeating tasks]()
|
||||
- [Managing user settings]()
|
||||
- [Restarting services]()
|
||||
- [Rebooting and powering off the machine]()
|
||||
- [Suspending the machine]()
|
||||
- [How-to ...](./operation/howto/index.md)
|
||||
- [Define services and service classes](./operation/howto/define-services.md)
|
||||
- [Restart services](./operation/howto/restart-services.md)
|
||||
- [Schedule one-off or repeating tasks](./operation/howto/schedule-tasks.md)
|
||||
- [Manage user settings](./operation/howto/manage-user-settings.md)
|
||||
- [Reboot and power off the machine](./operation/howto/reboot-and-power-off.md)
|
||||
- [Suspend the machine](./operation/howto/suspend.md)
|
||||
- [Standard tools]()
|
||||
- [preserves-tools]()
|
||||
- [Standard libraries]()
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
# How to define services and service classes
|
||||
|
||||
Synit [services](../builtin/index.md) are started in response to [`run-service`
|
||||
assertions](../service.md#run-service). These, in turn, are eventually asserted by the service
|
||||
dependency tracker in response to [`require-service`
|
||||
assertions](../service.md#require-service), once any declared dependencies have been started.
|
||||
|
||||
So to implement a service, respond to `run-service` records mentioning the service's name.
|
||||
|
||||
There are a number of concepts involved in service definitions:
|
||||
|
||||
- **Service name**. A unique identifier for a service instance.
|
||||
|
||||
- **Service implementation**. Code that responds to `run-service` requests for a service
|
||||
instance to start running, implementing the service's ongoing behaviour.
|
||||
|
||||
- **Service class**. A parameterized collection of services sharing a common parameterized
|
||||
implementation.
|
||||
|
||||
A service may be an instance of a service *class* (a parameterized family of services) or may
|
||||
be a simple service that is the only instance of its class. Service dependencies can be
|
||||
statically-declared or dynamically-computed.
|
||||
|
||||
A service's implementation may be [external](../builtin/daemon.md), running as a subprocess
|
||||
managed by `syndicate-server`; internal, backed by code that is part of the `syndicate-server`
|
||||
process itself; or user-defined, implemented via user-supplied code written in the
|
||||
[configuration language](../scripting.md) or as other actor programs connected somehow to the
|
||||
system bus.
|
||||
|
||||
An external service may involve a long-running process (a "daemon"; what [`s6-rc`][s6-rc] calls
|
||||
a "longrun"), or may involve a short-lived activity that, at startup or shutdown, modifies
|
||||
aspects of overall system state outside the purview of the supervision tree (what
|
||||
[`s6-rc`][s6-rc] calls a "one-shot").
|
||||
|
||||
[s6-rc]: https://skarnet.org/software/s6-rc/overview.html
|
||||
|
||||
## Service names
|
||||
|
||||
Every service is identified with its *name*. A service name can be any
|
||||
[Preserves](../../glossary.md#preserves) value. A simple symbol may suffice, but records and
|
||||
dictionaries are often useful in giving *structure* to service names.
|
||||
|
||||
Here are a few example service names:
|
||||
|
||||
- `<config-watcher "/foo/bar" $.>`[^interesting-service-name]
|
||||
- `<daemon docker>`
|
||||
- `<milestone network>`
|
||||
- `<qmi-wwan "/dev/cdc-wdm0">`
|
||||
- `<udhcpc "eth0">`
|
||||
|
||||
The first two invoke service behaviours that are [built-in to
|
||||
`syndicate-server`](../builtin/index.md); the last three are user-defined service names.
|
||||
|
||||
## Defining a simple external service
|
||||
|
||||
As an example of a simple external service, take the `ntpd` daemon. The following assertions
|
||||
placed in the configuration file `/etc/syndicate/services/ntpd.pr` cause `ntpd` to be run as
|
||||
part of the [Synit services layer](../synit-config.md#loading-of-core-and-services-layers).
|
||||
|
||||
First, we choose the service name: `<daemon ntpd>`. The name is a `daemon` record, marking it
|
||||
as a supervised [external service](../builtin/daemon.md). Having chosen a name, and chosen to
|
||||
use the external service supervision mechanism to run the service, we make our first assertion,
|
||||
which defines the program to be launched:
|
||||
|
||||
```preserves
|
||||
<daemon ntpd "ntpd -d -n -p pool.ntp.org">
|
||||
```
|
||||
|
||||
Next, we mark the service as depending on the presence of another assertion, `<default-route
|
||||
ipv4>`. This assertion is managed by the [networking core](../synit-config.md#networking-core).
|
||||
|
||||
```preserves
|
||||
<depends-on <daemon ntpd> <default-route ipv4>>
|
||||
```
|
||||
|
||||
These two assertions are, together, the total of the *definition* of the service.
|
||||
|
||||
However, without a final `require-service` assertion, the service will not be *activated*. By
|
||||
[requiring the service](../service.md#require-service), we connect the service definition into
|
||||
the system dependency tree, enabling actual loading and activation of the service.
|
||||
|
||||
```preserves
|
||||
<require-service <daemon ntpd>>
|
||||
```
|
||||
|
||||
## Defining a service class
|
||||
|
||||
The following stanza (actually part of [the networking
|
||||
core](../synit-config.md#networking-core)) waits for `run-service` assertions matching a
|
||||
*family* of service names, `<daemon <udhcpc `*ifname*`>>`. When it sees one, it computes the
|
||||
specification for the corresponding command-line, on the fly, substituting the value of the
|
||||
*ifname* binding in the correct places (once in the service name and once in the command-line
|
||||
specification).
|
||||
|
||||
```preserves
|
||||
? <run-service <daemon <udhcpc ?ifname>>> [
|
||||
<daemon
|
||||
<udhcpc $ifname>
|
||||
["udhcpc" "-i" $ifname "-fR" "-s" "/usr/lib/synit/udhcpc.script"]
|
||||
>
|
||||
]
|
||||
```
|
||||
|
||||
This suffices to define the service. To instantiate it, we may either manually provide
|
||||
assertions mentioning the interfaces we care about,
|
||||
|
||||
```preserves
|
||||
<require-service <daemon <udhcpc "eth0">>>
|
||||
<require-service <daemon <udhcpc "wlan0">>>
|
||||
```
|
||||
|
||||
or, as actually implemented in the networking core (in `network.pr` lines
|
||||
[13–15](https://git.syndicate-lang.org/synit/synit/src/commit/a43247fc96e906fbfdeb6e9a6e6d6e9a2f35f9e8/packaging/packages/synit-config/files/etc/syndicate/services/network.pr#L13-L15)
|
||||
and
|
||||
[42–47](https://git.syndicate-lang.org/synit/synit/src/commit/a43247fc96e906fbfdeb6e9a6e6d6e9a2f35f9e8/packaging/packages/synit-config/files/etc/syndicate/services/network.pr#L42-L47)),
|
||||
we may respond to assertions placed in the dataspace by [a daemon,
|
||||
`interface-monitor`](https://git.syndicate-lang.org/synit/synit/src/commit/e9bf91e9de0d2724df15835fc6ea33cbdf23b564/packaging/packages/synit-config/files/usr/lib/synit/python/synit/daemon/interface_monitor.py),
|
||||
whose role is to reflect [AF_NETLINK](https://en.wikipedia.org/wiki/Netlink) events into
|
||||
assertions:
|
||||
|
||||
```preserves
|
||||
? <configure-interface ?ifname <dhcp>> [
|
||||
<require-service <daemon <udhcpc $ifname>>>
|
||||
]
|
||||
```
|
||||
|
||||
Here, when an assertion of the form `<configure-interface `*ifname*` <dhcp>>` appears in the
|
||||
dataspace, we react by asserting a `require-service` record that in turn eventually triggers
|
||||
assertion of a matching `run-service`, which then in turn results in invocation of the `udhcpc`
|
||||
command-line we specified above.
|
||||
|
||||
## Defining non-`daemon` services; reacting to user settings
|
||||
|
||||
Only service names of the form `<daemon `*name*`>` are backed by [external service
|
||||
supervisor](../builtin/daemon.md) code. Other service name schemes have other implementations.
|
||||
In particualr, user-defined service name schemes are possible and useful.
|
||||
|
||||
For example, in the [configuration relating to setup of mobile data
|
||||
interfaces](../synit-config.md#wifi--mobile-data), service names of the form `<qmi-wwan
|
||||
`*devicePath*`>` are defined:
|
||||
|
||||
```preserves
|
||||
? <user-setting <mobile-data-enabled>> [
|
||||
? <user-setting <mobile-data-apn ?apn>> [
|
||||
? <run-service <qmi-wwan ?dev>> [
|
||||
<require-service <daemon <qmi-wwan-manager $dev $apn>>>
|
||||
$log ! <log "-" { line: "starting wwan manager", dev: $dev, apn: $apn }>
|
||||
]
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
Reading this inside-out,
|
||||
|
||||
- `run-service` for `qmi-wwan` service names is defined to require a `<daemon
|
||||
<qmi-wwan-manager `*deviceName APN*`>>` service, defined elsewhere; in addition, when a
|
||||
`run-service` assertion appears, a log message is produced.
|
||||
|
||||
- the stanza reacting to `run-service` is only active when some `<user-setting
|
||||
<mobile-data-apn `*APN*`>>` assertion exists.
|
||||
|
||||
- the stanza querying the `mobile-data-apn` user setting is itself only active when
|
||||
`<user-setting <mobile-data-enabled>>` has been asserted.
|
||||
|
||||
In sum, this means that even if a `qmi-wwan` service is requested and activated, nothing will
|
||||
happen until the user enables mobile data and selects an
|
||||
[APN](https://en.wikipedia.org/wiki/Access_Point_Name). If the user later disables mobile data,
|
||||
the `qmi-wwan` implementation will automatically be retracted, and the corresponding
|
||||
`qmi-wwan-manager` service terminated.
|
||||
|
||||
---
|
||||
|
||||
[^interesting-service-name]: This first service name example is interesting because it includes
|
||||
an [embedded capability reference](../../glossary.md#reference) using the `$.` syntax from
|
||||
the [scripting language](../scripting.md) to denote the active scripting language
|
||||
environment dictionary.
|
|
@ -0,0 +1,3 @@
|
|||
# How-to ...
|
||||
|
||||
The following pages walk through examples of common system administration tasks.
|
|
@ -0,0 +1,21 @@
|
|||
# How to manage user settings
|
||||
|
||||
Send a [`user-settings-command`]() message containing an `assert` or `retract` record
|
||||
containing the setting assertion to add or remove. Use the [`!` operator of the configuration
|
||||
language](../scripting.md#SendInstruction) to send a message (as opposed to make an assertion):
|
||||
|
||||
```preserves
|
||||
! <user-settings-command <assert <mobile-data-enabled>>>
|
||||
! <user-settings-command <assert <mobile-data-apn "internet">>>
|
||||
! <user-settings-command <retract <mobile-data-enabled>>>
|
||||
```
|
||||
|
||||
In future, a command-line tool for sending such messages will be provided; for now, create
|
||||
temporary configuration language scripts in `/run/etc/syndicate/services`:
|
||||
|
||||
```shell
|
||||
THROCK=/run/etc/syndicate/services/throck.pr
|
||||
echo '! <user-settings-command <assert <mobile-data-enabled>>>' > $THROCK
|
||||
sleep 1
|
||||
rm -f $THROCK
|
||||
```
|
|
@ -0,0 +1,5 @@
|
|||
# How to reboot and power off the machine
|
||||
|
||||
(TODO. Not yet implemented: eventually, `synit-pid1` will respond to messages/assertions from
|
||||
the dataspace, implementing the necessary coordination for a graceful shutdown procedure. For
|
||||
now, `sync` three times, sleep a bit, and `reboot -f` or `poweroff -f`...)
|
|
@ -0,0 +1,21 @@
|
|||
# How to restart services
|
||||
|
||||
Send a [`restart-service`](../service.md#restart-service) message mentioning the [service
|
||||
name](./define-services.md#service-names) of the service to restart. Use the [`!` operator of
|
||||
the configuration language](../scripting.md#SendInstruction) to send a message (as opposed to
|
||||
make an assertion):
|
||||
|
||||
```preserves
|
||||
! <restart-service <daemon <wifi-daemon "wlan0">>>
|
||||
! <restart-service <daemon user-settings-daemon>>
|
||||
```
|
||||
|
||||
In future, a command-line tool for sending messages to a system dataspace will be provided; for
|
||||
now, create temporary configuration language scripts in `/run/etc/syndicate/services`:
|
||||
|
||||
```shell
|
||||
THROCK=/run/etc/syndicate/services/throck.pr
|
||||
echo '! <restart-service <daemon <wifi-daemon "wlan0">>>' > $THROCK
|
||||
sleep 1
|
||||
rm -f $THROCK
|
||||
```
|
|
@ -0,0 +1,21 @@
|
|||
# How to schedule one-off or repeating tasks
|
||||
|
||||
(TODO. Not yet implemented: a cron-like program will eventually respond to assertions demanding
|
||||
periodic or delayed execution of tasks (likely expressed as assertions, making it more of a
|
||||
delayed-or-periodic-assertion-producing program).)
|
||||
|
||||
## Timer tolerances
|
||||
|
||||
Apple has come up with the useful idea of a [timer tolerance][apple-timer-tolerance],
|
||||
applicable to both repeating and one-off timers. In [their
|
||||
documentation][apple-timer-tolerance], they write:
|
||||
|
||||
> The timer may fire at any time between its scheduled fire date and the scheduled fire date
|
||||
> plus the tolerance. [...] A general rule, set the tolerance to at least 10% of the interval
|
||||
> [...] Even a small amount of tolerance has significant positive impact on the power usage of
|
||||
> your application.
|
||||
|
||||
[apple-timer-tolerance]: https://developer.apple.com/documentation/foundation/timer#1667624
|
||||
|
||||
## One-off tasks
|
||||
## Repeating tasks
|
|
@ -0,0 +1,5 @@
|
|||
# How to suspend the machine
|
||||
|
||||
(TODO. Not yet implemented: eventually, assertions in the dataspace will control the desired
|
||||
suspend state, and reactive stanzas will allow responses to any kind of ambient conditions to
|
||||
include changes in the suspend state.)
|
|
@ -127,7 +127,7 @@ active target register.
|
|||
As a convenient shorthand, the compiler also interprets every Preserves record or dictionary in
|
||||
*Instruction* position as denoting a *ValueExpr* to be used to produce a value to be asserted.
|
||||
|
||||
### Sending a message
|
||||
### <span id="SendInstruction"></span>Sending a message
|
||||
|
||||
*SendInstruction* = `! `*ValueExpr*
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ dependencies.
|
|||
The built-in handler for `require-service` assertions will assert `run-service` automatically
|
||||
once all dependencies have been satisfied.
|
||||
|
||||
### Declare a dependency among services
|
||||
### <span id="depends-on"></span>Declare a dependency among services
|
||||
|
||||
```preserves-schema
|
||||
ServiceDependency = <depends-on @depender any @dependee ServiceState>.
|
||||
|
@ -109,7 +109,7 @@ ServiceObject = <service-object @serviceName any @object any>.
|
|||
|
||||
A running service publishes zero or more of these. The details of the object vary by service.
|
||||
|
||||
### Request a service restart
|
||||
### <span id="restart-service"></span>Request a service restart
|
||||
|
||||
```preserves-schema
|
||||
RestartService = <restart-service @serviceName any>.
|
||||
|
|
Loading…
Reference in New Issue