Detect wireless interfaces; use layered config; use detected interfaces

This commit is contained in:
Tony Garnock-Jones 2022-02-06 23:06:55 +01:00
parent 6b4285242a
commit fc4783f17e
22 changed files with 185 additions and 76 deletions

View File

@ -1,8 +1,10 @@
# Contributor: Tony Garnock-Jones <tonyg@leastfixedpoint.com>
# Maintainer: Tony Garnock-Jones <tonyg@leastfixedpoint.com>
pkgname=synit-config
pkgver=0.0.5
pkgrel=1
pkgver=0.0.6
pkgrel=$(date '+%Y%m%d%H%M%S')
# pkgver=0.0.5
# pkgrel=1
pkgdesc="synit system layer configuration"
url="https://synit.org/"
arch="noarch"
@ -57,5 +59,5 @@ docker() {
description="Synit startup for Docker"
install_if="$pkgname docker"
amove etc/syndicate/docker.pr
amove etc/syndicate/services/docker.pr
}

View File

@ -0,0 +1,10 @@
; To "run" a milestone service,
; - assert that it is both started and ready
; - that's it!
;
? <run-service <milestone ?m>> [
<service-state <milestone $m> started>
<service-state <milestone $m> ready>
$log ! <log "-" { service: <milestone $m> state: up }>
?- <log "-" { service: <milestone $m> state: down }>
]

View File

@ -0,0 +1,4 @@
; To the usual suite of service states we add `up`, meaning "either `ready` or `complete`".
;
? <service-state ?x ready> <service-state $x up>
? <service-state ?x complete> <service-state $x up>

View File

@ -0,0 +1,28 @@
; Attenuate `$config` by rewriting plain `require-service` assertions to `require-core-service`
; assertions. Allow all other assertions through.
;
let ?sys = <* $config [
<rewrite <require-service ?s> <require-core-service $s>>
<filter _>
]>
; Give meaning to `require-core-service`: it is an ordinary `require-service`, plus a
; declaration that the `core` milestone depends on the service.
;
? <require-core-service ?s> [
<depends-on <milestone core> <service-state $s up>>
<require-service $s>
]
; Load config in the `core` directory, using the wrapped `config` so that all plain services
; required are changed to be *core* services.
;
<require-service <config-watcher "/etc/syndicate/core" {
config: $sys
gatekeeper: $gatekeeper
log: $log
}>>
; In addition, require the `core` milestone explicitly.
;
<require-service <milestone core>>

View File

@ -0,0 +1,26 @@
; Attenuate `$config` by rewriting plain `require-service` assertions to
; `require-basic-service` assertions. Allow all other assertions through.
;
let ?basic = <* $config [
<rewrite <require-service ?s> <require-basic-service $s>>
<filter _>
]>
; Give meaning to `require-basic-service`: it is an ordinary `require-service`, plus a
; declaration that the service depends on the `core` milestone.
;
? <require-basic-service ?s> [
<depends-on $s <service-state <milestone core> up>>
<require-service $s>
]
; Once we see that the `core` milestone is ready, start processing the `services`
; directory.
;
? <service-state <milestone core> up> [
<require-service <config-watcher "/etc/syndicate/services" {
config: $basic
gatekeeper: $gatekeeper
log: $log
}>>
]

View File

@ -1,2 +0,0 @@
<require-service <config-watcher "/run/etc/syndicate" $.>>
<require-service <config-watcher "/usr/local/etc/syndicate" $.>>

View File

@ -0,0 +1,2 @@
<require-service <config-watcher "/run/etc/syndicate/core" $.>>
<require-service <config-watcher "/usr/local/etc/syndicate/core" $.>>

View File

@ -1,9 +1,6 @@
<depends-on <milestone system-layer> <service-state <daemon eudev> ready>>
<depends-on <milestone system-layer> <service-state <daemon eudev-initial-scan> complete>>
<system-layer-service <daemon eudev>>
<require-service <daemon eudev>>
<daemon eudev ["/sbin/udevd", "--children-max=5"]>
<system-layer-service <daemon eudev-initial-scan>>
<depends-on <daemon eudev-initial-scan> <service-state <daemon eudev> ready>>
<require-service <daemon eudev-initial-scan>>
<depends-on <daemon eudev-initial-scan> <service-state <daemon eudev> up>>
<daemon eudev-initial-scan <one-shot "echo '' > /proc/sys/kernel/hotplug && udevadm trigger --type=subsystems --action=add && udevadm trigger --type=devices --action=add && udevadm settle --timeout=30">>

