Compare commits

..

3 commits

Author SHA1 Message Date
Jörg Thalheim
65c6e9d432 disable risv64 on unstable for now 2024-06-27 08:35:30 +02:00
Jörg Thalheim
7582b40ce3 wip: upstream cross fix 2024-06-27 08:32:42 +02:00
Jörg Thalheim
2d72a425a2 add riscv64 kexec image 2024-06-27 08:32:24 +02:00
21 changed files with 241 additions and 524 deletions

View file

@ -19,7 +19,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
- uses: cachix/install-nix-action@V27
with:
nix_path: nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixpkgs-unstable.tar.gz
- name: Build image

View file

@ -11,9 +11,9 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v30
uses: cachix/install-nix-action@V27
- name: Update flake.lock
uses: DeterminateSystems/update-flake-lock@v24
uses: DeterminateSystems/update-flake-lock@v22
with:
pr-labels: |
merge-queue

View file

@ -1,7 +1,7 @@
queue_rules:
- name: default
merge_conditions:
- check-success=buildbot/nix-build
- check-success=buildbot/nix-eval
defaults:
actions:
queue:

View file

@ -11,10 +11,10 @@ Kexec is a mechanism in Linux to load a new kernel from a running Linux to
replace the current kernel. This is useful for booting the Nixos installer from
existing Linux distributions, such as server provider that do not offer a NixOS
option. After running kexec, the NixOS installer exists only in memory. At the
time of writing, this requires secure boot off in BIOS settings and at least 1GB
of physical RAM (swap does not count) in the system. If not enough RAM is available,
the initrd cannot be loaded. Because the NixOS runs only in RAM, users can reformat
all the system's discs to prepare for a new NixOS installation.
time of writing, this requires at least 1GB of physical RAM (swap does not
count) in the system. If not enough RAM is available, the initrd cannot be
loaded. Because the NixOS runs only in RAM, users can reformat all the system's
discs to prepare for a new NixOS installation.
It can be booted as follows by running these commands as root:
@ -36,7 +36,7 @@ integration into automated nixos installation scripts, since you can cleanly
disconnect from the running machine before the kexec takes place. The tarball
is also designed to be run from NixOS, which can be useful for new installations
## Iso installer images
## ISO installer images
This image allows to boot a NixOS installer off a USB-Stick.
This installer has been optimized for remote installation i.e.

View file

