adding cypher graph generation utitlies
parent
cffdd7bbd7
commit
1f2cbd03b8
@ -0,0 +1,170 @@
|
||||
{ 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 (_: { isRouter, 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 = runCommand "import-network-graphs" {} ''
|
||||
${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})\"}]}"
|
||||
'';
|
||||
|
||||
}
|
Loading…
Reference in New Issue