173 lines
5.2 KiB
Nix
173 lines
5.2 KiB
Nix
{ config, pkgs, ... }:
|
|
let
|
|
inherit (pkgs) lib runCommand curl;
|
|
|
|
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
|
|
);
|
|
|
|
toCypher = { nodes, links, ... }: ''
|
|
${lib.concatMapStringsSep " " (name:
|
|
let
|
|
nodeAttrs = nodes.${name};
|
|
id = builtins.replaceStrings ["-"] ["_"] name;
|
|
nodeType = nodeAttrs.type;
|
|
in ''
|
|
CREATE (${id}:`${nodeType}`
|
|
{label:"${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.concatMapStringsSep " " ({ from, to, attrs }:
|
|
let
|
|
idFrom = builtins.replaceStrings ["-"] ["_"] from;
|
|
idTo = builtins.replaceStrings ["-"] ["_"] to;
|
|
in ''
|
|
CREATE (${idFrom})-[:CONNECTED_TO
|
|
{${lib.concatMapStringsSep ", " (attr:
|
|
let
|
|
value = attrs.${attr};
|
|
in
|
|
if builtins.isString value
|
|
then "${attr}:\"${value}\""
|
|
else "${attr}:${toString value}"
|
|
) (builtins.attrNames attrs)}
|
|
}]->(${idTo})
|
|
'') (dedupLinks links)}
|
|
'';
|
|
|
|
cypherGraph = args@{ name, ... }:
|
|
runCommand "${name}.cypher" {
|
|
src = builtins.toFile "${name}.cypher" (
|
|
toCypher args
|
|
);
|
|
} ''
|
|
sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' $src | tr -d '\n' > $out
|
|
'';
|
|
|
|
in rec {
|
|
# Layer 2
|
|
physical-cypher-graph = cypherGraph {
|
|
name = "physical";
|
|
nodes =
|
|
builtins.mapAttrs (_: { role, ... }: {
|
|
type = {
|
|
switch = "Switch";
|
|
server = "Server";
|
|
container = "Container";
|
|
ap = "AccessPoint";
|
|
client = "Client";
|
|
}.${role};
|
|
}) (
|
|
lib.filterAttrs (_: { links, ... }:
|
|
links != {}
|
|
) config.site.hosts
|
|
) // builtins.mapAttrs (_: _: {
|
|
type = "Other";
|
|
}) (
|
|
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-cypher-graph =
|
|
let
|
|
containers =
|
|
lib.filterAttrs (_: { role, ... }:
|
|
role == "container"
|
|
) config.site.hosts;
|
|
in
|
|
cypherGraph {
|
|
name = "logical";
|
|
nodes =
|
|
builtins.foldl' (result: hostName:
|
|
result // {
|
|
"${hostName}".type = "Container";
|
|
} // builtins.mapAttrs (_: _: {
|
|
type = "Container";
|
|
}) 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);
|
|
};
|
|
|
|
|
|
import-network-graphs = with pkgs; writeScriptBin "import-network-graphs" ''
|
|
#! ${runtimeShell} -e
|
|
|
|
${curl}/bin/curl -X POST -H 'Content-type: application/json' http://localhost:7474/db/data/transaction/commit -d "{\"statements\": [{\"statement\": \"$(cat ${physical-cypher-graph})\"}]}"
|
|
${curl}/bin/curl -X POST -H 'Content-type: application/json' http://localhost:7474/db/data/transaction/commit -d "{\"statements\": [{\"statement\": \"$(cat ${logical-cypher-graph})\"}]}"
|
|
'';
|
|
|
|
}
|