@ -2,11 +2,11 @@
"nodes": {
"nixos-stable": {
"locked": {
"lastModified": 1729181673,
"narHash": "sha256-LDiPhQ3l+fBjRATNtnuDZsBS7hqoBtPkKBkhpoBHv3I=",
"lastModified": 1719253556,
"narHash": "sha256-A/76RFUVxZ/7Y8+OMVL1Lc8LRhBxZ8ZE2bpMnvZ1VpY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "4eb33fe664af7b41a4c446f87d20c9a0a6321fa3",
"rev": "fc07dc3bdf2956ddd64f24612ea7fc894933eb2e",
"type": "github"
},
"original": {
@ -18,16 +18,16 @@
},
"nixos-unstable": {
"locked": {
"lastModified": 1729450260,
"narHash": "sha256-3GNZr0V4b19RZ5mlyiY/4F8N2pzitvjDU6aHMWjAqLI=",
"owner": "NixOS",
"lastModified": 1719456624,
"narHash": "sha256-j0iox16+eMO2ptZ/IfM57R/1OpnPu0H03wXwggmLBfg=",
"owner": "jmbaur",
"repo": "nixpkgs",
"rev": "e3f55158e7587c5a5fdb0e86eb7ca4f455f0928f",
"rev": "560cd874a37396968aea0bd9abc54fb1122424b7",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable-small",
"owner": "jmbaur",
"ref": "etc-overlay-cross",
"repo": "nixpkgs",
"type": "github"
}

120
flake.nix
View file

@ -1,53 +1,90 @@
{
description = "NixOS images";
inputs.nixos-unstable.url = "github:NixOS/nixpkgs/nixos-unstable-small";
#inputs.nixos-unstable.url = "github:NixOS/nixpkgs/nixos-unstable-small";
inputs.nixos-unstable.url = "github:jmbaur/nixpkgs/etc-overlay-cross";
inputs.nixos-stable.url = "github:NixOS/nixpkgs/nixos-24.05";
nixConfig.extra-substituters = [ "https://nix-community.cachix.org" ];
nixConfig.extra-trusted-public-keys = [ "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" ];
nixConfig.extra-trusted-public-keys = [
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
];
outputs = { self, nixos-unstable, nixos-stable }:
let
supportedSystems = [ "riscv64-linux" ];
forAllSystems = nixos-unstable.lib.genAttrs supportedSystems;
in
outputs =
{
hydraJobs = { inherit (self) checks; };
packages = forAllSystems (system:
self,
nixos-unstable,
nixos-stable,
}:
let
supportedSystems = [
"aarch64-linux"
"x86_64-linux"
];
forAllSystems = nixos-unstable.lib.genAttrs supportedSystems;
packages = forAllSystems (
system:
let
netboot = nixpkgs: (import (nixpkgs + "/nixos/release.nix") { }).netboot.${system};
kexec-installer = nixpkgs: module: (nixpkgs.legacyPackages.${system}.nixos [ module self.nixosModules.kexec-installer ]).config.system.build.kexecTarball;
netboot-installer = nixpkgs: (nixpkgs.legacyPackages.${system}.nixos [ self.nixosModules.netboot-installer ]).config.system.build.netboot;
image-installer = nixpkgs: (nixpkgs.legacyPackages.${system}.nixos [ self.nixosModules.image-installer ]).config.system.build.isoImage;
kexec-installer =
nixpkgs: modules:
(nixpkgs.legacyPackages.${system}.nixos (modules ++ [ self.nixosModules.kexec-installer ]))
.config.system.build.kexecTarball;
netboot-installer =
nixpkgs:
(nixpkgs.legacyPackages.${system}.nixos [ self.nixosModules.netboot-installer ])
.config.system.build.netboot;
image-installer =
nixpkgs:
(nixpkgs.legacyPackages.${system}.nixos [ self.nixosModules.image-installer ])
.config.system.build.isoImage;
in
{
netboot-nixos-unstable = netboot nixos-unstable;
netboot-nixos-stable = netboot nixos-stable;
kexec-installer-nixos-unstable = kexec-installer nixos-unstable {};
kexec-installer-nixos-stable = kexec-installer nixos-stable {};
kexec-installer-nixos-unstable = kexec-installer nixos-unstable [ ];
kexec-installer-nixos-stable = kexec-installer nixos-stable [ ];
image-installer-nixos-unstable = image-installer nixos-unstable;
image-installer-nixos-stable = image-installer nixos-stable;
kexec-installer-nixos-unstable-noninteractive = kexec-installer nixos-unstable {
_file = __curPos.file;
system.kexec-installer.name = "nixos-kexec-installer-noninteractive";
imports = [
kexec-installer-nixos-unstable-noninteractive = kexec-installer nixos-unstable [
{ system.kexec-installer.name = "nixos-kexec-installer-noninteractive"; }
self.nixosModules.noninteractive
];
};
kexec-installer-nixos-stable-noninteractive = kexec-installer nixos-stable {
_file = __curPos.file;
system.kexec-installer.name = "nixos-kexec-installer-noninteractive";
imports = [
kexec-installer-nixos-stable-noninteractive = kexec-installer nixos-stable [
{ system.kexec-installer.name = "nixos-kexec-installer-noninteractive"; }
self.nixosModules.noninteractive
];
};
netboot-installer-nixos-unstable = netboot-installer nixos-unstable;
netboot-installer-nixos-stable = netboot-installer nixos-stable;
});
}
);
crossPackages = {
x86_64-linux =
let
kexec-installer =
nixpkgs: modules:
(nixpkgs.legacyPackages.x86_64-linux.pkgsCross.riscv64.nixos (
modules
++ [
self.nixosModules.kexec-installer
self.nixosModules.noninteractive
]
)).config.system.build.kexecTarball;
in
{
kexec-installer-nixos-unstable-noninteractive-riscv64 = kexec-installer nixos-unstable [ ];
# needs a backport to nixpkgs-24.05
#kexec-installer-nixos-stable-noninteractive-riscv64 = kexec-installer nixos-stable [ ];
};
};
in
{
packages = nixos-unstable.lib.recursiveUpdate packages crossPackages;
nixosModules = {
kexec-installer = ./nix/kexec-installer/module.nix;
noninteractive = ./nix/noninteractive.nix;
@ -58,28 +95,29 @@
checks =
let
# re-export the packages as checks
packages = forAllSystems (system: nixos-unstable.lib.mapAttrs' (n: nixos-unstable.lib.nameValuePair "package-${n}") self.packages.${system});
packages = forAllSystems (
system:
nixos-unstable.lib.mapAttrs' (
n: nixos-unstable.lib.nameValuePair "package-${n}"
) self.packages.${system}
);
checks =
let
pkgsUnstable = nixos-unstable.legacyPackages.riscv64-linux;
pkgsStable = nixos-stable.legacyPackages.riscv64-linux;
bootTests = pkgs: channel: suffix: pkgs.lib.mapAttrs' (name: pkgs.lib.nameValuePair "${name}${suffix}") (pkgs.callPackages ./nix/image-installer/tests.nix {
nixpkgs = channel;
nixosModules = self.nixosModules;
});
pkgs = nixos-unstable.legacyPackages.x86_64-linux;
in
{
kexec-installer-unstable = pkgsUnstable.callPackage ./nix/kexec-installer/test.nix {
kexecTarball = self.packages.riscv64-linux.kexec-installer-nixos-unstable-noninteractive;
kexec-installer-unstable = pkgs.callPackage ./nix/kexec-installer/test.nix {
kexecTarball = self.packages.x86_64-linux.kexec-installer-nixos-unstable-noninteractive;
};
kexec-installer-stable = nixos-stable.legacyPackages.riscv64-linux.callPackage ./nix/kexec-installer/test.nix {
kexecTarball = self.packages.riscv64-linux.kexec-installer-nixos-stable-noninteractive;
shellcheck = pkgs.runCommand "shellcheck" { nativeBuildInputs = [ pkgs.shellcheck ]; } ''
shellcheck ${(pkgs.nixos [ self.nixosModules.kexec-installer ]).config.system.build.kexecRun}
touch $out
'';
kexec-installer-stable =
nixos-stable.legacyPackages.x86_64-linux.callPackage ./nix/kexec-installer/test.nix
{ kexecTarball = self.packages.x86_64-linux.kexec-installer-nixos-stable-noninteractive; };
};
} // (bootTests pkgsUnstable nixos-unstable "-nixos-unstable")
// (bootTests pkgsStable nixos-stable "-nixos-stable");
in
nixos-unstable.lib.recursiveUpdate packages { riscv64-linux = checks; };
nixos-unstable.lib.recursiveUpdate packages { x86_64-linux = checks; };
};
}

5
garnix.yaml Normal file
View file

@ -0,0 +1,5 @@
builds:
include:
- '*.x86_64-linux.*'
- '*.aarch64-linux.*'
- nixosConfigurations.*

View file

@ -40,9 +40,8 @@ in
imports = [
(modulesPath + "/installer/cd-dvd/installation-cd-base.nix")
../installer.nix
../noveau-workaround.nix
./hidden-ssh-announcement.nix
./wifi.nix
./hidden-ssh-announcement.nix
];
systemd.tmpfiles.rules = [ "d /var/shared 0777 root root - -" ];
services.openssh.settings.PermitRootLogin = "yes";

View file

@ -1,105 +0,0 @@
{
pkgs,
lib,
nixpkgs,
nixos,
nixosModules,
}:
let
testConfig = (
nixos [
(
{ modulesPath, ... }:
{
imports = [
nixosModules.image-installer
"${modulesPath}/testing/test-instrumentation.nix"
];
}
)
]
);
iso = testConfig.config.system.build.isoImage;
mkStartCommand =
{
memory ? 2048,
cdrom ? null,
usb ? null,
uefi ? false,
extraFlags ? [ ],
}:
let
qemu-common = import (nixpkgs + "/nixos/lib/qemu-common.nix") { inherit lib pkgs; };
qemu = qemu-common.qemuBinary pkgs.qemu_test;
flags =
[
"-m"
(toString memory)
"-netdev"
"user,id=net0"
"-device"
"virtio-net-pci,netdev=net0"
]
++ lib.optionals (cdrom != null) [
"-cdrom"
cdrom
]
++ lib.optionals (usb != null) [
"-device"
"usb-ehci"
"-drive"
"id=usbdisk,file=${usb},if=none,readonly"
"-device"
"usb-storage,drive=usbdisk"
]
++ lib.optionals uefi [
"-drive"
"if=pflash,format=raw,unit=0,readonly=on,file=${pkgs.OVMF.firmware}"
"-drive"
"if=pflash,format=raw,unit=1,readonly=on,file=${pkgs.OVMF.variables}"
]
++ extraFlags;
flagsStr = lib.concatStringsSep " " flags;
in
"${qemu} ${flagsStr}";
makeBootTest =
name: config:
let
startCommand = mkStartCommand config;
in
pkgs.testers.runNixOSTest {
name = "boot-${name}";
nodes = { };
testScript = ''
machine = create_machine("${startCommand}")
machine.start()
machine.wait_for_unit("multi-user.target")
machine.succeed("nix store verify --no-trust -r --option experimental-features nix-command /run/current-system")
machine.shutdown()
'';
};
in
{
uefi-cdrom = makeBootTest "uefi-cdrom" {
uefi = true;
cdrom = "${iso}/iso/nixos-installer-${pkgs.hostPlatform.system}.iso";
};
uefi-usb = makeBootTest "uefi-usb" {
uefi = true;
usb = "${iso}/iso/nixos-installer-${pkgs.hostPlatform.system}.iso";
};
bios-cdrom = makeBootTest "bios-cdrom" {
cdrom = "${iso}/iso/nixos-installer-${pkgs.hostPlatform.system}.iso";
};
bios-usb = makeBootTest "bios-usb" {
usb = "${iso}/iso/nixos-installer-${pkgs.hostPlatform.system}.iso";
};
}

View file

@ -2,42 +2,39 @@
config,
lib,
pkgs,
modulesPath,
...
}:
{
imports = [
# ./latest-zfs-kernel.nix
./nix-settings.nix
];
# more descriptive hostname than just "nixos"
networking.hostName = lib.mkDefault "nixos-installer";
# We are stateless, so just default to latest.
system.stateVersion = config.system.nixos.version;
# Enable bcachefs support
boot.supportedFilesystems.bcachefs = lib.mkDefault true;
# use latest kernel we can support to get more hardware support
# boot.zfs.package = pkgs.zfsUnstable;
boot.kernelPackages =
lib.mkDefault
(pkgs.zfs.override { removeLinuxDRM = pkgs.hostPlatform.isAarch64; }).latestCompatibleLinuxPackages;
boot.zfs.removeLinuxDRM = lib.mkDefault pkgs.hostPlatform.isAarch64;
documentation.enable = false;
documentation.man.man-db.enable = false;
# make it easier to debug boot failures
boot.initrd.systemd.emergencyAccess = true;
environment.systemPackages = [
pkgs.nixos-install-tools
# for zapping of disko
pkgs.jq
# for copying extra files of nixos-anywhere
pkgs.rsync
# alternative to nixos-generate-config
# TODO: use nixpkgs again after next nixos release
(pkgs.callPackage ./nixos-facter.nix {})
];
pkgs.disko
imports = [
./nix-settings.nix
# reduce closure size by removing perl
"${modulesPath}/profiles/perlless.nix"
# FIXME: we still are left with nixos-generate-config due to nixos-install-tools
{ system.forbiddenDependenciesRegexes = lib.mkForce []; }
];
# Don't add nixpkgs to the image to save space, for our intended use case we don't need it

View file

@ -1,26 +0,0 @@
#!/usr/bin/env -S nix shell --inputs-from .# nixos-unstable#bash nixos-unstable#iproute2 nixos-unstable#findutils nixos-unstable#coreutils nixos-unstable#python3 nixos-unstable#jq --command bash
set -eu
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
# This script can be used to see what network configuration would be restored by the restore_routes.py script for the current system.
tmp=$(mktemp -d)
trap "rm -rf $tmp" EXIT
ip --json address >"$tmp/addrs.json"
ip -6 --json route >"$tmp/routes-v6.json"
ip -4 --json route >"$tmp/routes-v4.json"
python3 "$SCRIPT_DIR/restore_routes.py" "$tmp/addrs.json" "$tmp/routes-v4.json" "$tmp/routes-v6.json" "$tmp"
ls -la "$tmp"
find "$tmp" -type f -name "*.json" -print0 | while IFS= read -r -d '' file; do
echo -e "\033[0;31m$(basename "$file")\033[0m"
jq . "$file"
echo ""
done
find "$tmp" -type f -name "*.network" -print0 | while IFS= read -r -d '' file; do
echo -e "\033[0;31m$(basename "$file")\033[0m"
cat "$file"
echo ""
done

View file

@ -1,17 +1,33 @@
{ config, lib, modulesPath, pkgs, ... }:
{
config,
lib,
modulesPath,
pkgs,
...
}:
let
writePython3 = pkgs.writers.makePythonWriter
pkgs.python3Minimal pkgs.python3Packages pkgs.buildPackages.python3Packages;
# writePython3Bin takes the same arguments as writePython3 but outputs a directory (like writeScriptBin)
writePython3Bin = name: writePython3 "/bin/${name}";
restore-network = writePython3Bin "restore-network" {
restore-network = pkgs.writers.writePython3 "restore-network" {
flakeIgnore = [ "E501" ];
} ./restore_routes.py;
# does not link with iptables enabled
iprouteStatic = pkgs.pkgsStatic.iproute2.override { iptables = null; };
kexec-tools = pkgs.pkgsStatic.kexec-tools.overrideAttrs (old: {
patches = old.patches ++ [
(pkgs.fetchpatch {
url = "https://marc.info/?l=kexec&m=166636009110699&q=mbox";
hash = "sha256-wi0/Ajy/Ac+7npKEvDsMzgNhEWhOMFeoUWcpgGrmVDc=";
})
];
nativeBuildInputs = (old.nativeBuildInputs or []) ++ [
pkgs.pkgsStatic.buildPackages.autoreconfHook
];
meta = old.meta // {
badPlatforms = [ ]; # allow riscv64
};
});
in
{
imports = [
@ -21,7 +37,6 @@ in
../serial.nix
../restore-remote-access.nix
];
options = {
system.kexec-installer.name = lib.mkOption {
type = lib.types.str;
@ -33,10 +48,11 @@ in
};
config = {
boot.initrd.compressor = "xz";
# This is a variant of the upstream kexecScript that also allows embedding
# a ssh key.
system.build.kexecRun = pkgs.runCommand "kexec-run" { } ''
system.build.kexecRun =
pkgs.runCommand "kexec-run" { nativeBuildInputs = [ pkgs.buildPackages.shellcheck ]; }
''
install -D -m 0755 ${./kexec-run.sh} $out
sed -i \
@ -44,7 +60,7 @@ in
-e 's|@kernelParams@|${lib.escapeShellArgs config.boot.kernelParams}|' \
$out
${pkgs.shellcheck}/bin/shellcheck $out
shellcheck $out
'';
system.build.kexecTarball = pkgs.runCommand "kexec-tarball" { } ''
@ -52,7 +68,7 @@ in
cp "${config.system.build.netbootRamdisk}/initrd" kexec/initrd
cp "${config.system.build.kernel}/${config.system.boot.loader.kernelFile}" kexec/bzImage
cp "${config.system.build.kexecRun}" kexec/run
cp "${pkgs.pkgsStatic.kexec-tools}/bin/kexec" kexec/kexec
cp "${kexec-tools}/bin/kexec" kexec/kexec
cp "${iprouteStatic}/bin/ip" kexec/ip
${lib.optionalString (pkgs.hostPlatform == pkgs.buildPlatform) ''
kexec/ip -V
@ -73,7 +89,7 @@ in
Type = "oneshot";
RemainAfterExit = true;
ExecStart = [
"${restore-network}/bin/restore-network /root/network/addrs.json /root/network/routes-v4.json /root/network/routes-v6.json /etc/systemd/network"
"${restore-network} /root/network/addrs.json /root/network/routes-v4.json /root/network/routes-v6.json /etc/systemd/network"
];
};

View file

@ -1,80 +1,34 @@
import json
import sys
from pathlib import Path
from typing import Any, Iterator
from dataclasses import dataclass
from typing import Any
@dataclass
class Address:
address: str
family: str
prefixlen: int
preferred_life_time: int = 0
valid_life_time: int = 0
@dataclass
class Interface:
name: str
ifname: str | None
mac_address: str
dynamic_addresses: list[Address]
static_addresses: list[Address]
static_routes: list[dict[str, Any]]
def filter_interfaces(network: list[dict[str, Any]]) -> list[Interface]:
interfaces = []
def filter_interfaces(network: list[dict[str, Any]]) -> list[dict[str, Any]]:
output = []
for net in network:
if net.get("link_type") == "loopback":
continue
if not (mac_address := net.get("address")):
if not net.get("address"):
# We need a mac address to match devices reliable
continue
static_addresses = []
dynamic_addresses = []
for info in net.get("addr_info", []):
addr_info = []
has_dynamic_address = False
for addr in net.get("addr_info", []):
# no link-local ipv4/ipv6
if info.get("scope") == "link":
if addr.get("scope") == "link":
continue
if (preferred_life_time := info.get("preferred_life_time")) is None:
# do not explicitly configure addresses from dhcp or router advertisement
if addr.get("dynamic", False):
has_dynamic_address = True
continue
if (valid_life_time := info.get("valid_life_time")) is None:
continue
if (prefixlen := info.get("prefixlen")) is None:
continue
if (family := info.get("family")) not in ["inet", "inet6"]:
continue
if (local := info.get("local")) is None:
continue
if (dynamic := info.get("dynamic", False)) is None:
continue
address = Address(
address=local,
family=family,
prefixlen=prefixlen,
preferred_life_time=preferred_life_time,
valid_life_time=valid_life_time,
)
if dynamic:
dynamic_addresses.append(address)
else:
static_addresses.append(address)
interfaces.append(
Interface(
name=net.get("ifname", mac_address.replace(":", "-")),
ifname=net.get("ifname"),
mac_address=mac_address,
dynamic_addresses=dynamic_addresses,
static_addresses=static_addresses,
static_routes=[],
)
)
addr_info.append(addr)
if addr_info != [] or has_dynamic_address:
net["addr_info"] = addr_info
output.append(net)
return interfaces
return output
def filter_routes(routes: list[dict[str, Any]]) -> list[dict[str, Any]]:
@ -88,54 +42,38 @@ def filter_routes(routes: list[dict[str, Any]]) -> list[dict[str, Any]]:
return filtered
def find_most_recent_v4_lease(addresses: list[Address]) -> Address | None:
most_recent_address = None
most_recent_lifetime = -1
for addr in addresses:
if addr.family == "inet6":
continue
lifetime = max(addr.preferred_life_time, addr.valid_life_time)
if lifetime > most_recent_lifetime:
most_recent_lifetime = lifetime
most_recent_address = addr
return most_recent_address
def generate_routes(
interface: Interface, routes: list[dict[str, Any]]
) -> Iterator[str]:
for route in routes:
if interface.ifname is None or route.get("dev") != interface.ifname:
continue
# we may ignore on-link default routes here, but I don't see how
# they would be useful for internet connectivity anyway
yield "[Route]"
if route.get("dst") != "default":
# can be skipped for default routes
yield f"Destination = {route['dst']}"
gateway = route.get("gateway")
# route v4 via v6
route_via = route.get("via")
if route_via and route_via.get("family") == "inet6":
gateway = route_via.get("host")
if route.get("dst") == "default":
yield "Destination = 0.0.0.0/0"
if gateway:
yield f"Gateway = {gateway}"
def generate_networkd_units(
interfaces: list[Interface], routes: list[dict[str, Any]], directory: Path
interfaces: list[dict[str, Any]], routes: list[dict[str, Any]], directory: Path
) -> None:
directory.mkdir(exist_ok=True)
for interface in interfaces:
name = f"00-{interface['ifname']}.network"
addresses = [
f"Address = {addr['local']}/{addr['prefixlen']}"
for addr in interface.get("addr_info", [])
]
route_sections = []
for route in routes:
if route.get("dev", "nodev") != interface.get("ifname", "noif"):
continue
route_section = "[Route]\n"
if route.get("dst") != "default":
# can be skipped for default routes
route_section += f"Destination = {route['dst']}\n"
gateway = route.get("gateway")
if gateway:
route_section += f"Gateway = {gateway}\n"
# we may ignore on-link default routes here, but I don't see how
# they would be useful for internet connectivity anyway
route_sections.append(route_section)
# FIXME in some networks we might not want to trust dhcp or router advertisements
unit_sections = [
f"""
unit = f"""
[Match]
MACAddress = {interface.mac_address}
MACAddress = {interface["address"]}
[Network]
# both ipv4 and ipv6
@ -145,24 +83,12 @@ LLDP = yes
# ipv6 router advertisements
IPv6AcceptRA = yes
# allows us to ping "nixos.local"
MulticastDNS = yes"""
]
unit_sections.extend(
f"Address = {addr.address}/{addr.prefixlen}"
for addr in interface.static_addresses
)
unit_sections.extend(generate_routes(interface, routes))
most_recent_v4_lease = find_most_recent_v4_lease(interface.dynamic_addresses)
if most_recent_v4_lease:
unit_sections.append("[DHCPv4]")
unit_sections.append(f"RequestAddress = {most_recent_v4_lease.address}")
MulticastDNS = yes
# trailing newline at the end
unit_sections.append("")
(directory / f"00-{interface.name}.network").write_text(
"\n".join(unit_sections)
)
"""
unit += "\n".join(addresses)
unit += "\n" + "\n".join(route_sections)
(directory / name).write_text(unit)
def main() -> None:

View file

@ -1,18 +1,25 @@
{ pkgs
, lib
, kexecTarball
, nixos-facter ? null
}:
pkgs.testers.runNixOSTest {
let
makeTest = import (pkgs.path + "/nixos/tests/make-test-python.nix");
makeTest' = args: makeTest args {
inherit pkgs;
inherit (pkgs) system;
};
in
makeTest' {
name = "kexec-installer";
meta = with pkgs.lib.maintainers; {
maintainers = [ mic92 ];
};
nodes = {
node1 = { modulesPath, pkgs, ... }: {
node1 = { modulesPath, ... }: {
virtualisation.vlans = [ ];
environment.noXlibs = false; # avoid recompilation
imports = [
(modulesPath + "/profiles/minimal.nix")
];
@ -47,17 +54,10 @@ pkgs.testers.runNixOSTest {
"192.168.42.1/24"
"42::1/64"
];
routes = if pkgs.lib.versionAtLeast lib.version "24.11" then [
{ Destination = "192.168.43.0/24"; }
{ Destination = "192.168.44.0/24"; Gateway = "192.168.43.1"; }
{ Destination = "192.168.45.0/24"; Gateway = "43::1"; }
{ Destination = "43::0/64"; }
{ Destination = "44::1/64"; Gateway = "43::1"; }
] else [
routes = [
# Some static routes that we want to see in the kexeced image
{ routeConfig = { Destination = "192.168.43.0/24"; }; }
{ routeConfig = { Destination = "192.168.44.0/24"; Gateway = "192.168.43.1"; }; }
{ routeConfig = { Destination = "192.168.45.0/24"; Gateway = "43::1"; }; }
{ routeConfig = { Destination = "43::0/64"; }; }
{ routeConfig = { Destination = "44::1/64"; Gateway = "43::1"; }; }
];
@ -65,14 +65,10 @@ pkgs.testers.runNixOSTest {
};
};
};
} // lib.optionalAttrs (lib.versionOlder lib.version "24.11pre") {
# avoid second overlay
environment.noXlibs = false;
};
};
testScript = /*python*/ ''
import json
testScript = ''
import time
import subprocess
import socket
@ -167,11 +163,6 @@ pkgs.testers.runNixOSTest {
host = ssh(["hostname"], stdout=subprocess.PIPE).stdout.strip()
assert host == "nixos-installer", f"hostname is {host}, not nixos-installer"
has_nixos_facter=${if nixos-facter != null then "True" else "False"}
if has_nixos_facter == True:
data = json.loads(ssh(["nixos-facter"], stdout=subprocess.PIPE).stdout)
assert data["virtualisation"] == "kvm", f"virtualisation is {data['virtualisation']}, not kvm"
host_ed25519_after = ssh(["cat", "/etc/ssh/ssh_host_ed25519_key.pub"], stdout=subprocess.PIPE).stdout.strip()
assert host_ed25519_before == host_ed25519_after, f"'{host_ed25519_before}' != '{host_ed25519_after}'"
@ -194,10 +185,6 @@ pkgs.testers.runNixOSTest {
print(out)
assert "192.168.44.2 via 192.168.43.1" in out, f"route to `192.168.44.2 via 192.168.43.1` not found: {out}"
out = ssh(["ip", "route", "get", "192.168.45.2"], stdout=subprocess.PIPE).stdout
print(out)
assert "192.168.45.2 via inet6 43::1" in out, f"route to `192.168.45.2 via inet6 43::1` not found: {out}"
out = ssh(["ip", "route", "get", "43::2"], stdout=subprocess.PIPE).stdout
print(out)
assert "43::2 from :: dev" in out, f"route `43::2 from dev` not found: {out}"

View file

@ -1,26 +0,0 @@
{
lib,
pkgs,
config,
...
}:
let
isUnstable = config.boot.zfs.package == pkgs.zfsUnstable;
zfsCompatibleKernelPackages = lib.filterAttrs (
name: kernelPackages:
(builtins.match "linux_[0-9]+_[0-9]+" name) != null
&& (builtins.tryEval kernelPackages).success
&& (
(!isUnstable && !kernelPackages.zfs.meta.broken)
|| (isUnstable && !kernelPackages.zfs_unstable.meta.broken)
)
) pkgs.linuxKernel.packages;
latestKernelPackage = lib.last (
lib.sort (a: b: (lib.versionOlder a.kernel.version b.kernel.version)) (builtins.attrValues zfsCompatibleKernelPackages)
);
in
{
# Note this might jump back and worth as kernel get added or removed.
boot.kernelPackages = latestKernelPackage;
}

View file

@ -5,7 +5,11 @@
nix.settings.connect-timeout = 5;
# Enable flakes
nix.settings.experimental-features = [ "nix-command" "flakes" ];
nix.settings.experimental-features = [
"nix-command"
"flakes"
"repl-flake"
];
# The default at 10 is rarely enough.
nix.settings.log-lines = lib.mkDefault 25;

View file

@ -1,71 +0,0 @@
{
lib,
buildGoModule,
fetchFromGitHub,
hwinfo,
libusb1,
gcc,
pkg-config,
util-linux,
pciutils,
stdenv,
}:
let
# We are waiting on some changes to be merged upstream: https://github.com/openSUSE/hwinfo/pulls
hwinfoOverride = hwinfo.overrideAttrs {
src = fetchFromGitHub {
owner = "numtide";
repo = "hwinfo";
rev = "a559f34934098d54096ed2078e750a8245ae4044";
hash = "sha256-3abkWPr98qXXQ17r1Z43gh2M5hl/DHjW2hfeWl+GSAs=";
};
};
in
buildGoModule rec {
pname = "nixos-facter";
version = "0.1.1";
src = fetchFromGitHub {
owner = "numtide";
repo = "nixos-facter";
rev = "v${version}";
hash = "sha256-vlPmvCrgX64dcf//BPtQszBt7dkq35JpgQg+/LW0AqM=";
};
vendorHash = "sha256-5leiTNp3FJmgFd0SKhu18hxYZ2G9SuQPhZJjki2SDVs=";
CGO_ENABLED = 1;
buildInputs = [
libusb1
hwinfoOverride
];
nativeBuildInputs = [
gcc
pkg-config
];
runtimeInputs = [
libusb1
util-linux
pciutils
];
ldflags = [
"-s"
"-w"
"-X git.numtide.com/numtide/nixos-facter/build.Name=nixos-facter"
"-X git.numtide.com/numtide/nixos-facter/build.Version=v${version}"
"-X github.com/numtide/nixos-facter/pkg/build.System=${stdenv.hostPlatform.system}"
];
meta = {
description = "Declarative hardware configuration for NixOS";
homepage = "https://github.com/numtide/nixos-facter";
license = lib.licenses.gpl3Plus;
maintainers = [ lib.maintainers.brianmcgee ];
mainProgram = "nixos-facter";
platforms = lib.platforms.linux;
};
}

View file

@ -1,7 +1,7 @@
# This module optimizes for non-interactive deployments by remove some store paths
# which are primarily useful for interactive installations.
{ lib, pkgs, modulesPath, ... }:
{ lib, pkgs, ... }:
{
disabledModules = [
# This module adds values to multiple lists (systemPackages, supportedFilesystems)
@ -10,14 +10,8 @@
];
imports = [
# ./zfs-minimal.nix
./zfs-minimal.nix
./no-bootloaders.nix
./python-minimal.nix
./noveau-workaround.nix
# reduce closure size by removing perl
"${modulesPath}/profiles/perlless.nix"
# FIXME: we still are left with nixos-generate-config due to nixos-install-tools
{ system.forbiddenDependenciesRegexes = lib.mkForce []; }
];
# among others, this prevents carrying a stdenv with gcc in the image
@ -30,29 +24,10 @@
programs.nano.enable = false;
# prevents strace
environment.defaultPackages = lib.mkForce [
pkgs.rsync
pkgs.parted
pkgs.gptfdisk
pkgs.e2fsprogs
];
# normal users are not allowed with sys-users
# see https://github.com/NixOS/nixpkgs/pull/328926
users.users.nixos = {
isSystemUser = true;
isNormalUser = lib.mkForce false;
shell = "/run/current-system/sw/bin/bash";
group = "nixos";
};
users.groups.nixos = {};
# we prefer root as this is also what we use in nixos-anywhere
services.getty.autologinUser = lib.mkForce "root";
environment.defaultPackages = lib.mkForce [ pkgs.rsync pkgs.parted pkgs.gptfdisk ];
# we are missing this from base.nix
boot.supportedFilesystems = [
"ext4"
"btrfs"
# probably not needed but does not seem to increase closure size
"cifs"

View file

@ -1,4 +0,0 @@
{
# fixes blank screen on boot for some cards
boot.kernelParams = [ "nouveau.modeset=0" ];
}

View file

@ -1,10 +0,0 @@
{
nixpkgs.overlays = [
(final: prev: {
bcachefs-tools = prev.bcachefs-tools.override { python3 = final.python3Minimal; };
cifs-utils = prev.cifs-utils.override { python3 = final.python3Minimal; };
nfs-utils = prev.nfs-utils.override { python3 = final.python3Minimal; };
talloc = prev.talloc.override { python3 = final.python3Minimal; };
})
];
}

View file

@ -1,21 +1,33 @@
{ config, lib, pkgs, ... }:
# incorperate a space-optimized version of zfs
let
zfs = pkgs.zfsUnstable.override {
zfs = pkgs.zfs.override {
# this overrides saves 10MB
samba = pkgs.coreutils;
python3 = pkgs.python3Minimal;
};
hasZfs = lib.meta.availableOn pkgs.stdenv.hostPlatform config.boot.zfs.package;
in
{
lib.mkIf hasZfs {
services.udev.packages = [ zfs ]; # to hook zvol naming, etc.
# unsure if need this, but in future udev rules could potentially point to systemd services.
systemd.packages = [ zfs ];
environment.defaultPackages = lib.mkForce [ zfs ]; # this merges with outer noninteractive module.
boot.kernelModules = [ "zfs" ];
boot.extraModulePackages = [ config.boot.kernelPackages.zfs_unstable ];
boot.extraModulePackages = [
(config.boot.kernelPackages.zfs.override {
inherit (config.boot.zfs) removeLinuxDRM;
})
];
boot.kernelPatches = lib.optional (config.boot.zfs.removeLinuxDRM && pkgs.stdenv.hostPlatform.system == "aarch64-linux") {
name = "export-neon-symbols-as-gpl";
patch = pkgs.fetchpatch {
url = "https://github.com/torvalds/linux/commit/aaeca98456431a8d9382ecf48ac4843e252c07b3.patch";
hash = "sha256-L2g4G1tlWPIi/QRckMuHDcdWBcKpObSWSRTvbHRIwIk=";
revert = true;
};
};
networking.hostId = lib.mkDefault "8425e349";
}