View File

@ -0,0 +1,2 @@
<require-service <daemon hostname>>
<daemon hostname <one-shot "hostname $(cat /etc/hostname)">>

View File

@ -0,0 +1,63 @@
<require-service <daemon interface-monitor>>
<require-service <milestone network>>
<depends-on <milestone network> <service-state <daemon interface-monitor> ready>>
<configure-interface "lo" <static "127.0.0.1">>
? <configure-interface ?ifname <static ?ipaddr>> [
$log ! <log "-" { service: $ifname line: "seen-static" ipaddr: $ipaddr }>
! <run-oneshot ["ifconfig" $ifname $ipaddr "up"]>
?- ! <run-oneshot ["ifconfig" $ifname "down"] never>
]
? <configure-interface ?ifname <dhcp>> [
$log ! <log "-" { service: $ifname line: "seen-dhcp" }>
! <run-oneshot ["ifconfig" $ifname "up"]>
?- ! <run-oneshot ["ifconfig" $ifname "down"] never>
<require-service <daemon <udhcpc $ifname>>>
]
? <run-service <daemon <udhcpc ?ifname>>> [
<daemon <udhcpc $ifname> ["udhcpc" "-i" $ifname "-fR"]>
]
?? <run-oneshot ?argv> ! <run-oneshot $argv on-error>
?? <run-oneshot ?argv ?restartPolicy> [
let ?id = timestamp
let ?facet = facet
let ?d = <temporary-exec $id $argv>
<run-service <daemon $d>>
<daemon $d {
argv: $argv,
readyOnStart: #f,
restart: $restartPolicy,
}>
? <service-state <daemon $d> complete> [$facet ! stop]
? <service-state <daemon $d> failed> [$facet ! stop]
]
;---------------------------------------------------------------------------
<daemon interface-monitor {
argv: "/usr/lib/synit/interface-monitor"
protocol: application/syndicate
}>
? <machine-dataspace ?machine> [
? <service-object <daemon interface-monitor> ?cap> [
$cap {
machine: $machine
}
]
$machine ? ?r [
$log ! <log "-" { line: "machine" |+++|: $r }>
?- $log ! <log "-" { line: "machine" |---|: $r }>
]
$machine ? <interface ?ifname _ normal _ _ carrier _> [
$config <configure-interface $ifname <dhcp>>
]
]

View File

@ -1,4 +0,0 @@
<require-service <daemon docker>>
<depends-on <daemon docker> <service-state <milestone network> ready>>
<daemon docker "/usr/bin/dockerd --experimental">

View File

@ -1,3 +0,0 @@
<depends-on <milestone system-layer> <service-state <daemon hostname> complete>>
<system-layer-service <daemon hostname>>
<daemon hostname <one-shot "hostname $(cat /etc/hostname)">>

View File

@ -1,20 +0,0 @@
; <depends-on <milestone network> <service-state <daemon interface-monitor> ready>>
<require-service <daemon interface-monitor>>
<daemon interface-monitor {
argv: "/usr/lib/synit/interface-monitor"
protocol: application/syndicate
}>
? <machine-dataspace ?machine> [
? <service-object <daemon interface-monitor> ?cap> [
$cap {
machine: $machine
}
]
$machine ? ?r [
$log ! <log "-" { line: "machine" |+++|: $r }>
?- $log ! <log "-" { line: "machine" |---|: $r }>
]
]

View File

@ -1,29 +0,0 @@
<require-service <milestone network>>
<configure-interface "lo" <static "127.0.0.1">>
<configure-interface "eth0" <dhcp>>
<depends-on <milestone network> <service-state <daemon interfaces> complete>>
? <configure-interface ?ifname <static ?ipaddr>> [
<daemon interfaces {
argv: ["ifconfig" $ifname $ipaddr "up"]
restart: on-error
}>
]
? <configure-interface ?ifname <dhcp>> [
<daemon interfaces {
argv: ["ifconfig" $ifname "up"]
restart: on-error
}>
<require-service <daemon <udhcpc $ifname>>>
]
? <run-service <daemon <udhcpc ?ifname>>> [
<daemon <udhcpc $ifname> ["udhcpc" "-i" $ifname "-fR"]>
]
;---------------------------------------------------------------------------
; TODO: put interface-monitor in here

View File

@ -0,0 +1,3 @@
<require-service <daemon docker>>
<depends-on <daemon docker> <service-state <milestone network> up>>
<daemon docker "/usr/bin/dockerd --experimental 2>/var/log/docker.log">

