From 7041a1ea7686f228b60062c6784d954933332ea9 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Sat, 14 May 2022 15:12:12 +0200 Subject: [PATCH] Howtos --- src/SUMMARY.md | 16 +- src/operation/howto/define-services.md | 176 ++++++++++++++++++++ src/operation/howto/index.md | 3 + src/operation/howto/manage-user-settings.md | 21 +++ src/operation/howto/reboot-and-power-off.md | 5 + src/operation/howto/restart-services.md | 21 +++ src/operation/howto/schedule-tasks.md | 21 +++ src/operation/howto/suspend.md | 5 + src/operation/scripting.md | 2 +- src/operation/service.md | 4 +- 10 files changed, 262 insertions(+), 12 deletions(-) create mode 100644 src/operation/howto/define-services.md create mode 100644 src/operation/howto/index.md create mode 100644 src/operation/howto/manage-user-settings.md create mode 100644 src/operation/howto/reboot-and-power-off.md create mode 100644 src/operation/howto/restart-services.md create mode 100644 src/operation/howto/schedule-tasks.md create mode 100644 src/operation/howto/suspend.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 46385bc..62e1d71 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -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]() diff --git a/src/operation/howto/define-services.md b/src/operation/howto/define-services.md new file mode 100644 index 0000000..31af4c3 --- /dev/null +++ b/src/operation/howto/define-services.md @@ -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: + + - ``[^interesting-service-name] + - `` + - `` + - `` + - `` + +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: ``. 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 + +``` + +Next, we mark the service as depending on the presence of another assertion, ``. This assertion is managed by the [networking core](../synit-config.md#networking-core). + +```preserves + > +``` + +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 +> +``` + +## 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, `>`. 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 +? >> [ + + ["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 +>> +>> +``` + +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 +? > [ + >> +] +``` + +Here, when an assertion of the form `>` 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 `` 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 `` are defined: + +```preserves +? > [ + ? > [ + ? > [ + >> + $log ! + ] + ] +] +``` + +Reading this inside-out, + + - `run-service` for `qmi-wwan` service names is defined to require a `>` 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 `>` assertion exists. + + - the stanza querying the `mobile-data-apn` user setting is itself only active when + `>` 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. diff --git a/src/operation/howto/index.md b/src/operation/howto/index.md new file mode 100644 index 0000000..bbc0825 --- /dev/null +++ b/src/operation/howto/index.md @@ -0,0 +1,3 @@ +# How-to ... + +The following pages walk through examples of common system administration tasks. diff --git a/src/operation/howto/manage-user-settings.md b/src/operation/howto/manage-user-settings.md new file mode 100644 index 0000000..2cba7f4 --- /dev/null +++ b/src/operation/howto/manage-user-settings.md @@ -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 +! >> +! >> +! >> +``` + +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 '! >>' > $THROCK +sleep 1 +rm -f $THROCK +``` diff --git a/src/operation/howto/reboot-and-power-off.md b/src/operation/howto/reboot-and-power-off.md new file mode 100644 index 0000000..76318aa --- /dev/null +++ b/src/operation/howto/reboot-and-power-off.md @@ -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`...) diff --git a/src/operation/howto/restart-services.md b/src/operation/howto/restart-services.md new file mode 100644 index 0000000..d3db009 --- /dev/null +++ b/src/operation/howto/restart-services.md @@ -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 +! >> +! > +``` + +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 '! >>' > $THROCK +sleep 1 +rm -f $THROCK +``` diff --git a/src/operation/howto/schedule-tasks.md b/src/operation/howto/schedule-tasks.md new file mode 100644 index 0000000..7592de8 --- /dev/null +++ b/src/operation/howto/schedule-tasks.md @@ -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 diff --git a/src/operation/howto/suspend.md b/src/operation/howto/suspend.md new file mode 100644 index 0000000..bc5c80e --- /dev/null +++ b/src/operation/howto/suspend.md @@ -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.) diff --git a/src/operation/scripting.md b/src/operation/scripting.md index 1ee5c27..6db5f25 100644 --- a/src/operation/scripting.md +++ b/src/operation/scripting.md @@ -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 +### Sending a message *SendInstruction* = `! `*ValueExpr* diff --git a/src/operation/service.md b/src/operation/service.md index 0d84fb1..f372a4a 100644 --- a/src/operation/service.md +++ b/src/operation/service.md @@ -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 +### Declare a dependency among services ```preserves-schema ServiceDependency = . @@ -109,7 +109,7 @@ ServiceObject = . A running service publishes zero or more of these. The details of the object vary by service. -### Request a service restart +### Request a service restart ```preserves-schema RestartService = .