initial commit
This commit is contained in:
+399
@@ -0,0 +1,399 @@
|
||||
{ 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
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user