Describe builtin services

This commit is contained in:
Tony Garnock-Jones 2022-03-08 06:58:12 +01:00
parent 5a89f30613
commit dd67e2950e
7 changed files with 299 additions and 25 deletions

View File

@ -1,7 +1,30 @@
# Configuration watcher
- Any number of [**configuration watchers**](./config-watcher.md) may be created to monitor
directories for changes to files written using the [server scripting
language](../scripting.md). (These can also be started from the `syndicate-server`
command-line with `-c` options.)
- Relevant schema: [[syndicate-rs]/syndicate-server/protocols/schemas/internalServices.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-rs/src/branch/main/syndicate-server/protocols/schemas/internalServices.prs)
Assertions [requiring](../service.md#require-service) a service with name matching
`ConfigWatcher` cause the server to start a configuration watcher service monitoring files in
and subdirectories of the given `path` for changes:
```preserves-schema
ConfigWatcher = <config-watcher @path string @env ConfigEnv>.
ConfigEnv = { symbol: any ...:... }.
```
The `path` may name either a file or directory. Any time the configuration watcher finds a file
matching the glob `*.pr` within the tree rooted at `path`, it loads the file. Each time a
`*.pr` file is loaded, it is interpreted as a [configuration scripting
language](../scripting.md) program, with a copy of `env` as the "initial environment" for the
script.
Whenever a change to a `*.pr` file is detected, the configuration watcher reloads the file,
discarding previous internal state related to the file.
Note that a quirk of the config language requires that there exist an entry in `env` with key
the symbol `config` and value an [entity reference](../../glossary.md#reference) (usually
denoting a [dataspace entity](../../glossary.md#dataspace)). However, the `config` entry need
not be the same as the surrounding `$config`! A useful pattern is to set up a new
`ConfigWatcher` with `env` containing a `config` binding pointing to an
[attenuated](../../glossary.md#attenuation) reference to the current `config` dataspace, or
even [an entirely fresh dataspace](../scripting.md#expr:dataspace) created specifically for the
task.

View File

@ -1,4 +1,181 @@
# Process supervision and management
- Finally, [**external programs**](./daemon.md) can be started, either as long-lived "daemon"
services or as one-off scripts.
- Relevant schema: [[syndicate-rs]/syndicate-server/protocols/schemas/externalServices.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-rs/src/branch/main/syndicate-server/protocols/schemas/externalServices.prs)
Assertions [requiring](../service.md#require-service) a service with name matching
`DaemonService` cause the server to start a subprocess-based service:
```preserves-schema
DaemonService = <daemon @id any> .
```
Each `daemon` service can have zero or more subprocesses associated with it. Subprocesses can
be long-lived services or short-lived, system-state-changing programs or scripts.
## Adding process specifications to a service
Each subprocess associated with a `DaemonService` is defined with a `DaemonProcess` assertion:
```preserves-schema
DaemonProcess = <daemon @id any @config DaemonProcessSpec>.
DaemonProcessSpec =
/ @simple CommandLine
/ @oneShot <one-shot @setup CommandLine>
/ @full FullDaemonProcess .
```
The simplest kind of subprocess specification is a `CommandLine`, either a string (sent to `sh
-c`) or an array of program name (looked up in the `$PATH`) and arguments:
```preserves-schema
CommandLine = @shell string / @full FullCommandLine .
FullCommandLine = [@program string, @args string ...] .
```
The `simple` and `oneShot` variants of `DaemonProcessSpec` expand into `FullDaemonProcess`
values as follows:
- a `simple` command-line *c* becomes `{ argv: `*c*` }`; and
- a record `<one-shot `*c*`>` becomes `{ argv: `*c*`, readyOnStart: false, restart: on-error }`.
## Subprocess specification
The `FullDaemonProcess` type matches a Preserves dictionary having, at minimum, an `argv` key,
and optionally including many other parameters controlling various aspects of the subprocess to
be created.[^full-process-split-out]
```preserves-schema
FullDaemonProcess =
& @process FullProcess
& @readyOnStart ReadyOnStart
& @restart RestartField
& @protocol ProtocolField .
FullProcess =
& { argv: CommandLine }
& @env ProcessEnv
& @dir ProcessDir
& @clearEnv ClearEnv .
```
The `CommandLine` associated with `argv` specifies the program name to invoke and its
command-line arguments. The other options are described in the remainder of this section.
### Ready-signalling
If the key `readyOnStart` is present in a `FullDaemonProcess` dictionary, then if its
associated value is `#t` (the default), the service will be considered
[`ready`](../service.md#service-states) immediately after it has been spawned; if its value is
`#f`, some other arrangement is expected to be made to announce a `ready` `ServiceState`
against the service's name.
```preserves-schema
ReadyOnStart =
/ @present { readyOnStart: bool }
/ @invalid { readyOnStart: any }
/ @absent {} .
```
### Whether and when to restart
The default restart policy is `always`. It can be overridden by providing the key `restart` a
`FullDaemonProcess` dictionary, mapping to a valid `RestartPolicy` value.
```preserves-schema
RestartField =
/ @present { restart: RestartPolicy }
/ @invalid { restart: any }
/ @absent {} .
RestartPolicy = =always / =on-error / =all / =never .
```
The valid restart policies are:
- `always`: Whether the process terminates normally or abnormally, restart it without affecting
any peer processes within the service.
- `on-error`: If the process terminates normally, leave everything alone; if it terminates
abnormally, restart it without affecting peers.
- `all`: If the process terminates normally, leave everything alone; if it terminates
abnormally, restart the whole daemon (all processes within the `Daemonservice`).
- `never`: Treat both normal and abnormal termination as normal termination; that is, never
restart, and enter state [`complete`](../service.md#service-states) even if the process
fails.
### Speaking Syndicate Network Protocol via stdin/stdout
By default, the `syndicate-server` program assumes nothing about the information to be read and
written via a subprocess's standard input and standard output. This can be overridden with a
`protocol` entry in a `FullDaemonProcess` specification. (Standard error is always considered
to produce information to be put in the system logs, however.)
```preserves-schema
ProtocolField =
/ @present { protocol: Protocol }
/ @invalid { protocol: any }
/ @absent {} .
Protocol = =none / =application/syndicate / =text/syndicate .
```
The available options for `protocol` are:
- `none`: the standard input of the subprocess is connected to `/dev/null`, and the standard
output and standard error are logged.
- `application/syndicate`: the subprocess standard input and output are used as a *binary*
syntax [Syndicate network protocol](../../protocol.md) relay. Standard error is logged. The
subprocess is expected to make some [entity](../../glossary.md#entity) available to the
server via [initial oid](../../glossary.md#initial-oid) 0. The server reflects this
expectation by automatically placing a [service object](../service.md#service-object) record
into the dataspace alongside the `daemon` record defining the subprocess.
- `text/syndicate`: as for `application/syndicate`, but Preserves' *text* syntax is used
instead of binary syntax.
### Specifying subprocess environment variables
By default, the Unix process environment passed on to subprocesses is not changed. Supplying
`clearEnv` and/or `env` keys alters this behaviour.
```preserves-schema
ClearEnv =
/ @present { clearEnv: bool }
/ @invalid { clearEnv: any }
/ @absent {} .
ProcessEnv =
/ @present { env: { EnvVariable: EnvValue ...:... } }
/ @invalid { env: any }
/ @absent {} .
EnvVariable = @string string / @symbol symbol / @invalid any .
EnvValue = @set string / @remove #f / @invalid any .
```
Setting `clearEnv` to `#t` causes the environment to be emptied before `env` is processed and
before the subprocess is started. The `env` key is expected to contain a dictionary whose keys
are strings or symbols and whose values are either a string, to set the variable to a new
value, or `#f`, to remove it from the environment.
### Setting the Current Working Directory for a subprocess
By default, each subprocess inherits the current working directory of the `syndicate-server`
program. Setting a `dir` key to a string value in a `FullDaemonProcess` overrides this.
```preserves-schema
ProcessDir =
/ @present { dir: string }
/ @invalid { dir: any }
/ @absent {} .
```
----
#### Notes
[^full-process-split-out]: The `FullProcess` type is split out in order for it to be able to be
reused outside the specific context of a *daemon* process.

View File

@ -1,15 +1,15 @@
# Gatekeeper
- Relevant schema:
- Gatekeepers: [[syndicate-protocol]/schemas/gatekeeper.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/gatekeeper.prs)
- Sturdyrefs: [[syndicate-protocol]/schemas/sturdy.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/sturdy.prs)
When `syndicate-server` starts, it creates a *gatekeeper service entity*, which accepts
`resolve` assertions requesting conversion of a long-lived "sturdyref" to a [live
reference](../../glossary.md#reference). The gatekeeper is the [default
object](../../glossary.md#initial-ref), available as [OID](../../glossary.md#oid) 0 to peers at
the other end of [relay listener](./relay-listener.md) connections.
## Gatekeeper protocol
- Relevant schema: [[syndicate-protocol]/schemas/gatekeeper.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/gatekeeper.prs)
```preserves-schema
Resolve = <resolve @sturdyref sturdy.SturdyRef @observer #!#!any>.
```
@ -27,6 +27,8 @@ asserted to the `observer` in the `resolve`.
## Sturdyrefs
- Relevant schema: [[syndicate-protocol]/schemas/sturdy.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/sturdy.prs)
A "sturdyref" is a long-lived certificate including a cryptographic signature that can be
upgraded by a gatekeeper entity to a live reference to the entity named in the sturdyref. The
current sturdyref implementation is based on the design of
@ -65,9 +67,8 @@ is shamelessly taken from [macaroons][], though our caveats presently embody onl
Macaroons paper are called "first-party caveats" over assertion structure; future versions of
the server may add "third-party caveats" and other, richer, predicates over assertions.
Each `Attenuation`'s `Caveat`s are run in *right to left* order.
For details of the structure and interpretation of `Caveat`s, see [the relevant section of the
Syndicate network protocol specification](../../protocol.md#attenuation-of-authority).
Each `Attenuation`'s `Caveat`s are run in *right to left* order. The structure and
interpretation of `Caveat`s is described fully in [the relevant section of the Syndicate
network protocol specification](../../protocol.md#attenuation-of-authority).
[Macaroons]: ../../glossary.md#macaroon

View File

@ -1 +1,23 @@
# Logging
The Synit logging infrastructure is still underdeveloped.
At present, there is an actor created at `syndicate-server` startup time that monitors the
`$log` dataspace for messages of the form:
```preserves-schema
LogEntry = <log @timestamp string @detail { any: any ...:... }> .
```
When it receives a log entry, it looks for a few conventional and optional keys in the `detail`
field, each permitted to be any kind of [value](../../glossary.md#value):
- `pid`, conventionally a Unix process ID;
- `line`, conventionally a string of free-form text intended for people to read;
- `service`, conventionally a service name in the sense of
[`require-service`](../service.md#require-service)/[`run-service`](../service.md#run-service); and
- `stream`, conventionally one of the symbols `stdout` or `stderr`.
The timestamp and the special keys are then formatted, along with all other information in the
entry record, and printed to the `syndicate-server`'s standard error at `INFO` level using
[`tracing`](https://docs.rs/tracing/latest/tracing/).

View File

@ -1,11 +1,61 @@
# TCP/IP, WebSocket and Unix-socket Transports
# Relay Listeners
- Any number of [**TCP/IP, WebSocket, and Unix socket transports**](./relay-listener.md) may
be configured to allow external access to the gatekeeper and its registered services. (These
can also be started from the `syndicate-server` command-line with `-p` and `-s` options.)
- Relevant schema:
- [[syndicate-rs]/syndicate-server/protocols/schemas/internalServices.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-rs/src/branch/main/syndicate-server/protocols/schemas/internalServices.prs)
- [[syndicate-protocol]/schemas/transportAddress.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/transportAddress.prs)
## TCP/IP
The `syndicate-server` program can be configured to listen on TCP/IP ports and Unix
sockets[^sock-stream-only] for incoming connections speaking the [Syndicate network
protocol][protocol].
## WebSockets
[protocol]: ../../protocol.md
## <span id="tcpip"></span>TCP/IP and WebSockets
Assertions [requiring](../service.md#require-service) a service with name matching
`TcpRelayListener` cause the server to start a TCP server socket on the given `addr`'s `host`
and `port`, exposing the `gatekeeper` [entity reference](../../glossary.md#reference) as the
[initial ref](../../glossary.md#initial-ref) of incoming connections:
```preserves-schema
TcpRelayListener = <relay-listener @addr Tcp @gatekeeper #!gatekeeper.Resolve> .
Tcp = <tcp @host string @port int>.
```
When a new connection arrives, the first byte is examined to see what kind of connection it is
and which Preserves syntax it will use.
- If it is ASCII "`G`" (0x47), it cannot be the start of a [protocol][] packet, so it is
interpreted as the start of a WebSocket connection and handed off to the
[tokio_tungstenite](https://docs.rs/tokio-tungstenite/latest/tokio_tungstenite/) WebSocket
library. Within the WebSocket's context, each packet must be encoded as a binary packet
using Preserves binary syntax.
- Otherwise, if it could start a valid UTF-8 sequence, the connection will be a plain TCP/IP
link using the Preserves text syntax.
- Otherwise, it's a byte which cannot be part of a valid UTF-8 sequence, so it is interpreted
as a Preserves binary syntax tag: the connection will be a plain TCP/IP link using Preserves
binary syntax.
## Unix sockets
Assertions [requiring](../service.md#require-service) a service with name matching
`UnixRelayListener` cause the server to start a Unix server socket on the given `addr`'s
`path`, exposing the `gatekeeper` [entity reference](../../glossary.md#reference) as the
[initial ref](../../glossary.md#initial-ref) of incoming connections:
```preserves-schema
UnixRelayListener = <relay-listener @addr Unix @gatekeeper #!gatekeeper.Resolve> .
Unix = <unix @path string>.
```
Syntax autodetection is as for [TCP/IP](#tcpip), except that WebSockets are not supported over
Unix sockets.
----
#### Notes
[^sock-stream-only]: Only `SOCK_STREAM` Unix sockets are supported, at present. In future,
`SOCK_DGRAM` could be useful for e.g. file-descriptor passing.

View File

@ -194,7 +194,8 @@ are introduced into the environment.
The right-hand-side of a `let`, after the equals sign, is either a normal *ValueExpr* or one of
the following special "convenience" expressions:
- `dataspace`: Evaluates to a fresh, empty [dataspace](../glossary.md#dataspace) entity.
- <span id="expr:dataspace">`dataspace`: Evaluates to a fresh, empty
[dataspace](../glossary.md#dataspace) entity.</span>
- `timestamp`: Evaluates to a string containing an
[RFC-3339](https://datatracker.ietf.org/doc/html/rfc3339)-formatted timestamp.

View File

@ -46,7 +46,7 @@ without use of variables or any reactive constructs.
A few different kinds of assertions, all declared in [the `service.prs` schema][service.prs],
form the heart of the system.
### Assert that a service and its dependencies should be started
### <span id="require-service"></span>Assert that a service and its dependencies should be started
```preserves-schema
RequireService = <require-service @serviceName any>.
@ -55,7 +55,7 @@ RequireService = <require-service @serviceName any>.
Asserts that a service should begin (and stay) running after waiting for its dependencies and
considering reverse-dependencies, blocks, and so on.
### Assert that a service should start *right now*
### <span id="run-service"></span>Assert that a service should start *right now*
```preserves-schema
RunService = <run-service @serviceName any>.
@ -76,7 +76,7 @@ ServiceDependency = <depends-on @depender any @dependee ServiceState>.
Asserts that, when `depender` is `require-service`d, it should not be started until `dependee`
has been asserted, and also that `dependee`'s `serviceName` should be `require-service`d.
### Convey the current state of a service
### <span id="service-states"></span>Convey the current state of a service
```preserves-schema
ServiceState = <service-state @serviceName any @state State>.
@ -101,7 +101,7 @@ A few built-in states are defined:
In addition, any user-defined value is acceptable as a `State`.
### Make an entity representing a service instance available
### <span id="service-object"></span>Make an entity representing a service instance available
```preserves-schema
ServiceObject = <service-object @serviceName any @object any>.