Compare commits

..

1 commit

Author SHA1 Message Date
Jörg Thalheim
7867c3a6a7 fix sysusers in noninteractive case 2024-08-02 09:33:28 +02:00
21 changed files with 153 additions and 480 deletions

View file

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

View file

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

View file

@ -1,7 +1,7 @@
queue_rules: queue_rules:
- name: default - name: default
merge_conditions: merge_conditions:
- check-success=buildbot/nix-build - check-success=buildbot/nix-eval
defaults: defaults:
actions: actions:
queue: 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 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 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 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 time of writing, this requires at least 1GB of physical RAM (swap does not
of physical RAM (swap does not count) in the system. If not enough RAM is available, count) in the system. If not enough RAM is available, the initrd cannot be
the initrd cannot be loaded. Because the NixOS runs only in RAM, users can reformat loaded. Because the NixOS runs only in RAM, users can reformat all the system's
all the system's discs to prepare for a new NixOS installation. discs to prepare for a new NixOS installation.
It can be booted as follows by running these commands as root: It can be booted as follows by running these commands as root:

View file

@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixos-stable": { "nixos-stable": {
"locked": { "locked": {
"lastModified": 1729181673, "lastModified": 1722372011,
"narHash": "sha256-LDiPhQ3l+fBjRATNtnuDZsBS7hqoBtPkKBkhpoBHv3I=", "narHash": "sha256-B2xRiC3NEJy/82ugtareBkRqEkPGpMyjaLxaR8LBxNs=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "4eb33fe664af7b41a4c446f87d20c9a0a6321fa3", "rev": "cf05eeada35e122770c5c14add958790fcfcbef5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -18,16 +18,16 @@
}, },
"nixos-unstable": { "nixos-unstable": {
"locked": { "locked": {
"lastModified": 1729450260, "lastModified": 1722582943,
"narHash": "sha256-3GNZr0V4b19RZ5mlyiY/4F8N2pzitvjDU6aHMWjAqLI=", "narHash": "sha256-PAzeUUnBcWwzHRiOovsaxEFiqUxu6Li1SSlLabkayJA=",
"owner": "NixOS", "owner": "Mic92",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "e3f55158e7587c5a5fdb0e86eb7ca4f455f0928f", "rev": "013b662a4433803218c5587f5e301d213d9aae0c",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "Mic92",
"ref": "nixos-unstable-small", "ref": "iproute2",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }

View file

@ -1,7 +1,9 @@
{ {
description = "NixOS images"; description = "NixOS images";
inputs.nixos-unstable.url = "github:NixOS/nixpkgs/nixos-unstable-small"; #inputs.nixos-unstable.url = "github:NixOS/nixpkgs/nixos-unstable-small";
# see https://github.com/NixOS/nixpkgs/pull/331699
inputs.nixos-unstable.url = "github:Mic92/nixpkgs/iproute2";
inputs.nixos-stable.url = "github:NixOS/nixpkgs/nixos-24.05"; inputs.nixos-stable.url = "github:NixOS/nixpkgs/nixos-24.05";
nixConfig.extra-substituters = [ "https://nix-community.cachix.org" ]; nixConfig.extra-substituters = [ "https://nix-community.cachix.org" ];
@ -9,41 +11,38 @@
outputs = { self, nixos-unstable, nixos-stable }: outputs = { self, nixos-unstable, nixos-stable }:
let let
supportedSystems = [ "riscv64-linux" ]; supportedSystems = [ "aarch64-linux" "x86_64-linux" ];
forAllSystems = nixos-unstable.lib.genAttrs supportedSystems; forAllSystems = nixos-unstable.lib.genAttrs supportedSystems;
in in
{ {
hydraJobs = { inherit (self) checks; };
packages = forAllSystems (system: packages = forAllSystems (system:
let let
netboot = nixpkgs: (import (nixpkgs + "/nixos/release.nix") { }).netboot.${system}; 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; 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; image-installer = nixpkgs: (nixpkgs.legacyPackages.${system}.nixos [ self.nixosModules.image-installer ]).config.system.build.isoImage;
in in
{ {
netboot-nixos-unstable = netboot nixos-unstable; netboot-nixos-unstable = netboot nixos-unstable;
netboot-nixos-stable = netboot nixos-stable; netboot-nixos-stable = netboot nixos-stable;
kexec-installer-nixos-unstable = kexec-installer nixos-unstable {}; kexec-installer-nixos-unstable = kexec-installer nixos-unstable [ ];
kexec-installer-nixos-stable = kexec-installer nixos-stable {}; kexec-installer-nixos-stable = kexec-installer nixos-stable [ ];
image-installer-nixos-unstable = image-installer nixos-unstable; image-installer-nixos-unstable = image-installer nixos-unstable;
image-installer-nixos-stable = image-installer nixos-stable; image-installer-nixos-stable = image-installer nixos-stable;
kexec-installer-nixos-unstable-noninteractive = kexec-installer nixos-unstable { kexec-installer-nixos-unstable-noninteractive = kexec-installer nixos-unstable [
_file = __curPos.file; {
system.kexec-installer.name = "nixos-kexec-installer-noninteractive"; system.kexec-installer.name = "nixos-kexec-installer-noninteractive";
imports = [ }
self.nixosModules.noninteractive self.nixosModules.noninteractive
]; ];
}; kexec-installer-nixos-stable-noninteractive = kexec-installer nixos-stable [
kexec-installer-nixos-stable-noninteractive = kexec-installer nixos-stable { {
_file = __curPos.file; system.kexec-installer.name = "nixos-kexec-installer-noninteractive";
system.kexec-installer.name = "nixos-kexec-installer-noninteractive"; }
imports = [ self.nixosModules.noninteractive
self.nixosModules.noninteractive ];
];
};
netboot-installer-nixos-unstable = netboot-installer nixos-unstable; netboot-installer-nixos-unstable = netboot-installer nixos-unstable;
netboot-installer-nixos-stable = netboot-installer nixos-stable; netboot-installer-nixos-stable = netboot-installer nixos-stable;
@ -61,25 +60,24 @@
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 = checks =
let let
pkgsUnstable = nixos-unstable.legacyPackages.riscv64-linux; pkgs = nixos-unstable.legacyPackages.x86_64-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;
});
in in
{ {
kexec-installer-unstable = pkgsUnstable.callPackage ./nix/kexec-installer/test.nix { kexec-installer-unstable = pkgs.callPackage ./nix/kexec-installer/test.nix {
kexecTarball = self.packages.riscv64-linux.kexec-installer-nixos-unstable-noninteractive; kexecTarball = self.packages.x86_64-linux.kexec-installer-nixos-unstable-noninteractive;
}; };
shellcheck = pkgs.runCommand "shellcheck"
kexec-installer-stable = nixos-stable.legacyPackages.riscv64-linux.callPackage ./nix/kexec-installer/test.nix { {
kexecTarball = self.packages.riscv64-linux.kexec-installer-nixos-stable-noninteractive; 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 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 = [ imports = [
(modulesPath + "/installer/cd-dvd/installation-cd-base.nix") (modulesPath + "/installer/cd-dvd/installation-cd-base.nix")
../installer.nix ../installer.nix
../noveau-workaround.nix
./hidden-ssh-announcement.nix
./wifi.nix ./wifi.nix
./hidden-ssh-announcement.nix
]; ];
systemd.tmpfiles.rules = [ "d /var/shared 0777 root root - -" ]; systemd.tmpfiles.rules = [ "d /var/shared 0777 root root - -" ];
services.openssh.settings.PermitRootLogin = "yes"; 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

@ -5,21 +5,17 @@
... ...
}: }:
{ {
imports = [
# ./latest-zfs-kernel.nix
./nix-settings.nix
];
# more descriptive hostname than just "nixos" # more descriptive hostname than just "nixos"
networking.hostName = lib.mkDefault "nixos-installer"; networking.hostName = lib.mkDefault "nixos-installer";
# We are stateless, so just default to latest. # We are stateless, so just default to latest.
system.stateVersion = config.system.nixos.version; 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 # 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.enable = false;
documentation.man.man-db.enable = false; documentation.man.man-db.enable = false;
@ -33,11 +29,10 @@
pkgs.jq pkgs.jq
# for copying extra files of nixos-anywhere # for copying extra files of nixos-anywhere
pkgs.rsync 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
]; ];
# Don't add nixpkgs to the image to save space, for our intended use case we don't need it # 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,14 +1,7 @@
{ config, lib, modulesPath, pkgs, ... }: { config, lib, modulesPath, pkgs, ... }:
let let
writePython3 = pkgs.writers.makePythonWriter restore-network = pkgs.writers.writePython3 "restore-network" { flakeIgnore = [ "E501" ]; }
pkgs.python3Minimal pkgs.python3Packages pkgs.buildPackages.python3Packages; ./restore_routes.py;
# 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;
# does not link with iptables enabled # does not link with iptables enabled
iprouteStatic = pkgs.pkgsStatic.iproute2.override { iptables = null; }; iprouteStatic = pkgs.pkgsStatic.iproute2.override { iptables = null; };
@ -21,7 +14,6 @@ in
../serial.nix ../serial.nix
../restore-remote-access.nix ../restore-remote-access.nix
]; ];
options = { options = {
system.kexec-installer.name = lib.mkOption { system.kexec-installer.name = lib.mkOption {
type = lib.types.str; type = lib.types.str;
@ -33,7 +25,6 @@ in
}; };
config = { config = {
boot.initrd.compressor = "xz";
# This is a variant of the upstream kexecScript that also allows embedding # This is a variant of the upstream kexecScript that also allows embedding
# a ssh key. # a ssh key.
system.build.kexecRun = pkgs.runCommand "kexec-run" { } '' system.build.kexecRun = pkgs.runCommand "kexec-run" { } ''
@ -73,7 +64,7 @@ in
Type = "oneshot"; Type = "oneshot";
RemainAfterExit = true; RemainAfterExit = true;
ExecStart = [ 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 json
import sys import sys
from pathlib import Path from pathlib import Path
from typing import Any, Iterator from typing import Any
from dataclasses import dataclass
@dataclass def filter_interfaces(network: list[dict[str, Any]]) -> list[dict[str, Any]]:
class Address: output = []
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 = []
for net in network: for net in network:
if net.get("link_type") == "loopback": if net.get("link_type") == "loopback":
continue continue
if not (mac_address := net.get("address")): if not net.get("address"):
# We need a mac address to match devices reliable # We need a mac address to match devices reliable
continue continue
static_addresses = [] addr_info = []
dynamic_addresses = [] has_dynamic_address = False
for info in net.get("addr_info", []): for addr in net.get("addr_info", []):
# no link-local ipv4/ipv6 # no link-local ipv4/ipv6
if info.get("scope") == "link": if addr.get("scope") == "link":
continue 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 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: else:
static_addresses.append(address) addr_info.append(addr)
interfaces.append( if addr_info != [] or has_dynamic_address:
Interface( net["addr_info"] = addr_info
name=net.get("ifname", mac_address.replace(":", "-")), output.append(net)
ifname=net.get("ifname"),
mac_address=mac_address,
dynamic_addresses=dynamic_addresses,
static_addresses=static_addresses,
static_routes=[],
)
)
return interfaces return output
def filter_routes(routes: list[dict[str, Any]]) -> list[dict[str, Any]]: def filter_routes(routes: list[dict[str, Any]]) -> list[dict[str, Any]]:
@ -88,54 +42,44 @@ def filter_routes(routes: list[dict[str, Any]]) -> list[dict[str, Any]]:
return filtered 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( 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: ) -> None:
directory.mkdir(exist_ok=True) directory.mkdir(exist_ok=True)
for interface in interfaces: 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")
# 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":
route_section += "Destination = 0.0.0.0/0\n"
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 # FIXME in some networks we might not want to trust dhcp or router advertisements
unit_sections = [ unit = f"""
f"""
[Match] [Match]
MACAddress = {interface.mac_address} MACAddress = {interface["address"]}
[Network] [Network]
# both ipv4 and ipv6 # both ipv4 and ipv6
@ -145,24 +89,12 @@ LLDP = yes
# ipv6 router advertisements # ipv6 router advertisements
IPv6AcceptRA = yes IPv6AcceptRA = yes
# allows us to ping "nixos.local" # allows us to ping "nixos.local"
MulticastDNS = yes""" 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}")
# trailing newline at the end """
unit_sections.append("") unit += "\n".join(addresses)
unit += "\n" + "\n".join(route_sections)
(directory / f"00-{interface.name}.network").write_text( (directory / name).write_text(unit)
"\n".join(unit_sections)
)
def main() -> None: def main() -> None:

View file

@ -1,18 +1,25 @@
{ pkgs { pkgs
, lib , lib
, kexecTarball , 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"; name = "kexec-installer";
meta = with pkgs.lib.maintainers; { meta = with pkgs.lib.maintainers; {
maintainers = [ mic92 ]; maintainers = [ mic92 ];
}; };
nodes = { nodes = {
node1 = { modulesPath, pkgs, ... }: { node1 = { modulesPath, ... }: {
virtualisation.vlans = [ ]; virtualisation.vlans = [ ];
environment.noXlibs = false; # avoid recompilation
imports = [ imports = [
(modulesPath + "/profiles/minimal.nix") (modulesPath + "/profiles/minimal.nix")
]; ];
@ -47,13 +54,7 @@ pkgs.testers.runNixOSTest {
"192.168.42.1/24" "192.168.42.1/24"
"42::1/64" "42::1/64"
]; ];
routes = if pkgs.lib.versionAtLeast lib.version "24.11" then [ routes = [
{ 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 [
# Some static routes that we want to see in the kexeced image # Some static routes that we want to see in the kexeced image
{ routeConfig = { Destination = "192.168.43.0/24"; }; } { routeConfig = { Destination = "192.168.43.0/24"; }; }
{ routeConfig = { Destination = "192.168.44.0/24"; Gateway = "192.168.43.1"; }; } { routeConfig = { Destination = "192.168.44.0/24"; Gateway = "192.168.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*/ '' testScript = /*python*/ ''
import json
import time import time
import subprocess import subprocess
import socket import socket
@ -167,11 +164,6 @@ pkgs.testers.runNixOSTest {
host = ssh(["hostname"], stdout=subprocess.PIPE).stdout.strip() host = ssh(["hostname"], stdout=subprocess.PIPE).stdout.strip()
assert host == "nixos-installer", f"hostname is {host}, not nixos-installer" 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() 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}'" assert host_ed25519_before == host_ed25519_after, f"'{host_ed25519_before}' != '{host_ed25519_after}'"

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; nix.settings.connect-timeout = 5;
# Enable flakes # 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. # The default at 10 is rarely enough.
nix.settings.log-lines = lib.mkDefault 25; 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

@ -10,10 +10,8 @@
]; ];
imports = [ imports = [
# ./zfs-minimal.nix ./zfs-minimal.nix
./no-bootloaders.nix ./no-bootloaders.nix
./python-minimal.nix
./noveau-workaround.nix
# reduce closure size by removing perl # reduce closure size by removing perl
"${modulesPath}/profiles/perlless.nix" "${modulesPath}/profiles/perlless.nix"
# FIXME: we still are left with nixos-generate-config due to nixos-install-tools # FIXME: we still are left with nixos-generate-config due to nixos-install-tools
@ -30,29 +28,19 @@
programs.nano.enable = false; programs.nano.enable = false;
# prevents strace # prevents strace
environment.defaultPackages = lib.mkForce [ environment.defaultPackages = lib.mkForce [ pkgs.rsync pkgs.parted pkgs.gptfdisk ];
pkgs.rsync
pkgs.parted
pkgs.gptfdisk
pkgs.e2fsprogs
];
# normal users are not allowed with sys-users # normal users are not allowed with sys-users
# see https://github.com/NixOS/nixpkgs/pull/328926 # see https://github.com/NixOS/nixpkgs/pull/328926
users.users.nixos = { users.users.nixos = {
isSystemUser = true; isSystemUser = true;
isNormalUser = lib.mkForce false; isNormalUser = lib.mkForce false;
shell = "/run/current-system/sw/bin/bash";
group = "nixos";
}; };
users.users.nixos.group = "nixos";
users.groups.nixos = {}; users.groups.nixos = {};
# we prefer root as this is also what we use in nixos-anywhere
services.getty.autologinUser = lib.mkForce "root";
# we are missing this from base.nix # we are missing this from base.nix
boot.supportedFilesystems = [ boot.supportedFilesystems = [
"ext4"
"btrfs" "btrfs"
# probably not needed but does not seem to increase closure size # probably not needed but does not seem to increase closure size
"cifs" "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,11 +1,9 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
# incorperate a space-optimized version of zfs # incorperate a space-optimized version of zfs
let let
zfs = pkgs.zfsUnstable.override { zfs = pkgs.zfs.override {
# this overrides saves 10MB # this overrides saves 10MB
samba = pkgs.coreutils; samba = pkgs.coreutils;
python3 = pkgs.python3Minimal;
}; };
in in
{ {
@ -15,7 +13,20 @@ in
environment.defaultPackages = lib.mkForce [ zfs ]; # this merges with outer noninteractive module. environment.defaultPackages = lib.mkForce [ zfs ]; # this merges with outer noninteractive module.
boot.kernelModules = [ "zfs" ]; 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"; networking.hostId = lib.mkDefault "8425e349";
} }