kexec: restore static ips after kexec

This commit is contained in:
lassulus 2022-11-24 17:30:37 +00:00
parent 65227bf951
commit 985547acc6
2 changed files with 103 additions and 0 deletions

View file

@ -29,6 +29,11 @@
for p in /etc/ssh/ssh_host_*; do for p in /etc/ssh/ssh_host_*; do
cp -a "$p" ssh cp -a "$p" ssh
done done
# save the networking config for later use
ip --json addr > addrs.json
ip --json route > routes.json
find | cpio -o -H newc | gzip -9 > ../extra.gz find | cpio -o -H newc | gzip -9 > ../extra.gz
popd popd
cat "''${SCRIPT_DIR}/initrd" extra.gz > final-initrd cat "''${SCRIPT_DIR}/initrd" extra.gz > final-initrd
@ -76,14 +81,29 @@
# for detection if we are on kexec # for detection if we are on kexec
environment.etc.is_kexec.text = "true"; environment.etc.is_kexec.text = "true";
systemd.services.restoreNetwork = {
path = [
pkgs.iproute2
];
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig.ExecStart = "/run/current-system/sw/bin/restore_network /root/network/addrs.json /root/network/routes.json";
};
environment.systemPackages = [
(pkgs.writers.writePython3Bin "restore_network" { flakeIgnore = ["E501"]; } ./restore_routes.py)
];
# Restore ssh host and user keys if they are available. # Restore ssh host and user keys if they are available.
# This avoids warnings of unknown ssh keys. # This avoids warnings of unknown ssh keys.
boot.initrd.postMountCommands = '' boot.initrd.postMountCommands = ''
mkdir -m 700 -p /mnt-root/root/.ssh mkdir -m 700 -p /mnt-root/root/.ssh
mkdir -m 755 -p /mnt-root/etc/ssh mkdir -m 755 -p /mnt-root/etc/ssh
mkdir -m 755 -p /mnt-root/root/network
if [[ -f ssh/authorized_keys ]]; then if [[ -f ssh/authorized_keys ]]; then
install -m 400 ssh/authorized_keys /mnt-root/root/.ssh install -m 400 ssh/authorized_keys /mnt-root/root/.ssh
fi fi
install -m 400 ssh/ssh_host_* /mnt-root/etc/ssh install -m 400 ssh/ssh_host_* /mnt-root/etc/ssh
cp *.json /mnt-root/root/network/
''; '';
} }

83
nix/restore_routes.py Normal file
View file

@ -0,0 +1,83 @@
import json
import sys
import subprocess
def filter_interfaces(network):
output = []
for net in network:
if net["ifname"] == "lo":
continue
addr_info = []
for addr in net["addr_info"]:
if addr.get("dynamic", False):
pass
elif addr["local"].startswith("fe80"):
pass
else:
addr_info.append(addr)
if addr_info != []:
net["addr_info"] = addr_info
output.append(net)
return output
def main():
with open(sys.argv[1]) as f:
addresses = json.load(f)
with open(sys.argv[2]) as f:
routes = json.load(f)
relevant_interfaces = filter_interfaces(addresses)
current_interfaces = json.loads(
subprocess.run(
["ip", "--json", "addr"],
capture_output=True,
).stdout
)
for interface in relevant_interfaces:
for current_interface in current_interfaces:
if "address" in interface and "address" in current_interface:
if interface["address"] == current_interface["address"]:
for addr in interface["addr_info"]:
subprocess.run(
[
"ip",
"addr",
"add",
"dev",
current_interface["ifname"],
f'{addr["local"]}/{addr["prefixlen"]}',
]
)
for route in routes:
if route["dev"] == interface["ifname"]:
if route.get("gateway", False):
subprocess.run(
[
"ip",
"route",
"add",
route["dst"],
"via",
route["gateway"],
"dev",
current_interface["ifname"],
]
)
else:
subprocess.run(
[
"ip",
"route",
"add",
route["dst"],
"dev",
current_interface["ifname"],
]
)
if __name__ == "__main__":
main()