172 lines
4.8 KiB
Nix
172 lines
4.8 KiB
Nix
{ config, pkgs, ... }:
|
|
let
|
|
inherit (pkgs) lib runCommand graphviz;
|
|
|
|
netColor = net:
|
|
if net == "core"
|
|
then "grey"
|
|
else if net == "mgmt"
|
|
then "brown"
|
|
else if builtins.elem net [ "c3d2" "serv" "cluster" ]
|
|
then "green"
|
|
else if builtins.match "up.+" net != null ||
|
|
builtins.match "anon.+" net != null
|
|
then "red"
|
|
else if builtins.match "priv.+" net != null
|
|
then "blue"
|
|
else "black";
|
|
|
|
dedupLinks = links:
|
|
builtins.attrValues (
|
|
builtins.foldl' (result: { pair, attrs ? {}, startLabel ? "" }:
|
|
let
|
|
peer1 = builtins.elemAt pair 0;
|
|
peer2 = builtins.elemAt pair 1;
|
|
sorted =
|
|
if peer1 < peer2
|
|
then { from = peer1; to = peer2; }
|
|
else { from = peer2; to = peer1; };
|
|
key = with sorted; "${from} ${to}";
|
|
prevAttrs =
|
|
if result ? ${key}
|
|
then result.${key}.attrs
|
|
else {};
|
|
newAttrs = attrs // (
|
|
if peer1 < peer2
|
|
then { taillabel = startLabel; }
|
|
else { headlabel = startLabel; }
|
|
);
|
|
in result // {
|
|
"${key}" = {
|
|
inherit (sorted) from to;
|
|
attrs = prevAttrs // newAttrs;
|
|
};
|
|
}
|
|
) {} links
|
|
);
|
|
|
|
toDot = { nodes, links, ... }: ''
|
|
digraph {
|
|
graph [splines=ortho, nodesep=64]
|
|
node []
|
|
edge [arrowhead=none, labelfontsize=8]
|
|
|
|
${lib.concatMapStrings (name:
|
|
let
|
|
nodeAttrs = nodes.${name};
|
|
in ''
|
|
"${name}" [${lib.concatMapStringsSep ", " (attr:
|
|
let
|
|
value = nodeAttrs.${attr};
|
|
in
|
|
if builtins.isString value
|
|
then "${attr}=\"${value}\""
|
|
else "${attr}=${toString value}"
|
|
) (builtins.attrNames nodeAttrs)}]
|
|
'') (builtins.attrNames nodes)}
|
|
|
|
${lib.concatMapStrings ({ from, to, attrs }: ''
|
|
"${from}" -> "${to}" [${lib.concatMapStringsSep ", " (attr:
|
|
let
|
|
value = attrs.${attr};
|
|
in
|
|
if builtins.isString value
|
|
then "${attr}=\"${value}\""
|
|
else "${attr}=${toString value}"
|
|
) (builtins.attrNames attrs)}]
|
|
'') (dedupLinks links)}
|
|
}
|
|
'';
|
|
renderGraph = args@{ name, engine, ... }:
|
|
runCommand "${name}.png" {
|
|
src = builtins.toFile "${name}.dot" (
|
|
toDot args
|
|
);
|
|
} ''
|
|
echo $src
|
|
${graphviz}/bin/${engine} -Tpng $src > $out
|
|
'';
|
|
|
|
in rec {
|
|
# Layer 2
|
|
physical-graph = renderGraph {
|
|
name = "physical";
|
|
engine = "fdp";
|
|
nodes =
|
|
builtins.mapAttrs (_: { role, ... }: {
|
|
shape = {
|
|
switch = "box";
|
|
server = "house";
|
|
container = "oval";
|
|
ap = "doubleoctagon";
|
|
client = "doublecircle";
|
|
}.${role};
|
|
}) (
|
|
lib.filterAttrs (_: { links, ... }:
|
|
links != {}
|
|
) config.site.hosts
|
|
) // builtins.mapAttrs (_: _: {
|
|
shape = "circle";
|
|
}) (
|
|
lib.filterAttrs (net: _:
|
|
builtins.match "up.*" net != null
|
|
) config.site.net
|
|
);
|
|
links =
|
|
builtins.concatMap (hostName:
|
|
map (link: {
|
|
pair = [ hostName link ];
|
|
startLabel = ( #lib.optionalString (config.site.hosts.${hostName}.links ? ${link}) (
|
|
lib.concatStringsSep ","
|
|
config.site.hosts.${hostName}.links.${link}.ports
|
|
);
|
|
}) (
|
|
builtins.filter (link:
|
|
config.site.hosts ? ${link}
|
|
||
|
|
builtins.match "up.*" link != null
|
|
) (builtins.attrNames config.site.hosts.${hostName}.links)
|
|
)
|
|
) (builtins.attrNames config.site.hosts);
|
|
};
|
|
|
|
# Layer 3
|
|
logical-graph =
|
|
let
|
|
containers =
|
|
lib.filterAttrs (_: { isRouter, role, ... }:
|
|
role == "container"
|
|
) config.site.hosts;
|
|
in
|
|
renderGraph {
|
|
name = "logical";
|
|
engine = "sfdp";
|
|
nodes =
|
|
builtins.foldl' (result: hostName:
|
|
result // {
|
|
"${hostName}".shape = "box";
|
|
} // builtins.mapAttrs (_: _: {
|
|
shape = "circle";
|
|
}) containers.${hostName}.interfaces
|
|
) {} (builtins.attrNames containers);
|
|
links =
|
|
builtins.concatMap (hostName:
|
|
map (net: {
|
|
pair = [ hostName net ];
|
|
attrs.color = netColor net;
|
|
}) (builtins.attrNames containers.${hostName}.interfaces)
|
|
) (builtins.attrNames containers);
|
|
};
|
|
|
|
network-graphs = runCommand "network-graphs" {} ''
|
|
DIR=$out/share/doc/zentralwerk
|
|
mkdir -p $DIR
|
|
ln -s ${physical-graph} $DIR/physical.png
|
|
ln -s ${logical-graph} $DIR/logical.png
|
|
|
|
mkdir -p $out/nix-support
|
|
echo doc image $DIR/physical.png >> $out/nix-support/hydra-build-products
|
|
echo doc image $DIR/logical.png >> $out/nix-support/hydra-build-products
|
|
'';
|
|
}
|