View File

@ -1,6 +1,5 @@
<require-service <daemon sshd>>
<depends-on <daemon sshd> <service-state <milestone network> ready>>
<depends-on <daemon sshd> <service-state <milestone network> up>>
<depends-on <daemon sshd> <service-state <daemon ssh-host-keys> complete>>
<daemon sshd "/usr/sbin/sshd -D">
<daemon ssh-host-keys <one-shot "ssh-keygen -A">>

View File

@ -19,7 +19,7 @@ mount -t cgroup2 none /sys/fs/cgroup
mount -o rw,remount /
mkdir -p /run/etc/syndicate
mkdir -p /usr/local/etc/syndicate
mkdir -p /run/etc/syndicate/core
mkdir -p /usr/local/etc/syndicate/core
exec /sbin/synit-pid1

View File

@ -10,6 +10,7 @@ import preserves.schema
import threading
import pyroute2
from pr2modules.iwutil import IW
schemas = preserves.schema.load_schema_file('/usr/share/synit/schemas/schema-bundle.prb')
network = schemas.network
@ -74,9 +75,21 @@ administrative_state_map = {
'down': network.AdministrativeState.down(),
}
def parse_interface(m):
def parse_interface(m, iw):
wireless_info = None
try:
wireless_info = iw.get_interface_by_ifindex(m['index'])
except Exception as e:
# presumably, no wireless extensions
pass
iftype = network.InterfaceType.normal()
if m['flags'] & 8:
iftype = network.InterfaceType.loopback()
if wireless_info is not None:
iftype = network.InterfaceType.wireless()
return network.Interface(m.get_attr('IFLA_IFNAME'),
m['index'],
iftype,
administrative_state_map.get(m['state'],
network.AdministrativeState.unknown()),
operational_state_map.get(m.get_attr('IFLA_OPERSTATE', 'UNKNOWN'),
@ -107,6 +120,8 @@ def main(args):
ip = pyroute2.IPRoute()
ip.bind()
iw = IW()
@turn.on_stop_or_crash
def shutdown():
ip.close()
@ -118,7 +133,7 @@ def main(args):
for m in events:
event_type = m['event']
if event_type == 'RTM_NEWLINK':
i = parse_interface(m)
i = parse_interface(m, iw)
if (wireless_extension := m.get_attr('IFLA_WIRELESS', None)) is not None \
and wireless_extension.get_attr('SIOCGIWSCAN', None) is not None:
turn.log.info(f'Interface {i.name} is performing a rescan')
@ -129,7 +144,7 @@ def main(args):
linktable[i.index] = Link(None, None)
linktable[i.index].update(machine_ds, i)
elif event_type == 'RTM_DELLINK':
i = parse_interface(m)
i = parse_interface(m, iw)
link = linktable.pop(i.index, None)
if link is not None:
link.update(machine_ds, None)

View File

@ -0,0 +1,3 @@
#!/bin/sh
rm -rf protocols
cp -rp ../../../protocols .

View File

@ -3,8 +3,8 @@ WidgetType
horizontal´³refµ„³Sizing„„´³named³vertical´³refµ„³Sizing„„„„„³SortKey´³orµµ±double´³atom³Double„„µ±string´³atom³String„„„„³LeafType´³orµµ±blank´³lit³blank„„µ±text´³lit³text„„µ±slider´³lit³slider„„µ±image´³lit³image„„µ±icon´³lit³icon„„„„³NodeType´³orµµ±column´³lit³column„„µ±row´³lit³row„„„„³WidgetId³any³ Attribute´³rec´³lit³ attribute„´³tupleµ´³named³id´³refµ„³WidgetId„„´³named³key´³atom³Symbol„„´³named³value³any„„„„³
WidgetType´³orµµ±NodeType´³refµ„³NodeType„„µ±LeafType´³refµ„³LeafType„„„„³ WindowTitle´³rec´³lit³ window-title„´³tupleµ´³named³title´³atom³String„„„„„³WidgetInstance´³rec´³lit³widget-instance„´³tupleµ´³named³id´³refµ„³WidgetId„„´³named³instance´³embedded³any„„„„„³WindowCloseable´³rec´³lit³window-closeable„´³tupleµ„„„„³ embeddedType€„„µ³mime„´³schema·³version³ definitions·³Value´³rec´³lit³mime„´³tupleµ´³named³type´³atom³Symbol„„´³named³data´³atom³
ByteString„„„„„„³ embeddedType€„„µ³time„´³schema·³version³ definitions·³Stamp´³rec´³lit³rfc3339„´³tupleµ´³named³value´³atom³String„„„„„„³ embeddedType€„„µ³audio„´³schema·³version³ definitions·³Sink´³orµµ±speaker´³lit³speaker„„µ±headset´³lit³headset„„µ±earpiece´³lit³earpiece„„„„³Source´³orµµ± speakerphone´³lit³ speakerphone„„µ±headset´³lit³headset„„µ±handset´³lit³handset„„„„³ SinkMapping´³rec´³lit³alsa-sink-mapping„´³tupleµ´³named³abstract´³refµ„³Sink„„´³named³concrete´³atom³String„„„„„³HeadsetSpeakerPresent´³rec´³lit³headset-speaker-present„´³tupleµ„„„³HeadsetMicrophonePresent´³rec´³lit³headset-microphone-present„´³tupleµ„„„„³ embeddedType€„„µ³hayes„´³schema·³version³ definitions·³Result´³rec´³lit³result„´³tupleµ´³named³text´³atom³String„„´³named³tag´³refµ„³ MaybeString„„´³named³fields´³refµ„³ MaybeStrings„„„„„³ MaybeString´³orµµ±present´³atom³String„„µ±absent´³lit€„„„„³ MaybeStrings´³orµµ±present´³seqof´³atom³String„„„µ±absent´³lit€„„„„³ ModemPresent´³rec´³lit³modem„´³tupleµ´³lit³hayes„´³named³
devicePath´³atom³String„„´³named³ dataspace´³embedded´³refµ„³InternalProtocol„„„„„„³ CommandResult´³rec´³lit³command-result„´³tupleµ´³named³ commandText´³atom³String„„´³named³results´³seqof´³refµ„³Result„„„´³named³ finalResult´³atom³String„„„„„³ExecuteCommand´³rec´³lit³execute-command„´³tupleµ´³named³ commandText´³atom³String„„´³named³replyTo´³refµ„³CommandContinuation„„„„„³InternalProtocol³any³CommandContinuation´³orµµ± replyWanted´³embedded´³refµ„³ CommandResult„„„µ± fireAndForget´³lit€„„„„³UnsolicitedResultCode´³rec´³lit³ unsolicited„´³tupleµ´³named³result´³refµ„³Result„„„„„„³ embeddedType€„„µ³network„´³schema·³version³ definitions·³Route´³rec´³lit³route„´³tupleµ´³named³ addressFamily´³refµ„³ AddressFamily„„´³named³ destination´³refµ„³RouteDestination„„´³named³priority´³atom³ SignedInteger„„´³named³ typeOfService´³atom³ SignedInteger„„´³named³ interfaceName´³refµ„³RouteInterface„„´³named³gateway´³refµ„³Gateway„„„„„³Gateway´³orµµ±addr´³atom³String„„µ±none´³lit€„„„„³ Interface´³rec´³lit³ interface„´³tupleµ´³named³name´³atom³String„„´³named³index´³atom³ SignedInteger„„´³named³administrativeState´³refµ„³AdministrativeState„„´³named³operationalState´³refµ„³OperationalState„„´³named³carrier´³refµ„³ CarrierState„„´³named³linkAddr´³atom³String„„„„„³ CarrierState´³orµµ± noCarrier´³lit³
no-carrier„„µ±carrier´³lit³carrier„„„„³ AddressFamily´³orµµ±ipv4´³lit³ipv4„„µ±ipv6´³lit³ipv6„„µ±other´³atom³ SignedInteger„„„„³RouteInterface´³orµµ±name´³atom³String„„µ±none´³lit€„„„„³OperationalState´³orµµ±unknown´³lit³unknown„„µ±down´³lit³down„„µ±lowerLayerDown´³lit³lower-layer-down„„µ±testing´³lit³testing„„µ±dormant´³lit³dormant„„µ±up´³lit³up„„„„³RouteDestination´³orµµ±default´³lit³default„„µ±prefix´³rec´³lit³prefix„´³tupleµ´³named³net´³atom³String„„´³named³bits´³atom³ SignedInteger„„„„„„„„³AdministrativeState´³orµµ±unknown´³lit³unknown„„µ±down´³lit³down„„µ±up´³lit³up„„„„„³ embeddedType€„„µ³ telephony„´³schema·³version³ definitions·³CallId´³atom³ SignedInteger„³Address´³rec´³lit³address„´³tupleµ´³named³
devicePath´³atom³String„„´³named³ dataspace´³embedded´³refµ„³InternalProtocol„„„„„„³ CommandResult´³rec´³lit³command-result„´³tupleµ´³named³ commandText´³atom³String„„´³named³results´³seqof´³refµ„³Result„„„´³named³ finalResult´³atom³String„„„„„³ExecuteCommand´³rec´³lit³execute-command„´³tupleµ´³named³ commandText´³atom³String„„´³named³replyTo´³refµ„³CommandContinuation„„„„„³InternalProtocol³any³CommandContinuation´³orµµ± replyWanted´³embedded´³refµ„³ CommandResult„„„µ± fireAndForget´³lit€„„„„³UnsolicitedResultCode´³rec´³lit³ unsolicited„´³tupleµ´³named³result´³refµ„³Result„„„„„„³ embeddedType€„„µ³network„´³schema·³version³ definitions·³Route´³rec´³lit³route„´³tupleµ´³named³ addressFamily´³refµ„³ AddressFamily„„´³named³ destination´³refµ„³RouteDestination„„´³named³priority´³atom³ SignedInteger„„´³named³ typeOfService´³atom³ SignedInteger„„´³named³ interfaceName´³refµ„³RouteInterface„„´³named³gateway´³refµ„³Gateway„„„„„³Gateway´³orµµ±addr´³atom³String„„µ±none´³lit€„„„„³ Interface´³rec´³lit³ interface„´³tupleµ´³named³name´³atom³String„„´³named³index´³atom³ SignedInteger„„´³named³type´³refµ„³ InterfaceType„„´³named³administrativeState´³refµ„³AdministrativeState„„´³named³operationalState´³refµ„³OperationalState„„´³named³carrier´³refµ„³ CarrierState„„´³named³linkAddr´³atom³String„„„„„³ CarrierState´³orµµ± noCarrier´³lit³
no-carrier„„µ±carrier´³lit³carrier„„„„³ AddressFamily´³orµµ±ipv4´³lit³ipv4„„µ±ipv6´³lit³ipv6„„µ±other´³atom³ SignedInteger„„„„³ InterfaceType´³orµµ±loopback´³lit³loopback„„µ±normal´³lit³normal„„µ±wireless´³lit³wireless„„„„³RouteInterface´³orµµ±name´³atom³String„„µ±none´³lit€„„„„³OperationalState´³orµµ±unknown´³lit³unknown„„µ±down´³lit³down„„µ±lowerLayerDown´³lit³lower-layer-down„„µ±testing´³lit³testing„„µ±dormant´³lit³dormant„„µ±up´³lit³up„„„„³RouteDestination´³orµµ±default´³lit³default„„µ±prefix´³rec´³lit³prefix„´³tupleµ´³named³net´³atom³String„„´³named³bits´³atom³ SignedInteger„„„„„„„„³AdministrativeState´³orµµ±unknown´³lit³unknown„„µ±down´³lit³down„„µ±up´³lit³up„„„„„³ embeddedType€„„µ³ telephony„´³schema·³version³ definitions·³CallId´³atom³ SignedInteger„³Address´³rec´³lit³address„´³tupleµ´³named³
numberType´³refµ„³
NumberType„„´³named³number´³atom³String„„„„„³CallType´³orµµ±voice´³lit³voice„„µ±data´³lit³data„„µ±fax´³lit³fax„„„„³ CallState´³orµµ±hold´³lit³hold„„µ±original´³lit³original„„µ±connect´³lit³connect„„µ±incoming´³lit³incoming„„µ±waiting´³lit³waiting„„µ±end´³lit³end„„µ±alerting´³lit³alerting„„„„³ PlaceCall´³rec´³lit³
place-call„´³tupleµ´³named³

View File

@ -3,11 +3,24 @@ version 1 .
Interface = <interface
@name string
@index int
@type InterfaceType
@administrativeState AdministrativeState
@operationalState OperationalState
@carrier CarrierState
@linkAddr string> .
; This is synthetic information, based on somewhat ad-hoc heuristics. It'd be nice if there was
; a better way to do this! Maybe someone can point me in the right direction!
;
InterfaceType =
/ ; `lo` and friends
=loopback
/ ; `eth0`, bridges, anything that isn't loopback and isn't wireless
=normal
/ ; 'wlan0' and friends
=wireless
.
AdministrativeState =
/ =unknown
/ =down