Compare commits
18 Commits
095853214b
...
e5963ae3f7
Author | SHA1 | Date |
---|---|---|
Daniel Barlow | e5963ae3f7 | |
Daniel Barlow | f164f19d95 | |
Daniel Barlow | dd4ab41f6a | |
Daniel Barlow | 5d5dff6729 | |
Daniel Barlow | 570d29c368 | |
Daniel Barlow | 725af00dc9 | |
Daniel Barlow | e1b932ec27 | |
Daniel Barlow | 7173b6fb1c | |
Daniel Barlow | ed9548f21d | |
Daniel Barlow | 0787807a7f | |
Daniel Barlow | 38ed91f641 | |
Daniel Barlow | ffe9603c39 | |
Daniel Barlow | cbd3dfefc5 | |
Daniel Barlow | 018c1868b5 | |
Daniel Barlow | 5184ff63f7 | |
Daniel Barlow | 35909c9a23 | |
Daniel Barlow | 4383462199 | |
Daniel Barlow | 9730cdd63b |
152
THOUGHTS.txt
152
THOUGHTS.txt
|
@ -4137,3 +4137,155 @@ p-clock-init,mfp,allows-mesh-bcast crc32 62f7565f
|
|||
[ 16.762697] ath10k_pci 0000:00:00.0: pdev param 0 not supported by firmware
|
||||
[ 23.030622] ath10k_pci 0000:00:00.0: pdev param 0 not supported by firmware
|
||||
[
|
||||
|
||||
|
||||
Tue Feb 27 23:16:27 GMT 2024
|
||||
|
||||
We made it a full week with rotuer running internet chez nous and no
|
||||
need for an intervention, so I am happy to call it "production". There are
|
||||
still things that need fixing but they're mostly within scope for
|
||||
a services refresh
|
||||
|
||||
I have embarked on "profiles" by creating a wap.nix
|
||||
|
||||
I think we could have a service module for resolvconf
|
||||
|
||||
It would be good to build a wap.nix example for the belkin and we
|
||||
could start looking at ubifs
|
||||
|
||||
I've lost a chunk of notes about using events to drive desired service
|
||||
state. There is probably only going to be one udev listener, so
|
||||
what if we have udev as a config key thusly
|
||||
|
||||
udev.rules = [
|
||||
{
|
||||
match = {
|
||||
SUBSYSTEM = "rpmsg";
|
||||
ATTR.name = "DATA5_CNTL";
|
||||
};
|
||||
|
||||
service = longrun {
|
||||
name = "lte-modem";
|
||||
run = "blah blah blah";
|
||||
};
|
||||
}
|
||||
|
||||
# this one would be provided by the bridge module instead of
|
||||
# adding bridge member services to the default target
|
||||
|
||||
{
|
||||
match = {
|
||||
SUBSYSTEM="net";
|
||||
ID_PATH="pci-0000:04:00.0";
|
||||
ATTR.operstate = "up";
|
||||
};
|
||||
|
||||
service = oneshot {
|
||||
up = "ip link set dev $dev master $(output ${primary} ifname)";
|
||||
down = "ip link set dev $(output ${member} ifname) nomaster";
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
This works for udev/sysfs, but we want a similar architecture(sic) for
|
||||
user-generated target state so we could have services that run on e.g.
|
||||
"is the ppp0 service healthy" or not. Probably there isn't a top-level
|
||||
config key for each service though
|
||||
|
||||
services.wan = svc.ppoe.build { .... };
|
||||
services.lte = watcher.build {
|
||||
watching = services.wan;
|
||||
match = {
|
||||
# an expression matching the outputs of the service
|
||||
# to be watched
|
||||
health = "failing";
|
||||
};
|
||||
service = oneshot {
|
||||
run = "start_lte_blah";
|
||||
};
|
||||
}
|
||||
|
||||
thing is, we could use this syntax also for sysfs watches, but not vice versa
|
||||
|
||||
... but it's not quite the same because here we're doing static matches
|
||||
on contents of files, whereas the udev one is a query expression on the
|
||||
sysfs database. we might need that flexibiity to implement "mount the
|
||||
backup drive no matter _which_ damn sda_n_ device it appears as". I don't
|
||||
know if there's the same need for service outputs - postulate the
|
||||
existence of a collection of services which are all similar enough that
|
||||
some other service can watch them all and do $something when one of
|
||||
the changes state. Or a single service with very complicated outputs.
|
||||
For example, something could watch the snmp database and update service
|
||||
status depending on what it finds. Or something something mqtt...
|
||||
|
||||
we find that the "match" needs to be interpreted differently according
|
||||
to the thing being watched. perhaps the service being watched needs to
|
||||
provide a "watch me" interface somehow which accepts match criteria and
|
||||
outputs a true/false. Something else then needs to
|
||||
|
||||
|
||||
services.addmember = services.udev.watch {
|
||||
match = {
|
||||
SUBSYSTEM = "net";
|
||||
ID_PATH = "pci-0000:04:00.0";
|
||||
ATTR.operstate = "up";
|
||||
};
|
||||
|
||||
service = oneshot {
|
||||
up = "ip link set dev $dev master $(output ${primary} ifname)";
|
||||
down = "ip link set dev $(output ${member} ifname) nomaster";
|
||||
};
|
||||
}
|
||||
|
||||
Sat Mar 2 15:37:29 GMT 2024
|
||||
|
||||
Simply put, what I think it boils down to is that we want a service
|
||||
which acts as an actuator or control switch for another service,
|
||||
and will start/stop that controlled service according to some
|
||||
criteria.
|
||||
|
||||
services.addmember = svc.network.ifwatch.build {
|
||||
interface = config.hardware.networkInterfaces.lan1;
|
||||
|
||||
# this should be part of the definition not the params
|
||||
service = oneshot {
|
||||
name = "member-${bridge}-${interface}";
|
||||
up = "ip link set dev $dev master $(output ${primary} ifname)";
|
||||
down = "ip link set dev $(output ${member} ifname) nomaster";
|
||||
};
|
||||
}
|
||||
|
||||
we could start by writing this. we need to adapt ifwait
|
||||
|
||||
Sun Mar 3 17:09:21 GMT 2024
|
||||
|
||||
this is annoyingly hard to test. the tests we'd like to write are
|
||||
|
||||
1) when it gets events that don't match the requirement, nothing happens
|
||||
2) when it gets an event that should start the service, the
|
||||
service starts
|
||||
3) when stop should stop
|
||||
4) when start and already started, nothing happens
|
||||
5) when stop and already stopped, nothing happens
|
||||
|
||||
what do we do if service fails to start? s6-rc will eventually reset it
|
||||
to "down", I think: do we need to take action?
|
||||
|
||||
Mon Mar 4 20:46:55 GMT 2024
|
||||
|
||||
# relevant but not correct for this model: https://www.forked.net/forums/viewtopic.php?f=13&t=3490
|
||||
|
||||
# power on port 5
|
||||
snmpset -v 1 -c private 192.168.5.14 .1.3.6.1.4.1.318.1.1.4.4.2.1.3.5 integer 1
|
||||
|
||||
# power off port 5
|
||||
snmpset -v 1 -c private 192.168.5.14 .1.3.6.1.4.1.318.1.1.4.4.2.1.3.5 integer 2
|
||||
|
||||
# toggle off/on port 5
|
||||
snmpset -v 1 -c private 192.168.5.14 .1.3.6.1.4.1.318.1.1.4.4.2.1.3.5 integer 3
|
||||
|
||||
Wed Mar 6 18:24:29 GMT 2024
|
||||
|
||||
What happens when we attempt to start the service but it fails? We
|
||||
assume the start was successful so we won't try and restart it again
|
||||
next time we get an event that should cause it to start.
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
(fn assoc [tbl k v]
|
||||
(tset tbl k v)
|
||||
tbl)
|
||||
|
||||
(fn merge [table1 table2]
|
||||
(collect [k v (pairs table2) &into table1]
|
||||
k v))
|
||||
|
@ -62,4 +66,4 @@
|
|||
(s:sub 1 (- (# s) pad))))
|
||||
|
||||
|
||||
{ : merge : split : file-exists? : system : hash : base64url : dup }
|
||||
{ : assoc : merge : split : file-exists? : system : hash : base64url : dup }
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
(local netlink (require :netlink))
|
||||
|
||||
(local { : view } (require :fennel))
|
||||
|
||||
(fn events [groups]
|
||||
(let [sock (netlink.socket)]
|
||||
(coroutine.wrap
|
||||
(fn []
|
||||
(each [_ e (ipairs (sock:query groups))]
|
||||
(coroutine.yield e))
|
||||
(while (sock:poll)
|
||||
(each [_ e (ipairs (sock:event))]
|
||||
(coroutine.yield e)))))))
|
||||
|
||||
{ : events }
|
|
@ -0,0 +1,7 @@
|
|||
(local nl (require :anoia.nl))
|
||||
(local { : view } (require :fennel))
|
||||
|
||||
(let [events (nl.events {:link true})]
|
||||
(each [ev events]
|
||||
(print "got one ")
|
||||
(print (view ev))))
|
|
@ -8,12 +8,14 @@
|
|||
, writeScriptBin
|
||||
, linotify
|
||||
, anoia
|
||||
, netlink-lua
|
||||
, fennel
|
||||
}:
|
||||
let packages = [
|
||||
linotify
|
||||
anoia
|
||||
fennel
|
||||
netlink-lua
|
||||
lua.pkgs.luafilesystem
|
||||
];
|
||||
join = ps: builtins.concatStringsSep ";" ps;
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
{:event "newlink"
|
||||
:hwaddr "00:00:00:00:00:00"
|
||||
:index 1
|
||||
:mtu 65536
|
||||
:name "lo"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "50:3e:aa:08:df:52"
|
||||
:index 2
|
||||
:mtu 1500
|
||||
:name "enp1s0"
|
||||
:running "no"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "1c:1b:0d:9c:39:2d"
|
||||
:index 3
|
||||
:mtu 1500
|
||||
:name "enp0s31f6"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "da:4d:53:c3:54:43"
|
||||
:index 4
|
||||
:mtu 1500
|
||||
:name "vbridge0"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "00:28:f8:69:fa:14"
|
||||
:index 6
|
||||
:mtu 1500
|
||||
:name "wlp4s0"
|
||||
:running "no"
|
||||
:stamp 857161382
|
||||
:up "no"}
|
||||
{:event "newlink"
|
||||
:hwaddr "02:42:b1:e6:e5:bd"
|
||||
:index 7
|
||||
:mtu 1500
|
||||
:name "br-7ddfef4820c5"
|
||||
:running "no"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "02:42:8d:d4:36:34"
|
||||
:index 8
|
||||
:mtu 1500
|
||||
:name "br-95da8b40a7cc"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "02:42:bc:cf:a8:5e"
|
||||
:index 9
|
||||
:mtu 1500
|
||||
:name "docker0"
|
||||
:running "no"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "b6:66:50:69:33:a6"
|
||||
:index 11
|
||||
:mtu 1500
|
||||
:name "veth2ff6ec3"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "e6:94:c8:48:f3:97"
|
||||
:index 13
|
||||
:mtu 1500
|
||||
:name "veth0913974"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "9a:87:d8:f2:c6:96"
|
||||
:index 15
|
||||
:mtu 1500
|
||||
:name "veth0e74156"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "5e:d2:92:b9:5f:6d"
|
||||
:index 17
|
||||
:mtu 1500
|
||||
:name "veth89a36b3"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "ca:88:3f:09:bc:51"
|
||||
:index 19
|
||||
:mtu 1500
|
||||
:name "veth73c1e0b"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "b6:7d:5c:38:89:1d"
|
||||
:index 21
|
||||
:mtu 1500
|
||||
:name "dummy0"
|
||||
:running "no"
|
||||
:stamp 857161382
|
||||
:up "no"}
|
||||
{:event "newlink"
|
||||
:hwaddr "52:f0:46:da:0c:0c"
|
||||
:index 22
|
||||
:mtu 1500
|
||||
:name "dummy1"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "00:22:61:3d:f7:54"
|
||||
:index 4
|
||||
:ip "192.168.8.140"
|
||||
:probes 1
|
||||
:stamp 857165355
|
||||
:state "stale"}
|
||||
{:event "delneigh"
|
||||
:hwaddr "5c:60:ba:58:34:93"
|
||||
:index 3
|
||||
:stamp 857166891
|
||||
:state "stale"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "80:64:6f:9e:15:02"
|
||||
:index 4
|
||||
:ip "192.168.8.161"
|
||||
:probes 1
|
||||
:stamp 857172523
|
||||
:state "stale"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "e4:95:6e:42:c2:6c"
|
||||
:index 3
|
||||
:stamp 857174763
|
||||
:state "reachable"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "e4:b3:18:76:1b:23"
|
||||
:index 4
|
||||
:ip "2001:8b0:de3a:40de:4708:c700:4de2:9264"
|
||||
:probes 1
|
||||
:stamp 857175595
|
||||
:state "stale"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "80:64:6f:9e:10:c6"
|
||||
:index 4
|
||||
:ip "192.168.8.53"
|
||||
:probes 1
|
||||
:stamp 857176619
|
||||
:state "stale"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "80:64:6f:9e:15:02"
|
||||
:index 4
|
||||
:ip "192.168.8.161"
|
||||
:probes 1
|
||||
:stamp 857177643
|
||||
:state "probe"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "80:64:6f:9e:15:02"
|
||||
:index 4
|
||||
:ip "192.168.8.161"
|
||||
:probes 1
|
||||
:stamp 857177644
|
||||
:state "reachable"}
|
||||
{:event "newlink"
|
||||
:hwaddr "b6:7d:5c:38:89:1d"
|
||||
:index 21
|
||||
:mtu 1500
|
||||
:name "dummy0"
|
||||
:running "yes"
|
||||
:stamp 857178258
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "b6:7d:5c:38:89:1d"
|
||||
:index 21
|
||||
:mtu 1500
|
||||
:name "dummy0"
|
||||
:running "no"
|
||||
:stamp 857181661
|
||||
:up "no"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "80:64:6f:9e:10:c6"
|
||||
:index 4
|
||||
:ip "192.168.8.53"
|
||||
:probes 1
|
||||
:stamp 857182251
|
||||
:state "probe"}
|
|
@ -1,52 +1,64 @@
|
|||
(local netlink (require :netlink))
|
||||
(local sock (netlink.socket))
|
||||
(local nl (require :anoia.nl))
|
||||
(local { : assoc : system } (require :anoia))
|
||||
|
||||
; (local { : view} (require :fennel))
|
||||
|
||||
(fn assoc [tbl k v]
|
||||
(tset tbl k v)
|
||||
tbl)
|
||||
|
||||
(fn parse-args [args]
|
||||
(match args
|
||||
["-v" & rest] (assoc (parse-args rest) :verbose true)
|
||||
["-t" timeout & rest] (assoc (parse-args rest) :timeout (tonumber timeout))
|
||||
["-s" service & rest] (assoc (parse-args rest) :service service)
|
||||
[linkname "up"] {:link linkname :expecting "up"}
|
||||
[linkname "running"] {:link linkname :expecting "running"}
|
||||
[linkname "present"] {:link linkname :expecting "present"}
|
||||
[linkname nil] {:link linkname :expecting "present"}
|
||||
_ nil))
|
||||
|
||||
(local parameters
|
||||
(or
|
||||
(parse-args arg)
|
||||
(assert false (.. "Usage: " (. arg 0) " [-v] ifname [present|up|running]"))))
|
||||
(fn event-matches? [params v]
|
||||
(let [got
|
||||
(match v
|
||||
;; - up: Reflects the administrative state of the interface (IFF_UP)
|
||||
;; - running: Reflects the operational state (IFF_RUNNING).
|
||||
{:event "newlink" :name params.link :up :yes :running :yes}
|
||||
{:present true :up true :running true}
|
||||
|
||||
(fn run-events [evs]
|
||||
(each [_ v (ipairs evs)]
|
||||
(let [got
|
||||
(match v
|
||||
;; - up: Reflects the administrative state of the interface (IFF_UP)
|
||||
;; - running: Reflects the operational state (IFF_RUNNING).
|
||||
{:event "newlink" :name parameters.link :up :yes :running :yes}
|
||||
{:present true :up true :running true}
|
||||
{:event "newlink" :name params.link :up :yes}
|
||||
{:present :true :up true}
|
||||
|
||||
{:event "newlink" :name parameters.link :up :yes}
|
||||
{:present :true :up true}
|
||||
{:event "newlink" :name params.link}
|
||||
{:present true }
|
||||
|
||||
{:event "newlink" :name parameters.link}
|
||||
{:present true }
|
||||
_
|
||||
{})]
|
||||
(not (not (. got params.expecting)))))
|
||||
|
||||
_
|
||||
{})]
|
||||
(when (. got parameters.expecting)
|
||||
(os.exit 0)))))
|
||||
(var up :unknown)
|
||||
(fn toggle-service [service wanted?]
|
||||
(when (not (= up wanted?))
|
||||
(set up
|
||||
(if wanted?
|
||||
(pcall system (.. "s6-rc -u change " service))
|
||||
(not (pcall system (.. "s6-rc -d change " service)))))
|
||||
))
|
||||
|
||||
(fn run [args event-fn]
|
||||
(set up :unknown)
|
||||
(let [parameters
|
||||
(assert (parse-args args)
|
||||
(.. "Usage: ifwait [-v] ifname [present|up|running]"))]
|
||||
(when parameters.verbose
|
||||
(print (.. "ifwait: waiting for "
|
||||
parameters.link " to be " parameters.expecting)))
|
||||
|
||||
(when parameters.verbose
|
||||
(print (.. (. arg 0) ": waiting for "
|
||||
parameters.link " to be " parameters.expecting)))
|
||||
(if parameters.service
|
||||
(each [e (event-fn)]
|
||||
(if (= e.name parameters.link)
|
||||
(toggle-service parameters.service (event-matches? parameters e))))
|
||||
(each [e (event-fn)
|
||||
&until (event-matches? parameters e)]
|
||||
true))))
|
||||
|
||||
(run-events (sock:query {:link true}))
|
||||
(when (not (= (. arg 0) "test"))
|
||||
(run arg #(nl.events {:link true})))
|
||||
|
||||
(while (sock:poll) (run-events (sock:event)))
|
||||
{ : run }
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
(local { : view &as fennel } (require :fennel))
|
||||
(local anoia (require :anoia))
|
||||
|
||||
(var fake-system (fn [s] (print "executing " s)))
|
||||
(tset anoia :system #(fake-system $1))
|
||||
|
||||
(macro expect= [actual expected]
|
||||
`(let [ve# (view ,expected)
|
||||
va# (view ,actual)]
|
||||
(when (not (= ve# va#))
|
||||
(assert false
|
||||
(.. "\nexpected " ve# "\ngot " va#)
|
||||
))))
|
||||
|
||||
(fn event-generator [events]
|
||||
(coroutine.wrap
|
||||
(fn []
|
||||
(each [_ e (ipairs events)] (coroutine.yield e)))))
|
||||
|
||||
(fn file-events [path]
|
||||
(let [data (with-open [e (io.open path "r")] (e:read "*a"))
|
||||
parse (fennel.parser data)]
|
||||
(icollect [_ ast parse]
|
||||
ast)))
|
||||
|
||||
(set _G.arg (doto [] (tset 0 "test")))
|
||||
(local ifwait (require :ifwait))
|
||||
|
||||
(let [gen (event-generator (file-events "events-fixture"))]
|
||||
(ifwait.run ["dummy0" "up"] #gen)
|
||||
(match (pcall gen)
|
||||
(true _) true
|
||||
(false msg) (error "didn't detect dummy0 up event")))
|
||||
|
||||
(var upsies [])
|
||||
(set fake-system
|
||||
(fn [s]
|
||||
(if (s:match "-u change addmember")
|
||||
(table.insert upsies :u)
|
||||
(s:match "-d change addmember")
|
||||
(table.insert upsies :d))))
|
||||
|
||||
(fn newlink [name up running]
|
||||
{:event "newlink"
|
||||
:hwaddr "b6:7d:5c:38:89:1d"
|
||||
:index (string.unpack ">i2" name)
|
||||
:mtu 1500
|
||||
: name
|
||||
: running
|
||||
:stamp 857161382
|
||||
: up })
|
||||
|
||||
"when it gets events that don't match the interface, nothing happens"
|
||||
|
||||
(let [gen (-> [(newlink "eth1" "no" "no")] event-generator)]
|
||||
(set upsies [])
|
||||
(ifwait.run [ "-s" "addmember" "dummy0" "up"] #gen)
|
||||
(expect= upsies []))
|
||||
|
||||
"when it gets an event that should start the service, the service starts"
|
||||
|
||||
(let [gen (->
|
||||
[(newlink "dummy0" "no" "no")
|
||||
(newlink "dummy0" "yes" "no")
|
||||
(newlink "eth1" "no" "no")]
|
||||
event-generator)]
|
||||
(set upsies [])
|
||||
(ifwait.run ["-s" "addmember" "dummy0" "up"] #gen)
|
||||
(expect= upsies [:d :u]))
|
||||
|
||||
"when it gets an event that should stop the service, the service stops"
|
||||
|
||||
(let [gen (->
|
||||
[(newlink "dummy0" "no" "no")
|
||||
(newlink "dummy0" "yes" "no")
|
||||
(newlink "dummy0" "no" "no")
|
||||
]
|
||||
event-generator)]
|
||||
(set upsies [])
|
||||
(ifwait.run ["-s" "addmember" "dummy0" "up"] #gen)
|
||||
(expect= upsies [:d :u :d]))
|
||||
|
||||
"it does not call s6-rc again if the service is already in required state"
|
||||
|
||||
(let [gen (->
|
||||
[(newlink "dummy0" "no" "no")
|
||||
(newlink "dummy0" "yes" "no")
|
||||
(newlink "dummy0" "yes" "yes")
|
||||
(newlink "dummy0" "yes" "yes")
|
||||
(newlink "dummy0" "yes" "no")
|
||||
(newlink "dummy0" "no" "no")
|
||||
]
|
||||
event-generator)]
|
||||
(set upsies [])
|
||||
(ifwait.run ["-s" "addmember" "dummy0" "up"] #gen)
|
||||
(expect= upsies [:d :u :d]))
|
||||
|
||||
"it handles an error return from s6-rc"
|
||||
|
||||
(set fake-system
|
||||
(fn [s]
|
||||
(if (s:match "-u change addmember")
|
||||
(table.insert upsies :u)
|
||||
(s:match "-d change addmember")
|
||||
(table.insert upsies :d))
|
||||
(error "false")
|
||||
))
|
||||
|
||||
(let [gen (->
|
||||
[(newlink "dummy0" "yes" "no")
|
||||
(newlink "dummy0" "yes" "yes")
|
||||
(newlink "dummy0" "yes" "yes")
|
||||
(newlink "dummy0" "yes" "no")
|
||||
(newlink "dummy0" "no" "no")
|
||||
]
|
||||
event-generator)]
|
||||
(set upsies [])
|
||||
(ifwait.run ["-s" "addmember" "dummy0" "up"] #gen)
|
||||
(expect= upsies [:u :u :u :u]))
|
Loading…
Reference in New Issue