Compare commits
2
Commits
2db9b77272
...
4535616799
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4535616799 | ||
|
|
ad459e2b4b |
@@ -0,0 +1,84 @@
|
|||||||
|
{...}: {
|
||||||
|
# `nix run .#sync-hardware`
|
||||||
|
#
|
||||||
|
# Refreshes the calling host's generated hardware module in-repo, replacing the
|
||||||
|
# old habit of importing /etc/nixos/hardware-configuration.nix by absolute path.
|
||||||
|
#
|
||||||
|
# Why bother: that absolute import left the flake impure (every eval needed
|
||||||
|
# --impure, since the file lives outside the store) and — worse — meant *both*
|
||||||
|
# hosts resolved to whichever machine's hardware file was on disk at build
|
||||||
|
# time. Building t480 from shadow silently baked in shadow's disk UUIDs.
|
||||||
|
#
|
||||||
|
# Run this on a host after changing its hardware, then commit the result.
|
||||||
|
perSystem = {pkgs, ...}: let
|
||||||
|
script = pkgs.writeShellApplication {
|
||||||
|
name = "sync-hardware";
|
||||||
|
runtimeInputs = [pkgs.nixos-install-tools pkgs.git pkgs.coreutils pkgs.nettools];
|
||||||
|
text = ''
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
host="''${1:-$(hostname)}"
|
||||||
|
|
||||||
|
root=$(git rev-parse --show-toplevel 2>/dev/null || true)
|
||||||
|
if [ -z "$root" ]; then
|
||||||
|
echo "sync-hardware: run this from inside the config repo." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
dir="$root/modules/hosts/$host"
|
||||||
|
if [ ! -d "$dir" ]; then
|
||||||
|
echo "sync-hardware: no host directory at $dir" >&2
|
||||||
|
echo " known hosts: $(cd "$root/modules/hosts" && echo *)" >&2
|
||||||
|
echo " pass an explicit name with: nix run .#sync-hardware -- <host>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
out="$dir/_hardware.nix"
|
||||||
|
|
||||||
|
# --no-filesystems is load-bearing: fileSystems/swapDevices are declared
|
||||||
|
# by hand in the host's disks.nix. Without the flag this would emit
|
||||||
|
# entries for whatever is mounted right now, duplicating (and conflicting
|
||||||
|
# with) those definitions.
|
||||||
|
header=$(cat <<'EOF'
|
||||||
|
# GENERATED FILE — do not edit by hand.
|
||||||
|
#
|
||||||
|
# Regenerate on the host itself with: nix run .#sync-hardware
|
||||||
|
#
|
||||||
|
# Produced by `nixos-generate-config --show-hardware-config --no-filesystems`.
|
||||||
|
# The --no-filesystems flag is deliberate: fileSystems and swapDevices are
|
||||||
|
# declared by hand in ./disks.nix, so regenerating this file can never clobber
|
||||||
|
# them or emit duplicates for whatever happened to be mounted at the time.
|
||||||
|
#
|
||||||
|
# Leading underscore keeps import-tree from auto-importing this as a
|
||||||
|
# flake-parts module (its filter drops any path containing "/_"); it is
|
||||||
|
# imported explicitly from ./default.nix instead.
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
tmp=$(mktemp)
|
||||||
|
trap 'rm -f "$tmp"' EXIT
|
||||||
|
|
||||||
|
# Strip the upstream 3-line "Do not modify" banner; ours replaces it.
|
||||||
|
{
|
||||||
|
printf '%s\n' "$header" | sed 's/^ //'
|
||||||
|
nixos-generate-config --show-hardware-config --no-filesystems | tail -n +4
|
||||||
|
} > "$tmp"
|
||||||
|
|
||||||
|
if [ -f "$out" ] && cmp -s "$tmp" "$out"; then
|
||||||
|
echo "sync-hardware: $out already up to date."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp "$tmp" "$out"
|
||||||
|
echo "sync-hardware: wrote $out"
|
||||||
|
echo " review with: git diff -- $out"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
apps.sync-hardware = {
|
||||||
|
type = "app";
|
||||||
|
program = "${script}/bin/sync-hardware";
|
||||||
|
meta.description = "Regenerate modules/hosts/<host>/_hardware.nix from the running machine";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -27,6 +27,32 @@
|
|||||||
services.xserver.enable = true;
|
services.xserver.enable = true;
|
||||||
security.polkit.enable = true;
|
security.polkit.enable = true;
|
||||||
|
|
||||||
|
# Removable-media automounting.
|
||||||
|
#
|
||||||
|
# udiskie is only a tray frontend to the udisks2 D-Bus daemon, so the daemon
|
||||||
|
# has to be enabled or udiskie runs but can never mount anything. Note this
|
||||||
|
# covers removable media *only*: udisks2 reports the internal SATA disks as
|
||||||
|
# HintSystem=true, so udiskie leaves them alone. Permanently attached drives
|
||||||
|
# are declared in the host's disks.nix instead.
|
||||||
|
services.udisks2.enable = true;
|
||||||
|
|
||||||
|
# Run udiskie as a user unit rather than from the hypr autostart — it was
|
||||||
|
# previously only installed, never actually launched. Binding it to
|
||||||
|
# graphical-session.target (which UWSM manages properly) means it starts and
|
||||||
|
# stops with the session instead of leaking across logins.
|
||||||
|
systemd.user.services.udiskie = {
|
||||||
|
description = "udiskie removable media automounter";
|
||||||
|
partOf = ["graphical-session.target"];
|
||||||
|
after = ["graphical-session.target"];
|
||||||
|
wantedBy = ["graphical-session.target"];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
# -s = smart tray: the icon appears only while removable media is present.
|
||||||
|
ExecStart = "${pkgs.udiskie}/bin/udiskie -s";
|
||||||
|
Restart = "on-failure";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
# hypr* ecosystem (keybinds / hypridle / autostart)
|
# hypr* ecosystem (keybinds / hypridle / autostart)
|
||||||
hyprlock
|
hyprlock
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# GENERATED FILE — do not edit by hand.
|
||||||
|
#
|
||||||
|
# Regenerate on the host itself with: nix run .#sync-hardware
|
||||||
|
#
|
||||||
|
# Produced by `nixos-generate-config --show-hardware-config --no-filesystems`.
|
||||||
|
# The --no-filesystems flag is deliberate: fileSystems and swapDevices are
|
||||||
|
# declared by hand in ./disks.nix, so regenerating this file can never clobber
|
||||||
|
# them or emit duplicates for whatever happened to be mounted at the time.
|
||||||
|
#
|
||||||
|
# Leading underscore keeps import-tree from auto-importing this as a
|
||||||
|
# flake-parts module (its filter drops any path containing "/_"); it is
|
||||||
|
# imported explicitly from ./default.nix instead.
|
||||||
|
{ config, lib, pkgs, modulesPath, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports =
|
||||||
|
[ (modulesPath + "/installer/scan/not-detected.nix")
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usbhid" "uas" "sd_mod" ];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ "kvm-amd" ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
|
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
|
}
|
||||||
@@ -5,8 +5,12 @@
|
|||||||
}: {
|
}: {
|
||||||
flake.nixosConfigurations.shadow = inputs.nixpkgs.lib.nixosSystem {
|
flake.nixosConfigurations.shadow = inputs.nixpkgs.lib.nixosSystem {
|
||||||
modules = with self.nixosModules; [
|
modules = with self.nixosModules; [
|
||||||
|
# Generated hardware scan, in-repo so the flake stays pure.
|
||||||
|
# Refresh with `nix run .#sync-hardware` (run on shadow itself).
|
||||||
|
./_hardware.nix
|
||||||
desktop
|
desktop
|
||||||
shadowConfiguration
|
shadowConfiguration
|
||||||
|
shadowDisks
|
||||||
cpuAmd
|
cpuAmd
|
||||||
gpuNvidia
|
gpuNvidia
|
||||||
development
|
development
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
{...}: {
|
||||||
|
# Every filesystem on shadow lives here, hand-maintained.
|
||||||
|
#
|
||||||
|
# hardware.nix is generated with `--no-filesystems` precisely so it never
|
||||||
|
# emits fileSystems/swapDevices entries of its own. That keeps regeneration
|
||||||
|
# (`nix run .#sync-hardware`) safe: re-running it can never clobber these
|
||||||
|
# definitions, nor produce duplicates for whichever data drives happened to
|
||||||
|
# be mounted at the time it ran.
|
||||||
|
flake.nixosModules.shadowDisks = {...}: let
|
||||||
|
# Secondary data drive, addressed by filesystem label.
|
||||||
|
#
|
||||||
|
# noauto + x-systemd.automount makes systemd generate an .automount unit and
|
||||||
|
# mount on first access to the path rather than at boot — the two 2.7T
|
||||||
|
# spinners stay parked until something actually touches them. idle-timeout
|
||||||
|
# unmounts them again once quiet so they can spin back down.
|
||||||
|
#
|
||||||
|
# nofail matters even with automount: it stops a missing or dying disk from
|
||||||
|
# becoming a failed dependency that drops the boot into emergency mode.
|
||||||
|
#
|
||||||
|
# On-disk ownership is already ahmza mode 755 on all three, so no uid mapping
|
||||||
|
# is needed — ext4 stores ownership in the filesystem and ignores uid=/gid=.
|
||||||
|
dataDrive = label: {
|
||||||
|
device = "/dev/disk/by-label/${label}";
|
||||||
|
fsType = "ext4";
|
||||||
|
options = [
|
||||||
|
"nofail"
|
||||||
|
"noauto"
|
||||||
|
"x-systemd.automount"
|
||||||
|
"x-systemd.idle-timeout=600"
|
||||||
|
"x-systemd.device-timeout=10"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
fileSystems = {
|
||||||
|
# Boot essentials, by UUID. UUIDs rather than labels here on purpose:
|
||||||
|
# these two must resolve unambiguously, and a label is only as unique as
|
||||||
|
# the last disk someone plugged in.
|
||||||
|
"/" = {
|
||||||
|
device = "/dev/disk/by-uuid/deff63fc-1738-4cfc-a79c-06e58c78471a";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
|
||||||
|
"/boot" = {
|
||||||
|
device = "/dev/disk/by-uuid/5873-AD05";
|
||||||
|
fsType = "vfat";
|
||||||
|
options = ["fmask=0077" "dmask=0077"];
|
||||||
|
};
|
||||||
|
|
||||||
|
"/mnt/dump" = dataDrive "DUMP";
|
||||||
|
"/mnt/games" = dataDrive "GAMES";
|
||||||
|
"/mnt/bak" = dataDrive "BAK";
|
||||||
|
};
|
||||||
|
|
||||||
|
swapDevices = [];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -5,6 +5,17 @@
|
|||||||
}: {
|
}: {
|
||||||
flake.nixosConfigurations.t480 = inputs.nixpkgs.lib.nixosSystem {
|
flake.nixosConfigurations.t480 = inputs.nixpkgs.lib.nixosSystem {
|
||||||
modules = with self.nixosModules; [
|
modules = with self.nixosModules; [
|
||||||
|
# TODO: still importing by absolute path, so evaluating t480 requires
|
||||||
|
# --impure and picks up the hardware file of whatever machine you build
|
||||||
|
# from (on shadow, that means shadow's disk UUIDs — wrong but harmless
|
||||||
|
# until you actually deploy). Fix by running, ON THE T480 ITSELF:
|
||||||
|
#
|
||||||
|
# nix run .#sync-hardware
|
||||||
|
#
|
||||||
|
# then create modules/hosts/t480/disks.nix (mirroring shadow's) and swap
|
||||||
|
# this line for `./_hardware.nix` + `t480Disks`. Cannot be done remotely:
|
||||||
|
# the hardware scan has to happen on the target machine.
|
||||||
|
/etc/nixos/hardware-configuration.nix
|
||||||
desktop
|
desktop
|
||||||
t480Configuration
|
t480Configuration
|
||||||
# CPU microcode + integrated Intel GPU. The T480 also has an NVIDIA MX150;
|
# CPU microcode + integrated Intel GPU. The T480 also has an NVIDIA MX150;
|
||||||
|
|||||||
@@ -18,11 +18,11 @@
|
|||||||
nix-ld
|
nix-ld
|
||||||
];
|
];
|
||||||
in {
|
in {
|
||||||
imports =
|
# Hardware/disk config is deliberately NOT imported here. It is per-host and
|
||||||
[
|
# lives in modules/hosts/<host>/{_hardware.nix,disks.nix}, wired up by that
|
||||||
/etc/nixos/hardware-configuration.nix
|
# host's default.nix. Importing it from this shared module used to mean both
|
||||||
]
|
# hosts resolved to whichever machine's /etc/nixos file existed at build time.
|
||||||
++ modules;
|
imports = modules;
|
||||||
services = {
|
services = {
|
||||||
openssh.enable = true;
|
openssh.enable = true;
|
||||||
avahi.enable = true;
|
avahi.enable = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user