forked from mirrors_public/oddlama_nix-config
chore: topology updates and experiments
This commit is contained in:
parent
d494e19e1c
commit
35275d09d5
2 changed files with 67 additions and 129 deletions
|
@ -52,130 +52,31 @@
|
|||
|
||||
nodesById = mapAttrs' (_: node: nameValuePair node.config.topology.id node) nixosConfigurations;
|
||||
|
||||
xmlAttrs = attrs: concatStringsSep " " (mapAttrsToList (n: v: "${n}=\"${v}\"") attrs);
|
||||
font = attrs: text: "<font ${xmlAttrs attrs}>${text}</font>";
|
||||
fontMono = {face = "JetBrains Mono";};
|
||||
mono = font fontMono;
|
||||
monoColor = color: font (fontMono // {inherit color;});
|
||||
|
||||
mkCell = cellAttrs: text: "<td ${xmlAttrs cellAttrs}>${text}</td>";
|
||||
mapToTableRows = xs: {
|
||||
columnOrder,
|
||||
columns,
|
||||
titleRow ? true,
|
||||
titleRowColor ? colors.base0C,
|
||||
titleRowAttrs ? {bgcolor = titleRowColor;},
|
||||
alternateRowAttrs ? {bgcolor = colors.base03b;},
|
||||
}:
|
||||
concatLines (
|
||||
optional titleRow "<tr>${concatStringsSep "" (flip map columnOrder (c: mkCell titleRowAttrs "<b>${mono columns.${c}.title}</b>"))}</tr>"
|
||||
++ flip imap0 xs (
|
||||
i: x: "<tr>${concatStringsSep "" (flip map columnOrder (c:
|
||||
mkCell
|
||||
(optionalAttrs (pkgs.lib.mod i 2 == 1) alternateRowAttrs // (columns.${c}.cellAttrs or {}))
|
||||
(columns.${c}.transform x.${c})))}</tr>"
|
||||
)
|
||||
);
|
||||
|
||||
mkTable = xs: settings: ''
|
||||
<table border="0" cellborder="0" cellspacing="0" cellpadding="4" bgcolor="${colors.base03}" color="${colors.base04}">
|
||||
${mapToTableRows xs settings}
|
||||
</table>
|
||||
'';
|
||||
|
||||
nodeId = str: "\"${escapeXML str}\"";
|
||||
isGuestOfAny = node: any (x: elem node x.config.topology.guests) (attrValues nodesById);
|
||||
rootNodes = filterAttrs (n: _: !(isGuestOfAny n)) nodesById;
|
||||
|
||||
toDot = node: let
|
||||
toD2 = node: let
|
||||
topo = node.config.topology;
|
||||
in ''
|
||||
${topo.id}: |md
|
||||
# ${topo.id}
|
||||
|
||||
diskTable = mkTable (attrValues topo.disks) {
|
||||
titleRowColor = colors.base0F;
|
||||
columnOrder = ["name"];
|
||||
columns = {
|
||||
name = {
|
||||
title = "Name";
|
||||
transform = mono;
|
||||
};
|
||||
};
|
||||
};
|
||||
## Guests:
|
||||
${concatLines (map (x: "- ${x}") topo.guests)}
|
||||
|
||||
interfaceTable = mkTable (attrValues topo.interfaces) {
|
||||
titleRowColor = colors.base0D;
|
||||
columnOrder = ["name" "mac" "addresses"];
|
||||
columns = {
|
||||
name = {
|
||||
title = "Name";
|
||||
transform = x:
|
||||
if x == null
|
||||
then ""
|
||||
else mono x;
|
||||
};
|
||||
mac = {
|
||||
title = "MAC";
|
||||
transform = x:
|
||||
if x == null
|
||||
then ""
|
||||
else monoColor colors.base09 x;
|
||||
};
|
||||
addresses = {
|
||||
title = "Addr";
|
||||
transform = xs: mono (concatStringsSep " " xs);
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
''
|
||||
subgraph ${nodeId "cluster_${topo.id}"} {
|
||||
color = "${colors.base04}";
|
||||
## Disks:
|
||||
${concatLines (mapAttrsToList (_: v: "- ${v.name}") topo.disks)}
|
||||
|
||||
${nodeId topo.id} [label=<
|
||||
<table border="0" cellborder="0" cellspacing="0" cellpadding="4" bgcolor="${colors.base03}" color="${colors.base04}">
|
||||
<tr><td bgcolor="${colors.base08}"><b>${mono "Attribute"}</b></td><td bgcolor="${colors.base08}"><b>${mono "Value"}</b></td></tr>
|
||||
<tr><td>${mono "id"}</td><td>${mono topo.id}</td></tr>
|
||||
<tr><td>${mono "type"}</td><td>${mono topo.type}</td></tr>
|
||||
</table>
|
||||
>];
|
||||
## Interfaces:
|
||||
${concatLines (mapAttrsToList (_: v: "- ${v.name}, mac ${toString v.mac}, addrs ${toString v.addresses}, network ${toString v.network}") topo.interfaces)}
|
||||
|
||||
{
|
||||
rank = "same";
|
||||
${nodeId "${topo.id}.disks"} [label=<
|
||||
${diskTable}
|
||||
>];
|
||||
${nodeId "${topo.id}.interfaces"} [label=<
|
||||
${interfaceTable}
|
||||
>];
|
||||
}
|
||||
## Firewall Zones:
|
||||
${concatLines (mapAttrsToList (_: v: "- ${v.name}, mac ${toString v.mac}, addrs ${toString v.addresses}, network ${toString v.network}") topo.firewallRules)}
|
||||
|
|
||||
'';
|
||||
|
||||
${nodeId topo.id} -> ${nodeId "${topo.id}.disks"} [label="disks", color="${colors.base05}", fontcolor="${colors.base06}"];
|
||||
${nodeId topo.id} -> ${nodeId "${topo.id}.interfaces"} [label="interfaces", color="${colors.base05}", fontcolor="${colors.base06}"];
|
||||
''
|
||||
+ optionalString (topo.guests != []) ''
|
||||
subgraph ${nodeId "cluster_guests_${topo.id}"} {
|
||||
color = "${colors.base04}";
|
||||
{
|
||||
rank = "same";
|
||||
${concatLines (map (guest: "${nodeId guest};") topo.guests)}
|
||||
}
|
||||
|
||||
${concatLines (map (guest: dotForNodes.${guest}) topo.guests)}
|
||||
};
|
||||
|
||||
${concatLines (map (guest: "${nodeId topo.id} -> ${nodeId guest} [color=\"${colors.base05}\"];") topo.guests)}
|
||||
}
|
||||
''
|
||||
+ optionalString (!isGuestOfAny topo.id) ''
|
||||
root -> ${nodeId topo.id} [color="${colors.base05}"];
|
||||
'';
|
||||
|
||||
dotForNodes = mapAttrs' (_: node: nameValuePair node.config.topology.id (toDot node)) nodesById;
|
||||
d2ForNodes = mapAttrs' (_: node: nameValuePair node.config.topology.id (toD2 node)) nodesById;
|
||||
in
|
||||
pkgs.writeText "topology.dot" ''
|
||||
digraph G {
|
||||
graph [rankdir=TB, splines=spline, bgcolor="${colors.base00}"];
|
||||
node [shape=plaintext, fontcolor="${colors.base06}", color="${colors.base06}"];
|
||||
|
||||
${concatLines (map (x: dotForNodes.${x}) (attrNames rootNodes))}
|
||||
}
|
||||
pkgs.writeText "topology.d2" ''
|
||||
${concatLines (map (x: d2ForNodes.${x}) (attrNames rootNodes))}
|
||||
''
|
||||
|
|
|
@ -19,24 +19,44 @@ in {
|
|||
options.topology = {
|
||||
id = mkOption {
|
||||
description = ''
|
||||
The attribute name in nixosConfigurations corresponding to this host.
|
||||
Please overwrite with a unique identifier if your hostnames are not
|
||||
The attribute name in the given `nodes` which corresponds to this host.
|
||||
Please overwrite it with a unique identifier if your hostnames are not
|
||||
unique or don't reflect the name you use to refer to that node.
|
||||
'';
|
||||
default = config.networking.hostName;
|
||||
# TODO ensure unique across the board
|
||||
type = types.str;
|
||||
};
|
||||
guests = mkOption {
|
||||
description = "TODO guests ids (topology.id)";
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
|
||||
type = mkOption {
|
||||
description = "TODO";
|
||||
type = types.enum ["normal" "microvm" "nixos-container"];
|
||||
default = "normal";
|
||||
type = types.enum ["normal" "microvm" "nixos-container"];
|
||||
};
|
||||
|
||||
guests = mkOption {
|
||||
description = "TODO guests ids (topology.node.<name>.id) ensure exists";
|
||||
default = [];
|
||||
type = types.listOf types.str;
|
||||
};
|
||||
|
||||
disks = mkOption {
|
||||
default = {};
|
||||
type = types.attrsOf (types.submodule (submod: {
|
||||
options = {
|
||||
name = mkOption {
|
||||
description = "The name of this disk";
|
||||
default = submod.config._module.args.name;
|
||||
readOnly = true;
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
}));
|
||||
};
|
||||
|
||||
interfaces = mkOption {
|
||||
description = "TODO";
|
||||
default = {};
|
||||
type = types.attrsOf (types.submodule (submod: {
|
||||
options = {
|
||||
name = mkOption {
|
||||
|
@ -48,30 +68,45 @@ in {
|
|||
|
||||
mac = mkOption {
|
||||
description = "The MAC address of this interface, if known.";
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
type = types.nullOr types.str;
|
||||
};
|
||||
|
||||
addresses = mkOption {
|
||||
description = "The configured address(es), or a descriptive string (like DHCP).";
|
||||
type = types.listOf types.str;
|
||||
};
|
||||
|
||||
network = mkOption {
|
||||
description = ''
|
||||
The global name of the attached/spanned network.
|
||||
If this is given, this interface can be shown in the network graph.
|
||||
'';
|
||||
default = null;
|
||||
type = types.nullOr types.str;
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = {};
|
||||
};
|
||||
disks = mkOption {
|
||||
|
||||
firewallRules = mkOption {
|
||||
description = "TODO";
|
||||
default = {};
|
||||
type = types.attrsOf (types.submodule (submod: {
|
||||
options = {
|
||||
name = mkOption {
|
||||
description = "The name of this disk";
|
||||
description = "The name of this firewall rule";
|
||||
type = types.str;
|
||||
readOnly = true;
|
||||
default = submod.config._module.args.name;
|
||||
};
|
||||
|
||||
contents = mkOption {
|
||||
description = "A human readable summary of this rule's effects";
|
||||
type = types.lines;
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -89,8 +124,10 @@ in {
|
|||
disks =
|
||||
flip mapAttrs (config.disko.devices.disk or {})
|
||||
(_: _: {});
|
||||
# TODO: zfs pools from disko / fileSystems
|
||||
# TODO: microvm shares
|
||||
# TODO: container shares
|
||||
# TODO: OCI containers shares
|
||||
|
||||
interfaces = let
|
||||
isNetwork = netDef: (netDef.matchConfig != {}) && (netDef.address != [] || netDef.DHCP != null);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue