400 lines
9.1 KiB
Nix
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
|
|
);
|
|
};
|
|
};
|
|
}
|