Compare commits

..

1 commit
main ... foo

Author SHA1 Message Date
Jörg Thalheim
fa0c4d1523
also disable man page to save a few mb 2024-05-22 18:46:04 +02:00
25 changed files with 204 additions and 547 deletions

View file

@ -11,7 +11,7 @@ jobs:
fail-fast: false
matrix:
tag:
- nixos-24.05
- nixos-23.11
- nixos-unstable
os:
- nscloud-ubuntu-22.04-arm64-4x16
@ -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@v26
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@v26
- name: Update flake.lock
uses: DeterminateSystems/update-flake-lock@v24
uses: DeterminateSystems/update-flake-lock@v21
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:

View file

@ -5,8 +5,8 @@ set -xeuo pipefail
shopt -s lastpipe
build_netboot_image() {
declare -r tag=$1 channel=$2 arch=$3 tmp=$4
img=$(nix build --print-out-paths --option accept-flake-config true -L ".#packages.${arch}.netboot-nixos-${channel//./}")
declare -r tag=$1 arch=$2 tmp=$3
img=$(nix build --print-out-paths --option accept-flake-config true -L ".#packages.${arch}.netboot-${tag//./}")
kernel=$(echo "$img"/*Image)
kernelName=$(basename "$kernel")
ln -s "$kernel" "$tmp/$kernelName-$arch"
@ -22,14 +22,14 @@ build_netboot_image() {
}
build_kexec_installer() {
declare -r channel=$1 arch=$2 tmp=$3 variant=$4
out=$(nix build --print-out-paths --option accept-flake-config true -L ".#packages.${arch}.kexec-installer-nixos-${channel}${variant}")
declare -r tag=$1 arch=$2 tmp=$3 variant=$4
out=$(nix build --print-out-paths --option accept-flake-config true -L ".#packages.${arch}.kexec-installer-${tag//./}${variant}")
echo "$out/nixos-kexec-installer${variant}-$arch.tar.gz"
}
build_image_installer() {
declare -r channel=$1 arch=$2 tmp=$3
out=$(nix build --print-out-paths --option accept-flake-config true -L ".#packages.${arch}.image-installer-nixos-${channel//./}")
declare -r tag=$1 arch=$2 tmp=$3
out=$(nix build --print-out-paths --option accept-flake-config true -L ".#packages.${arch}.image-installer-${tag//./}")
echo "$out/iso/nixos-installer-${arch}.iso"
}
@ -38,11 +38,10 @@ main() {
tmp="$(mktemp -d)"
trap 'rm -rf -- "$tmp"' EXIT
(
channel=$(if [[ "$tag" == nixos-unstable ]]; then echo "unstable"; else echo "stable"; fi)
build_kexec_installer "$channel" "$arch" "$tmp" ""
build_kexec_installer "$channel" "$arch" "$tmp" "-noninteractive"
build_netboot_image "$tag" "$channel" "$arch" "$tmp"
build_image_installer "$channel" "$arch" "$tmp"
build_kexec_installer "$tag" "$arch" "$tmp" ""
build_kexec_installer "$tag" "$arch" "$tmp" "-noninteractive"
build_netboot_image "$tag" "$arch" "$tmp"
build_image_installer "$tag" "$arch" "$tmp"
) | readarray -t assets
for asset in "${assets[@]}"; do
pushd "$(dirname "$asset")"

View file

@ -1,28 +1,28 @@
{
"nodes": {
"nixos-stable": {
"nixos-2311": {
"locked": {
"lastModified": 1729181673,
"narHash": "sha256-LDiPhQ3l+fBjRATNtnuDZsBS7hqoBtPkKBkhpoBHv3I=",
"lastModified": 1715818734,
"narHash": "sha256-WvAJWCwPj/6quKcsgsvQYyZRxV8ho/yUzj0HZQ34DVU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "4eb33fe664af7b41a4c446f87d20c9a0a6321fa3",
"rev": "95742536dc6debb5a8b8b78b27001c38f369f1e7",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.05",
"ref": "release-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixos-unstable": {
"locked": {
"lastModified": 1729450260,
"narHash": "sha256-3GNZr0V4b19RZ5mlyiY/4F8N2pzitvjDU6aHMWjAqLI=",
"lastModified": 1715777523,
"narHash": "sha256-S6g1OWbKXswOMoTssq3aOm4OhxhlKoIwEAXWmU57vts=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e3f55158e7587c5a5fdb0e86eb7ca4f455f0928f",
"rev": "c029b7f004009923bbfc90bbc31263cd4b08759f",
"type": "github"
},
"original": {
@ -34,7 +34,7 @@
},
"root": {
"inputs": {
"nixos-stable": "nixos-stable",
"nixos-2311": "nixos-2311",
"nixos-unstable": "nixos-unstable"
}
}

View file

@ -2,51 +2,48 @@
description = "NixOS images";
inputs.nixos-unstable.url = "github:NixOS/nixpkgs/nixos-unstable-small";
inputs.nixos-stable.url = "github:NixOS/nixpkgs/nixos-24.05";
inputs.nixos-2311.url = "github:NixOS/nixpkgs/release-23.11";
nixConfig.extra-substituters = [ "https://nix-community.cachix.org" ];
nixConfig.extra-trusted-public-keys = [ "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" ];
nixConfig.extra-substituters = [ "https://numtide.cachix.org" ];
nixConfig.extra-trusted-public-keys = [ "numtide.cachix.org-1:2ps1kLBUWjxIneOy1Ik6cQjb41X0iXVXeHigGmycPPE=" ];
outputs = { self, nixos-unstable, nixos-stable }:
outputs = { self, nixos-unstable, nixos-2311 }:
let
supportedSystems = [ "riscv64-linux" ];
supportedSystems = [ "aarch64-linux" "x86_64-linux" ];
forAllSystems = nixos-unstable.lib.genAttrs supportedSystems;
in
{
hydraJobs = { inherit (self) checks; };
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;
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 {};
netboot-nixos-2311 = netboot nixos-2311;
kexec-installer-nixos-unstable = kexec-installer nixos-unstable [ ];
kexec-installer-nixos-2311 = kexec-installer nixos-2311 [ ];
image-installer-nixos-unstable = image-installer nixos-unstable;
image-installer-nixos-stable = image-installer nixos-stable;
image-installer-nixos-2311 = image-installer nixos-2311;
kexec-installer-nixos-unstable-noninteractive = kexec-installer nixos-unstable {
_file = __curPos.file;
system.kexec-installer.name = "nixos-kexec-installer-noninteractive";
imports = [
self.nixosModules.noninteractive
];
};
kexec-installer-nixos-stable-noninteractive = kexec-installer nixos-stable {
_file = __curPos.file;
system.kexec-installer.name = "nixos-kexec-installer-noninteractive";
imports = [
self.nixosModules.noninteractive
];
};
kexec-installer-nixos-unstable-noninteractive = kexec-installer nixos-unstable [
{
system.kexec-installer.name = "nixos-kexec-installer-noninteractive";
}
self.nixosModules.noninteractive
];
kexec-installer-nixos-2311-noninteractive = kexec-installer nixos-2311 [
{
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;
netboot-installer-nixos-2311 = netboot-installer nixos-2311;
});
nixosModules = {
kexec-installer = ./nix/kexec-installer/module.nix;
@ -61,25 +58,24 @@
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-2311 = nixos-2311.legacyPackages.x86_64-linux.callPackage ./nix/kexec-installer/test.nix {
kexecTarball = self.packages.x86_64-linux.kexec-installer-nixos-2311-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,44 @@
config,
lib,
pkgs,
modulesPath,
...
}:
let
# can be dropped after 23.11 is removed
hasPerlless = builtins.pathExists "${modulesPath}/profiles/perlless.nix";
in
{
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
] ++ lib.optionals hasPerlless [
"${modulesPath}/profiles/perlless.nix"
# We relax the perl check in perlless.nix as not all images are actually perlless
# and we also want to allow users to install perl if they need it.
{ system.forbiddenDependenciesRegexes = lib.mkForce []; }
];
# Don't add nixpkgs to the image to save space, for our intended use case we don't need it

25
nix/kexec-installer/kexec-run.sh Executable file → Normal file
View file

@ -1,19 +1,6 @@
#!/bin/sh
set -ex
kexec_extra_flags=""
while [ $# -gt 0 ]; do
case "$1" in
--kexec-extra-flags)
kexec_extra_flags="$2"
shift
;;
esac
shift
done
# provided by nix
init="@init@"
kernelParams="@kernelParams@"
@ -78,12 +65,10 @@ if printf "%s\n" "6.1" "$(uname -r)" | sort -c -V 2>&1; then
kexecSyscallFlags="--kexec-syscall-auto"
fi
if ! sh -c "'$SCRIPT_DIR/kexec' --load '$SCRIPT_DIR/bzImage' \
$kexecSyscallFlags \
$kexec_extra_flags \
--initrd='$SCRIPT_DIR/initrd' --no-checks \
--command-line 'init=$init $kernelParams'"
then
if ! "$SCRIPT_DIR/kexec" --load "$SCRIPT_DIR/bzImage" \
"$kexecSyscallFlags" \
--initrd="$SCRIPT_DIR/initrd" --no-checks \
--command-line "init=$init $kernelParams"; then
echo "kexec failed, dumping dmesg"
dmesg | tail -n 100
exit 1
@ -99,4 +84,4 @@ else
fi
# We will kexec in background so we can cleanly finish the script before the hosts go down.
# This makes integration with tools like terraform easier.
nohup sh -c "sleep 6 && '$SCRIPT_DIR/kexec' -e ${kexec_extra_flags}" &
nohup sh -c "sleep 6 && '$SCRIPT_DIR/kexec' -e" &

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,14 +1,7 @@
{ 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" {
flakeIgnore = [ "E501" ];
} ./restore_routes.py;
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; };
@ -21,7 +14,6 @@ in
../serial.nix
../restore-remote-access.nix
];
options = {
system.kexec-installer.name = lib.mkOption {
type = lib.types.str;
@ -33,7 +25,6 @@ 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" { } ''
@ -73,7 +64,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,24 +1,32 @@
{ 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")
];
system.extraDependencies = [ kexecTarball ];
virtualisation.memorySize = 1 * 1024;
# TODO: remove the conditional after 23.11 is end-of-life
virtualisation.memorySize = 1 * 1024 + (if (lib.versionOlder lib.version "24.05pre") then 256 else 0);
virtualisation.diskSize = 4 * 1024;
virtualisation.forwardPorts = [{
host.port = 2222;
@ -47,17 +55,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 +66,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 +164,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 +186,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,8 @@
{ lib, ... }: {
# HACK: Drop this, once we have 24.11 everywhere
nixpkgs.overlays = lib.optionals (lib.versionOlder lib.version "24.11pre") [
# Both syslinux and grub also reference perl
{
# HACK: Drop this once, we have https://github.com/NixOS/nixpkgs/pull/312863 merged
# Both syslinux and grub also reference perl
nixpkgs.overlays = [
(final: prev: {
# we don't need grub: save ~ 60MB
grub2 = prev.coreutils;

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,6 +1,10 @@
{ lib, ... }:
let
is2405 = lib.versionAtLeast lib.version "24.05pre";
in
{
# We have a bug in 23.11 in combination with netboot.
boot.initrd.systemd.enable = true;
boot.initrd.systemd.enable = is2405;
boot.initrd.systemd.services.restore-state-from-initrd = {
unitConfig = {
DefaultDependencies = false;
@ -26,4 +30,17 @@
fi
'';
};
boot.initrd.postMountCommands = lib.mkIf (!is2405) ''
mkdir -m 700 -p /mnt-root/root/.ssh
mkdir -m 755 -p /mnt-root/etc/ssh
mkdir -m 755 -p /mnt-root/root/network
if [[ -f ssh/authorized_keys ]]; then
install -m 400 ssh/authorized_keys /mnt-root/root/.ssh
fi
install -m 400 ssh/ssh_host_* /mnt-root/etc/ssh
cp *.json /mnt-root/root/network/
if [[ -f machine-id ]]; then
cp machine-id /mnt-root/etc/machine-id
fi
'';
}

View file

@ -1,11 +1,9 @@
{ 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;
};
in
{
@ -15,7 +13,20 @@ in
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";
}