Files
Floweynt 76fa38e34c
flake-check / flake-check (push) Canceled after 0s
lint / lint (push) Canceled after 0s
diff-tag / dix (push) Canceled after 0s
initial commit
2026-08-31 08:41:45 -05:00

400 lines
9.1 KiB
Nix

{ lib, dsl }:
let
plain =
v:
if lib.isFunction v then
null
else if lib.isDerivation v then
"${v}"
else if lib.isList v then
map plain v
else if lib.isAttrs v then
lib.mapAttrs (_: plain) v
else if builtins.isPath v then
toString v
else
v;
relations = [
{
field = "after";
kind = "after";
reverse = false;
}
{
field = "before";
kind = "after";
reverse = true;
}
{
field = "wants";
kind = "wants";
reverse = false;
}
{
field = "wantedBy";
kind = "wants";
reverse = true;
}
{
field = "requires";
kind = "requires";
reverse = false;
}
{
field = "requiredBy";
kind = "requires";
reverse = true;
}
{
field = "upholds";
kind = "upholds";
reverse = false;
}
{
field = "upheldBy";
kind = "upholds";
reverse = true;
}
{
field = "bindsTo";
kind = "bindsTo";
reverse = false;
}
{
field = "partOf";
kind = "partOf";
reverse = false;
}
{
field = "requisite";
kind = "requisite";
reverse = false;
}
{
field = "conflicts";
kind = "conflicts";
reverse = false;
}
{
field = "onFailure";
kind = "onFailure";
reverse = false;
}
{
field = "onSuccess";
kind = "onSuccess";
reverse = false;
}
];
relationFields = map (r: r.field) relations;
# raw NixOS command options, mirrors every generated Exec* wrapper
commandFields = [
"script"
"scriptArgs"
"preStart"
"postStart"
"reload"
"preStop"
"postStop"
];
allUnits =
c:
lib.concatMap lib.attrValues [
c.systemd.paths
c.systemd.services
c.systemd.slices
c.systemd.sockets
c.systemd.targets
c.systemd.timers
]
++ c.systemd.mounts
++ c.systemd.automounts;
unitSummary =
u:
{
inherit (u) name;
description = u.description or "";
enable = u.enable or true;
unitConfig = u.unitConfig or { };
}
// lib.filterAttrs (_: v: v != [ ]) (lib.genAttrs relationFields (f: u.${f} or [ ]))
// lib.optionalAttrs (u ? serviceConfig) (
{
inherit (u) serviceConfig;
environment = u.environment or { };
path = u.path or [ ];
restartIfChanged = u.restartIfChanged or null;
stopIfChanged = u.stopIfChanged or null;
}
# raw command text: the real logic behind the store-path Exec* wrappers
// lib.filterAttrs (_: v: v != "") (lib.genAttrs commandFields (f: u.${f} or ""))
)
// lib.optionalAttrs (u ? timerConfig) { inherit (u) timerConfig; }
// lib.optionalAttrs (u ? socketConfig) {
inherit (u) socketConfig;
listenStreams = u.listenStreams or [ ];
listenDatagrams = u.listenDatagrams or [ ];
}
// lib.optionalAttrs (u ? pathConfig) { inherit (u) pathConfig; }
// lib.optionalAttrs (u ? what) {
inherit (u) what;
where = u.where or "";
type = u.type or "";
options = u.options or "";
};
unitEdges =
node: u:
let
ref = n: "${node}:${n}";
in
lib.concatMap (
r:
map (
peer:
{
inherit (r) kind;
}
// (
if r.reverse then
{
from = ref peer;
to = ref u.name;
}
else
{
from = ref u.name;
to = ref peer;
}
)
) (u.${r.field} or [ ])
) relations;
fileSystemsOf =
c:
lib.mapAttrsToList (mountPoint: fs: {
inherit mountPoint;
inherit (fs)
device
fsType
options
neededForBoot
depends
;
}) c.fileSystems;
firewallOf =
c:
let
fw = c.networking.firewall;
portsOf = f: {
inherit (f)
allowedTCPPorts
allowedUDPPorts
allowedTCPPortRanges
allowedUDPPortRanges
;
};
in
{
inherit (fw) enable trustedInterfaces;
interfaces = lib.mapAttrs (_: portsOf) fw.interfaces;
}
// portsOf fw;
isBuildUser = n: builtins.match "nixbld[0-9]+" n != null;
usersOf = c: {
inherit (c.users) mutableUsers;
groups = lib.mapAttrs (_: g: {
inherit (g) gid;
members = lib.filter (m: !isBuildUser m) g.members;
}) c.users.groups;
users = lib.mapAttrs (_: u: {
inherit (u)
uid
group
home
shell
description
createHome
isNormalUser
isSystemUser
extraGroups
;
authorizedKeys = u.openssh.authorizedKeys.keys;
passwordSet = lib.any (v: v != null) [
u.hashedPassword
u.hashedPasswordFile
u.password
u.initialPassword
u.initialHashedPassword
];
}) (lib.filterAttrs (n: _: !isBuildUser n) c.users.users);
};
in
{
hostReport =
{ host }:
let
cfg = host.hostCfg.config;
deployments = host.containers;
depList = lib.attrValues deployments;
configOf =
c:
if c.kind == "nspawn" then
cfg.containers.${c.name}.config
else
cfg.microvm.vms.${c.name}.config.config;
unitOf = c: "${dsl.serviceUnitName c}.service";
nodes = {
"@host" = cfg;
}
// lib.mapAttrs (_: configOf) deployments;
forward =
proto: c: p:
let
q = dsl.normalizePort p;
in
{
inherit proto;
hostPort = q.host;
target = c.name;
targetPort = q.container;
targetAddr = c.addr;
};
mountsOf =
c:
if c.kind == "nspawn" then
lib.mapAttrsToList (mountPoint: bm: {
inherit mountPoint;
inherit (bm) hostPath isReadOnly;
}) c.bindMounts
else
map (s: {
mountPoint = s.mountPoint or null;
hostPath = s.source;
isReadOnly = s.readOnly or false;
inherit (s) proto tag;
}) c.shares;
in
plain {
meta = {
host = host.hostName;
system = cfg.nixpkgs.hostPlatform.system;
inherit (cfg.system) stateVersion;
inherit (host.specialArgs.hostInfo) paths mainGateway;
toplevel = cfg.system.build.toplevel;
};
deployments = lib.mapAttrs (_: c: {
inherit (c)
name
kind
autoStart
access
allowInternet
needsGateway
includedInTests
;
# names only; c.depends holds whole deployment objects
depends = map (d: d.name) c.depends;
unit = unitOf c;
limits =
if c.kind == "nspawn" then
{ inherit (c) memoryMax cpuQuota privateUsers; }
else
{ inherit (c) vcpu mem hypervisor; };
inherit (c) miscProperties;
}) deployments;
access = {
specials = [
"@host"
"@internet"
];
edges = lib.concatMap (
c:
map (a: {
from = c.name;
inherit (a) to;
tcp = a.tcp or [ ];
udp = a.udp or [ ];
}) c.access
) depList;
};
kernel = {
sysctl = cfg.boot.kernel.sysctl;
params = cfg.boot.kernelParams;
modules = cfg.boot.kernelModules;
};
network = {
inherit (cfg.networking) nameservers;
links = lib.mapAttrs (_: c: {
inherit (c)
kind
iface
mac
addr
hostAddr
allowInternet
needsGateway
;
}) deployments;
hostInterfaces = lib.mapAttrs (_: i: { inherit (i) ipv4; }) cfg.networking.interfaces;
dnsmasq = cfg.services.dnsmasq.settings;
};
ports = {
forwards = lib.concatMap (
c: map (forward "tcp" c) c.hostPorts ++ map (forward "udp" c) c.hostUdpPorts
) depList;
declared = lib.mapAttrs (_: c: c.ports or [ ]) deployments;
firewall = lib.mapAttrs (_: firewallOf) nodes;
};
mounts = {
fileSystems = lib.mapAttrs (_: fileSystemsOf) nodes;
declared = lib.mapAttrs (_: mountsOf) deployments;
};
users = lib.mapAttrs (_: usersOf) nodes;
units = lib.mapAttrs (
_: c: lib.listToAttrs (map (u: lib.nameValuePair u.name (unitSummary u)) (allUnits c))
) nodes;
dependencies = {
edges =
lib.concatLists (lib.mapAttrsToList (node: c: lib.concatMap (unitEdges node) (allUnits c)) nodes)
++ map (c: {
from = "@host:${unitOf c}";
to = "${c.name}:multi-user.target";
kind = "spawns";
}) depList;
};
nftables = {
inherit (cfg.networking.nftables) enable ruleset;
tables = lib.mapAttrs (n: t: {
name = t.name or n;
inherit (t) family enable content;
}) cfg.networking.nftables.tables;
rendered = builtins.readFile (
builtins.elemAt cfg.systemd.services.nftables.serviceConfig.ExecStart 1
);
};
};
}