Compare commits
15 Commits
83e346d5a0
...
a873dc6608
Author | SHA1 | Date |
---|---|---|
Daniel Barlow | a873dc6608 | |
Daniel Barlow | 2fb4756a7f | |
Daniel Barlow | 04f5174425 | |
Daniel Barlow | dca2e4def1 | |
Daniel Barlow | b60126775a | |
Daniel Barlow | 76f11bcc93 | |
Daniel Barlow | efcfdcc21d | |
Daniel Barlow | 77f1a78331 | |
Daniel Barlow | 28a5dec7dd | |
Daniel Barlow | fad0a47b75 | |
Daniel Barlow | af52aafc84 | |
Daniel Barlow | 34442b6069 | |
Daniel Barlow | b8a46fc05e | |
Daniel Barlow | 8ac2c6cec1 | |
Daniel Barlow | 8879b2d1ba |
68
THOUGHTS.txt
68
THOUGHTS.txt
|
@ -4322,6 +4322,16 @@ set_link virtio-net-pci.0 on
|
|||
|
||||
See if both devices are bridge members
|
||||
|
||||
disable again,check if back to starting position
|
||||
|
||||
|
||||
Wed Mar 13 00:00:16 GMT 2024
|
||||
|
||||
aside: "trigger" is the least bad word I've thought of so far for
|
||||
these services that stop/start other services
|
||||
|
||||
telent: yeah, in general 'ps afuxww' (or s6-ps -H :)) is the way to solve this, look for hung s6-rc processes and in particular their s6-svlisten1 children, where the command line will show what service is still waiting for readiness
|
||||
|
||||
Wed Mar 20 19:34:36 GMT 2024
|
||||
|
||||
Because I forgot hoe to rebuild rotuer, I tihnk it is time to improve
|
||||
|
@ -4344,3 +4354,61 @@ just now but it does mean we can punt on specifying the device inside the
|
|||
liminix-config which is unreasonably circular.
|
||||
|
||||
Maybe we'll just chuck a makefile in telent-nixos-config
|
||||
|
||||
Fri Mar 22 22:14:32 GMT 2024
|
||||
|
||||
For the service failover milestone we said
|
||||
|
||||
a. A configuration demonstrating a service which is restarted when it crashes
|
||||
b. A failover config where service B runs iff service A is unavailable
|
||||
c. A config showing different pppd behaviour when interface is flakey (retry) vs ppp password is wrong (report error, wait for resolution)
|
||||
|
||||
Sun Mar 24 23:41:27 GMT 2024
|
||||
|
||||
TODO
|
||||
|
||||
1) make liminix-rebuild bounce only affected services instead of
|
||||
full reboot (what does it do about triggered services?)
|
||||
2) sniproxy
|
||||
|
||||
3) see if arhcive still works. usb disk hotplug would be a good candidate for
|
||||
switching to triggers
|
||||
|
||||
Mon Mar 25 19:35:47 GMT 2024
|
||||
|
||||
to make the liminix-rebuild thing restart only affected services, it needs to
|
||||
know when the new service is not like the old one. By default it does not
|
||||
restart a service with a changed up/down/run script unless the name has
|
||||
also changed, so we need to figure out how to generate a "conversion"
|
||||
file with the services that are different
|
||||
|
||||
pkgs/s6-rc-database/default.nix creates $out/compiled, we could add
|
||||
$out/hashes to this
|
||||
|
||||
the other thing making this fun is that we will need to run `activate`
|
||||
(which is usually done in preinit) otherwise the new configuration's
|
||||
fhs directories won't exist.
|
||||
|
||||
so the plan woyuld be
|
||||
|
||||
in liminix-rebuild, when reboot was not chosen,
|
||||
|
||||
- run activate
|
||||
- compare /run/s6-rc/compiled/hashes (old services) with
|
||||
/etc/s6-rc/compiled/hashes (new services)
|
||||
|
||||
- whenever both files have the same column 1 and different
|
||||
column 2, add that name to restart list
|
||||
|
||||
(need to turn restarts.fnl into a lua script)
|
||||
|
||||
s6-rc-update /etc/s6-rc/compiled/hashes restarts
|
||||
|
||||
Tue Mar 26 23:18:53 GMT 2024
|
||||
|
||||
activate overwrites /etc/s6-rc/compiled, which is a problem because
|
||||
s6-rc-update expects to find the old compiled database here so that
|
||||
it can know what to update
|
||||
|
||||
Maybe config.filesystem should specify /etc/s6-rc/compiled.new
|
||||
and something in early boot could symlink /etc/s6-rc/compiled to it
|
||||
|
|
|
@ -136,6 +136,7 @@
|
|||
};
|
||||
extraPatchPhase = ''
|
||||
${openwrt.applyPatches.ramips}
|
||||
${openwrt.applyPatches.rt2x00}
|
||||
'';
|
||||
config = {
|
||||
|
||||
|
|
|
@ -29,6 +29,10 @@ in {
|
|||
services = mkOption {
|
||||
type = types.attrsOf type_service;
|
||||
};
|
||||
system.callService = mkOption {
|
||||
type = types.functionTo (types.functionTo types.anything);
|
||||
};
|
||||
|
||||
filesystem = mkOption {
|
||||
type = types.anything;
|
||||
description = ''
|
||||
|
@ -111,6 +115,31 @@ in {
|
|||
"fw_devlink=off"
|
||||
] ++ lib.optional (config.rootOptions != null) "rootflags=${config.rootOptions}";
|
||||
|
||||
system.callService = path : parameters :
|
||||
let
|
||||
typeChecked = caller: type: value:
|
||||
let
|
||||
inherit (lib) types mergeDefinitions;
|
||||
defs = [{ file = caller; inherit value; }];
|
||||
type' = types.submodule { options = type; };
|
||||
in (mergeDefinitions [] type' defs).mergedValue;
|
||||
cp = lib.callPackageWith(pkgs // { svc = config.system.service; });
|
||||
pkg = cp path {};
|
||||
checkTypes = t : p : typeChecked (builtins.toString path) t p;
|
||||
in {
|
||||
inherit parameters;
|
||||
build = { dependencies ? [], ... } @ args :
|
||||
let
|
||||
s = pkg (checkTypes parameters
|
||||
(builtins.removeAttrs args ["dependencies"]));
|
||||
in s.overrideAttrs (o: {
|
||||
dependencies = (builtins.map (d: d.name) dependencies) ++ o.dependencies;
|
||||
buildInputs = dependencies ++ o.buildInputs;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
users.root = {
|
||||
uid = 0; gid= 0; gecos = "Root of all evaluation";
|
||||
dir = "/home/root/";
|
||||
|
|
|
@ -14,6 +14,8 @@ let
|
|||
inherit (pkgs) liminix;
|
||||
in
|
||||
{
|
||||
imports = [ ../ifwait ];
|
||||
|
||||
options = {
|
||||
system.service.bridge = {
|
||||
primary = mkOption { type = liminix.lib.types.serviceDefn; };
|
||||
|
@ -27,7 +29,7 @@ in
|
|||
description = "bridge interface name to create";
|
||||
};
|
||||
};
|
||||
members = liminix.callService ./members.nix {
|
||||
members = config.system.callService ./members.nix {
|
||||
primary = mkOption {
|
||||
type = liminix.lib.types.interface;
|
||||
description = "primary bridge interface";
|
||||
|
@ -47,5 +49,5 @@ in
|
|||
# a better way to test for the existence of vlan config:
|
||||
# maybe the module should set an `enabled` attribute?
|
||||
BRIDGE_VLAN_FILTERING = "y";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
liminix
|
||||
, ifwait
|
||||
, lib
|
||||
, svc
|
||||
}:
|
||||
{ members, primary } :
|
||||
|
||||
|
@ -10,14 +11,20 @@ let
|
|||
inherit (liminix.services) bundle oneshot;
|
||||
inherit (lib) mkOption types;
|
||||
addif = member :
|
||||
oneshot {
|
||||
name = "${primary.name}.member.${member.name}";
|
||||
up = ''
|
||||
dev=$(output ${member} ifname)
|
||||
${ifwait}/bin/ifwait $dev running && ip link set dev $dev master $(output ${primary} ifname)
|
||||
'';
|
||||
down = "ip link set dev $(output ${member} ifname) nomaster";
|
||||
# how do we get sight of services from here? maybe we need to
|
||||
# implement ifwait as a regualr derivation instead of a
|
||||
# servicedefinition
|
||||
svc.ifwait.build {
|
||||
state = "running";
|
||||
interface = member;
|
||||
dependencies = [ primary member ];
|
||||
service = oneshot {
|
||||
name = "${primary.name}.member.${member.name}";
|
||||
up = ''
|
||||
ip link set dev $(output ${member} ifname) master $(output ${primary} ifname)
|
||||
'';
|
||||
down = "ip link set dev $(output ${member} ifname) nomaster";
|
||||
};
|
||||
};
|
||||
in bundle {
|
||||
name = "${primary.name}.members";
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{ config, pkgs, lib, ... } :
|
||||
let
|
||||
inherit (pkgs) liminix;
|
||||
inherit (lib) mkOption types;
|
||||
in {
|
||||
options.system.service.ifwait =
|
||||
mkOption { type = liminix.lib.types.serviceDefn; };
|
||||
|
||||
config.system.service.ifwait = config.system.callService ./ifwait.nix {
|
||||
state = mkOption { type = types.str; };
|
||||
interface = mkOption {
|
||||
type = liminix.lib.types.interface;
|
||||
};
|
||||
service = mkOption {
|
||||
type = liminix.lib.types.service;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{ ifwait, liminix } :
|
||||
{
|
||||
state
|
||||
, interface
|
||||
, service
|
||||
}:
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
in longrun {
|
||||
name = "ifwait.${interface.name}";
|
||||
buildInputs = [ service ];
|
||||
run = ''
|
||||
${ifwait}/bin/ifwait -s ${service.name} $(output ${interface} ifname) ${state}
|
||||
'';
|
||||
}
|
|
@ -34,7 +34,7 @@ fi
|
|||
|
||||
### If your services are managed by s6-rc:
|
||||
### (replace /run/service with your scandir)
|
||||
s6-rc-init /run/service -d -c /etc/s6-rc/compiled
|
||||
s6-rc-init -d -c /etc/s6-rc/compiled /run/service
|
||||
|
||||
|
||||
### 2. Starting the wanted set of services
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
(when (not (= up wanted?))
|
||||
(set up
|
||||
(if wanted?
|
||||
(pcall system (.. "s6-rc -u change " service))
|
||||
(not (pcall system (.. "s6-rc -d change " service)))))
|
||||
(pcall system (.. "s6-rc -b -u change " service))
|
||||
(not (pcall system (.. "s6-rc -b -d change " service)))))
|
||||
))
|
||||
|
||||
(fn run [args event-fn]
|
||||
|
|
|
@ -11,7 +11,7 @@ test -n "$contents" && for d in $contents; do
|
|||
touch $out/${name}/contents.d/$d
|
||||
done
|
||||
|
||||
for i in run notification-fd up down consumer-for producer-for pipeline-name ; do
|
||||
for i in timeout-up timeout-down run notification-fd up down consumer-for producer-for pipeline-name ; do
|
||||
test -n "$(printenv $i)" && (echo "$(printenv $i)" > $out/${name}/$i)
|
||||
done
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@ let
|
|||
, producer-for ? null
|
||||
, consumer-for ? null
|
||||
, pipeline-name ? null
|
||||
, timeout-up ? 30000 # milliseconds
|
||||
, timeout-down ? 0
|
||||
, dependencies ? []
|
||||
, contents ? []
|
||||
, buildInputs ? []
|
||||
|
@ -39,7 +41,7 @@ let
|
|||
# we use stdenvNoCC to avoid generating derivations with names
|
||||
# like foo.service-mips-linux-musl
|
||||
inherit name serviceType up down run notification-fd
|
||||
producer-for consumer-for pipeline-name;
|
||||
producer-for consumer-for pipeline-name timeout-up timeout-down;
|
||||
buildInputs = buildInputs ++ dependencies ++ contents;
|
||||
dependencies = builtins.map (d: d.name) dependencies;
|
||||
contents = builtins.map (d: d.name) contents;
|
||||
|
@ -52,6 +54,7 @@ let
|
|||
, outputs ? []
|
||||
, notification-fd ? null
|
||||
, dependencies ? []
|
||||
, buildInputs ? []
|
||||
, ...
|
||||
} @ args:
|
||||
let logger = service {
|
||||
|
@ -63,7 +66,7 @@ let
|
|||
pipeline-name = "${name}-pipeline";
|
||||
};
|
||||
in service (args // {
|
||||
buildInputs = [ logger ];
|
||||
buildInputs = buildInputs ++ [ logger ];
|
||||
serviceType = "longrun";
|
||||
run = serviceScript "${run}\n${cleanupScript name}";
|
||||
producer-for = "${name}-log";
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
ssh_command=${SSH_COMMAND-ssh}
|
||||
if [ "$1" = "--no-reboot" ] ; then
|
||||
reboot="true"
|
||||
shift
|
||||
else
|
||||
reboot="reboot"
|
||||
fi
|
||||
|
||||
reboot="reboot"
|
||||
|
||||
case "$1" in
|
||||
"--no-reboot")
|
||||
unset reboot
|
||||
shift
|
||||
;;
|
||||
"--fast")
|
||||
reboot="soft"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
|
||||
target_host=$1
|
||||
shift
|
||||
|
@ -20,7 +27,16 @@ if toplevel=$(nix-build "$@" -A outputs.systemConfiguration --no-out-link); then
|
|||
echo systemConfiguration $toplevel
|
||||
min-copy-closure $target_host $toplevel
|
||||
$ssh_command $target_host $toplevel/bin/install
|
||||
$ssh_command $target_host "sync; source /etc/profile; reboot -f"
|
||||
case "$reboot" in
|
||||
reboot)
|
||||
$ssh_command $target_host "sync; source /etc/profile; reboot"
|
||||
;;
|
||||
soft)
|
||||
$ssh_command $target_host $toplevel/bin/restart-services
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo Rebuild failed
|
||||
fi
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
fetchFromGitHub
|
||||
, writeShellScript
|
||||
, pkgsBuildBuild
|
||||
}:
|
||||
let
|
||||
src = fetchFromGitHub {
|
||||
|
@ -36,4 +37,25 @@ in {
|
|||
applyPatches.ramips = doPatch "ramips";
|
||||
applyPatches.mediatek = doPatch "mediatek"; # aarch64
|
||||
applyPatches.mvebu = doPatch "mvebu"; # arm
|
||||
|
||||
applyPatches.rt2x00 = ''
|
||||
PATH=${pkgsBuildBuild.patchutils}/bin:$PATH
|
||||
for i in ${src}/package/kernel/mac80211/patches/rt2x00/6*.patch ; do
|
||||
fixed=$(basename $i).fixed
|
||||
sed '/depends on m/d' < $i | sed 's/CPTCFG_/CONFIG_/g' | recountdiff | filterdiff -x '*/local-symbols' > $fixed
|
||||
case $fixed in
|
||||
606-*)
|
||||
;;
|
||||
611-*)
|
||||
filterdiff -x '*/rt2x00.h' < $fixed | patch --forward -p1
|
||||
;;
|
||||
601-*|607-*)
|
||||
filterdiff -x '*/rt2x00_platform.h' < $fixed | patch --forward -p1
|
||||
;;
|
||||
*)
|
||||
cat $fixed | patch --forward -p1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -21,11 +21,22 @@ in stdenvNoCC.mkDerivation {
|
|||
if test -d $i; then
|
||||
for j in $i/* ; do
|
||||
if test -f $j/type ; then
|
||||
case $(cat $j/type) in
|
||||
longrun|oneshot)
|
||||
# s6-rc-update only wants oneshots in its
|
||||
# restarts file
|
||||
echo $(basename $j) " " $i >> $out/hashes
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
srcs="$srcs $i"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
s6-rc-compile $out/compiled $srcs
|
||||
'';
|
||||
}
|
||||
s6-rc-db -c $out/compiled contents default
|
||||
mv $out/hashes $out/compiled
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
{
|
||||
writeText
|
||||
, writeFennelScript
|
||||
, lib
|
||||
, s6-init-bin
|
||||
, closureInfo
|
||||
|
@ -52,7 +53,7 @@ let
|
|||
chown = if uid>0 || gid>0
|
||||
then "\nCHOWN(${qpathname},${toString uid},${toString gid});\n"
|
||||
else "";
|
||||
in "${cmd} ${chown}";
|
||||
in "unlink(${qpathname}); ${cmd} ${chown}";
|
||||
in mapAttrsToList (makeFile prefix) attrset;
|
||||
activateScript = attrset: writeText "makedevs.c" ''
|
||||
#include "defs.h"
|
||||
|
@ -80,6 +81,7 @@ in attrset:
|
|||
cp $closure/store-paths $out/etc/nix-store-paths
|
||||
$STRIP --remove-section=.note --remove-section=.comment --strip-all makedevs -o $out/bin/activate
|
||||
ln -s ${s6-init-bin}/bin/init $out/bin/init
|
||||
cp -p ${writeFennelScript "restart-services" [] ./restart-services.fnl} $out/bin/restart-services
|
||||
cat > $out/bin/install <<EOF
|
||||
#!/bin/sh -e
|
||||
prefix=\''${1-/}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
(fn hashes-from-file [name]
|
||||
(with-open [f (assert (io.open name :r) name)]
|
||||
(accumulate [h []
|
||||
l #(f:read "*l")]
|
||||
(let [(name hash) (string.match l "([^%s]+) +([^%s]+)")]
|
||||
(if name
|
||||
(doto h (tset name hash))
|
||||
h)))))
|
||||
|
||||
(fn write-restarts [old new]
|
||||
(let [old-hashes (hashes-from-file old)
|
||||
new-hashes (hashes-from-file new)]
|
||||
(with-open [f (io.open "/tmp/restarts" :w)]
|
||||
(each [n h (pairs old-hashes)]
|
||||
(when (not (= h (. new-hashes n)))
|
||||
(f:write (.. n " restart\n")))))))
|
||||
|
||||
(fn exec [text command]
|
||||
(io.write (.. text ": "))
|
||||
(match (os.execute command)
|
||||
res (print "[OK]")
|
||||
(nil err) (error (.. "[FAILED " err "]"))))
|
||||
|
||||
(let [mypath (: (. arg 0) :match "(.*/)")
|
||||
activate (.. mypath "activate /")
|
||||
old-compiled "/run/s6-rc/compiled/"
|
||||
new-compiled "/etc/s6-rc/compiled/"]
|
||||
|
||||
(exec "installing FHS files" activate)
|
||||
|
||||
(write-restarts (.. old-compiled "hashes") (.. new-compiled "hashes"))
|
||||
|
||||
(exec "updating service database"
|
||||
(.. "s6-rc-update -f /tmp/restarts " new-compiled))
|
||||
|
||||
(exec "starting services" (.. "s6-rc -u -p change default"))
|
||||
)
|
|
@ -0,0 +1,12 @@
|
|||
loopback /nix/store/3k7yp08465k8z8a1514slansj0hbrvbq-loopback
|
||||
default /nix/store/5247rr0mcr17x9lkaqjiywxmn4q3ibgd-default
|
||||
lan.link.a.10.3.0.1 /nix/store/99ic5bryzbx12ip4v8sh9cdrv15c8qwl-lan.link.a.10.3.0.1
|
||||
lo.link.a.-1 /nix/store/a2yvj42ghcg8iyvi51zcmzmpwwkrx30l-lo.link.a.-1
|
||||
sshd /nix/store/afgznmavi6s9dxkv4vnn9xwd7qz5kk35-sshd
|
||||
lo.link /nix/store/dz0nvlf16lqv9yndas0sk0xqh7jvx8gm-lo.link
|
||||
lo.link.a.127.0.0.1 /nix/store/jl018kbgxcnyb70s0cfw19q1zqa0pval-lo.link.a.127.0.0.1
|
||||
lan.link /nix/store/lxvmhb7ax46s2akj9lsivcq494kmx0hm-lan.link
|
||||
lan.link.a.10.3.0.1.dnsmasq-log /nix/store/rk8265ikd9lj3fpibyrw0kal32h0ksqg-lan.link.a.10.3.0.1.dnsmasq-log
|
||||
hostname /nix/store/xfy0ymvnd0zv6wcd26h405f85hfkd8wq-hostname
|
||||
sshd-log /nix/store/xj58nxvkacsjg3rvwb4bxcqnhaav4d3s-sshd-log
|
||||
lan.link.a.10.3.0.1.dnsmasq /nix/store/z4l7h9pr4an9aq921cs9wrlvf9b8xr48-lan.link.a.10.3.0.1.dnsmasq
|
|
@ -0,0 +1,12 @@
|
|||
loopback /nix/store/3k7yp08465k8z8a1514slansj0hbrvbq-loopback
|
||||
default /nix/store/5247rr0mcr17x9lkaqjiywxmn4q3ibgd-default
|
||||
lan.link.a.10.3.0.1 /nix/store/99ic5bryzbx12ip4v8sh9cdrv15c8qwl-lan.link.a.10.3.0.1
|
||||
lo.link.a.-1 /nix/store/a2yvj42ghcg8iyvi51zcmzmpwwkrx30l-lo.link.a.-1
|
||||
sshd /nix/store/afgznmavi6s9dxkv4vnn9xwd7qz5kk35-sshd
|
||||
lo.link /nax/store/dz0nvlf16lqv9yndas0sk0xqh7jvx8gm-lo.link
|
||||
lo.link.a.127.0.0.1 /nix/store/jl018kbgxcnyb70s0cfw19q1zqa0pval-lo.link.a.127.0.0.1
|
||||
lan.link /nix/store/lxvmhb7ax46s2akj9lsivcq494kmx0hm-lan.link
|
||||
lan.link.a.10.3.0.1.dnsmasq-log /nix/store/rk8265ikd9lj3fpibyrw0kal32h0ksqg-lan.link.a.10.3.0.1.dnsmasq-log
|
||||
hostname /nax/store/xfy0ymvnd0zv6wcd26h405f85hfkd8wq-hostname
|
||||
sshd-log /nax/store/xj58nxvkacsjg3rvwb4bxcqnhaav4d3s-sshd-log
|
||||
|
|
@ -8,4 +8,5 @@
|
|||
min-copy-closure = import ./min-copy-closure/test.nix;
|
||||
fennel = import ./fennel/test.nix;
|
||||
tftpboot = import ./tftpboot/test.nix;
|
||||
updown = import ./updown/test.nix;
|
||||
}
|
||||
|
|
|
@ -32,9 +32,5 @@ in {
|
|||
};
|
||||
|
||||
rootfsType = "jffs2";
|
||||
services.default = lib.mkForce (target {
|
||||
name = "default";
|
||||
contents = with config.services; [ loopback ntp defaultroute4 sshd dhcpv4 ];
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,14 +1,26 @@
|
|||
#!/usr/bin/env nix-shell
|
||||
#! nix-shell -v -i bash -p expect socat
|
||||
|
||||
# This is a test for liminix-rebuild. It's not a CI test because
|
||||
# liminix-rebuild calls nix-build so won't run inside a derivation,
|
||||
# meaning you have to remember to run it manually when changing
|
||||
# liminix-rebuild
|
||||
|
||||
# nix-shell -p expect socat --run "sh ./tests/min-copy-closure/test-liminix-rebuild.sh "
|
||||
|
||||
. tests/test-helpers.sh
|
||||
|
||||
set -e
|
||||
|
||||
while test -n "$1"; do
|
||||
case $1 in
|
||||
--fast)
|
||||
FAST=true
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
here=$(pwd)/tests/min-copy-closure
|
||||
top=$(pwd)
|
||||
|
||||
|
@ -31,7 +43,7 @@ mkdir ./vm
|
|||
|
||||
cat ${rootfs} > rootfs
|
||||
|
||||
truncate -s 24M rootfs
|
||||
truncate -s 32M rootfs
|
||||
resize2fs rootfs
|
||||
|
||||
dd if=rootfs of=disk-image bs=512 seek=4 conv=sync
|
||||
|
@ -50,9 +62,12 @@ echo "READY"
|
|||
touch known_hosts
|
||||
export SSH_COMMAND="ssh -o UserKnownHostsFile=${work}/known_hosts -o StrictHostKeyChecking=no -p 2022 -i ${here}/id"
|
||||
|
||||
(cd ${top} && liminix-rebuild root@localhost -I liminix-config=${here}/with-figlet.nix --arg device "import ./devices/qemu-armv7l")
|
||||
if test -n "$FAST"; then
|
||||
(cd ${top} && liminix-rebuild --fast root@localhost -I liminix-config=${here}/with-figlet.nix --argstr deviceName qemu-armv7l)
|
||||
cd ${work} && expect $here/wait-for-soft-restart.expect
|
||||
else
|
||||
(cd ${top} && liminix-rebuild root@localhost -I liminix-config=${here}/with-figlet.nix --arg device "import ./devices/qemu-armv7l")
|
||||
cd ${work} && expect $here/wait-for-reboot.expect
|
||||
fi
|
||||
|
||||
ls -l vm
|
||||
|
||||
cd ${work} && expect $here/wait-for-reboot.expect
|
||||
cd / ; rm -rf $work
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
proc chat {instr outstr} {
|
||||
expect {
|
||||
$instr { send $outstr }
|
||||
timeout { exit 1 }
|
||||
}
|
||||
}
|
||||
spawn socat unix-connect:vm/console -
|
||||
|
||||
send "exit\r"
|
||||
chat "BusyBox" "\r"
|
||||
chat "#" "stty -echo; type -p figlet\r"
|
||||
chat "figlet-armv7l-unknown-linux" "s6-rc -a list |grep w\\inkle\r"
|
||||
chat "winkle" "poweroff\r"
|
|
@ -5,4 +5,9 @@ send "\r\n"
|
|||
expect {
|
||||
"# " { send "hostname\r\n" };
|
||||
}
|
||||
expect "(none)"
|
||||
|
||||
expect {
|
||||
"(none)" {}
|
||||
"liminix" {}
|
||||
timeout { exit(1) }
|
||||
}
|
|
@ -4,4 +4,11 @@
|
|||
defaultProfile.packages = with pkgs; [
|
||||
figlet
|
||||
];
|
||||
services.ripvanwinkle = pkgs.liminix.services.longrun {
|
||||
name = "winkle";
|
||||
run = ''
|
||||
echo SLEEPING > /dev/console
|
||||
sleep 3600
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
{ config, pkgs, lib, ... } :
|
||||
let
|
||||
inherit (pkgs.liminix.services) bundle oneshot longrun;
|
||||
inherit (pkgs) serviceFns;
|
||||
# EDIT: you can pick your preferred RFC1918 address space
|
||||
# for NATted connections, if you don't like this one.
|
||||
ipv4LocalNet = "10.8.0";
|
||||
svc = config.system.service;
|
||||
|
||||
in rec {
|
||||
imports = [
|
||||
../../modules/bridge
|
||||
../../modules/dhcp6c
|
||||
../../modules/dnsmasq
|
||||
../../modules/firewall
|
||||
../../modules/hostapd
|
||||
../../modules/network
|
||||
../../modules/ssh
|
||||
../../modules/vlan
|
||||
../../modules/wlan.nix
|
||||
];
|
||||
rootfsType = "jffs2";
|
||||
hostname = "updown";
|
||||
|
||||
services.int = svc.network.address.build {
|
||||
interface = svc.bridge.primary.build { ifname = "int"; };
|
||||
family = "inet"; address = "${ipv4LocalNet}.1"; prefixLength = 16;
|
||||
};
|
||||
|
||||
services.bridge = svc.bridge.members.build {
|
||||
primary = services.int;
|
||||
members = with config.hardware.networkInterfaces;
|
||||
[ lan ];
|
||||
};
|
||||
|
||||
services.sshd = svc.ssh.build { };
|
||||
|
||||
# users.root = {
|
||||
# # EDIT: choose a root password and then use
|
||||
# # "mkpasswd -m sha512crypt" to determine the hash.
|
||||
# # It should start wirh $6$.
|
||||
# passwd = "$6$6HG7WALLQQY1LQDE$428cnouMJ7wVmyK9.dF1uWs7t0z9ztgp3MHvN5bbeo0M4Kqg/u2ThjoSHIjCEJQlnVpDOaEKcOjXAlIClHWN21";
|
||||
# openssh.authorizedKeys.keys = [
|
||||
# # EDIT: you can add your ssh pubkey here
|
||||
# # "ssh-rsa AAAAB3NzaC1....H6hKd user@example.com";
|
||||
# ];
|
||||
# };
|
||||
|
||||
defaultProfile.packages = with pkgs; [
|
||||
min-collect-garbage
|
||||
# strace
|
||||
# ethtool
|
||||
tcpdump
|
||||
];
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
set timeout 10
|
||||
|
||||
spawn socat unix-connect:vm/monitor -
|
||||
set monitor_id $spawn_id
|
||||
|
||||
expect "(qemu)"
|
||||
send "set_link virtio-net-pci.1 off\n"
|
||||
expect "(qemu)"
|
||||
send "set_link virtio-net-pci.0 off\n"
|
||||
expect "(qemu)"
|
||||
send "c\r\n"
|
||||
spawn socat unix-connect:vm/console -
|
||||
set console_id $spawn_id
|
||||
|
||||
expect "BusyBox"
|
||||
expect "#" { send "PS1=RE\\ADY_\\ ; stty -echo \r" }
|
||||
expect "READY_" { send "s6-rc -b -a list\r" } ; # -b waits for s6-rc lock
|
||||
expect "READY_" { send "ls /sys/class/net/lan/master\r" }
|
||||
expect {
|
||||
"No such file or directory" { }
|
||||
timeout { exit 1 }
|
||||
}
|
||||
|
||||
expect "READY_" { send "cat /sys/class/net/lan/operstate\r" }
|
||||
expect {
|
||||
"down" { }
|
||||
"up" { exit 1 }
|
||||
}
|
||||
expect "READY_" { send "s6-rc -a -u change\r" }
|
||||
expect {
|
||||
"unable to take locks" { exit 1 }
|
||||
"READY_" { send "\r" }
|
||||
}
|
||||
|
||||
set spawn_id $monitor_id
|
||||
send "\r"
|
||||
expect "(qemu)"
|
||||
send "set_link virtio-net-pci.1 on\n"
|
||||
expect "(qemu)"
|
||||
send "set_link virtio-net-pci.0 on\n"
|
||||
expect "(qemu)"
|
||||
set spawn_id $console_id
|
||||
|
||||
expect "entered forwarding state"
|
||||
send "\r"
|
||||
expect "READY_" { send "cat /sys/class/net/lan/operstate\r" }
|
||||
expect {
|
||||
"down" { exit 1 }
|
||||
"up" { }
|
||||
}
|
||||
|
||||
expect "READY_" { send "cat /sys/class/net/lan/master/uevent\r" }
|
||||
expect {
|
||||
"INTERFACE=int" { }
|
||||
timeout { exit 1 }
|
||||
}
|
||||
|
||||
expect "READY_" { send "s6-rc listall int.link.a.10.8.0.1.member.lan.link ; hostname\r" }
|
||||
|
||||
expect {
|
||||
"updown" {}
|
||||
timeout { exit 1 }
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
liminix
|
||||
, nixpkgs
|
||||
}:
|
||||
let img = (import liminix {
|
||||
device = import "${liminix}/devices/qemu/";
|
||||
liminix-config = ./configuration.nix;
|
||||
}).outputs.vmroot;
|
||||
pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
|
||||
in pkgs.runCommand "check" {
|
||||
nativeBuildInputs = with pkgs; [
|
||||
expect
|
||||
socat
|
||||
] ;
|
||||
} ''
|
||||
mkdir vm
|
||||
${img}/run.sh --flag -S --background ./vm
|
||||
expect ${./script.expect} | tee $out
|
||||
''
|
|
@ -16,7 +16,7 @@ in rec {
|
|||
in svc.network.dhcp.client.build { interface = iface; };
|
||||
|
||||
services.defaultroute4 = svc.network.route.build {
|
||||
via = "$(output ${services.dhcpv4} address)";
|
||||
via = "$(output ${services.dhcpv4} ip)";
|
||||
target = "default";
|
||||
dependencies = [ services.dhcpv4 ];
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue