1
1
Fork 1
mirror of https://github.com/oddlama/nix-config.git synced 2025-10-10 23:00:39 +02:00

feat(topology): begin writing elk based renderer

This commit is contained in:
oddlama 2024-03-24 21:28:16 +01:00
parent 8f66df0238
commit 3e14f82952
No known key found for this signature in database
GPG key ID: 14EFE510775FE39A
8 changed files with 114 additions and 31 deletions

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 7 KiB

Before After
Before After

View file

@ -1,3 +1 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 -127 1278 1278" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M186.97049 390.020858c249.283591-143.926213 654.058848-143.926213 903.342438 0 249.283591 143.921015 249.283591 377.621133 0 521.542148-249.283591 143.926213-654.058848 143.926213-903.342438 0-249.288789-143.921015-249.288789-377.621133 0-521.542148z" fill="#4467AE" /><path d="M0.005198 368.719633h1277.273022v282.072299H0.005198z" fill="#4467AE" /><path d="M186.97049 107.948559c249.283591-143.926213 654.058848-143.926213 903.342438 0 249.283591 143.921015 249.283591 377.621133 0 521.542148-249.283591 143.926213-654.058848 143.926213-903.342438 0-249.288789-143.921015-249.288789-377.621133 0-521.542148z" fill="#6D8ACA" /><path d="M436.243685 524.263279l57.323062 33.095388-164.5621-6.819719-11.814955-95.008246 57.323063 33.095388 148.037797-85.475194 61.73093 35.642386-148.037797 85.469997zM846.320857 216.221989l-57.323063-33.09019 164.562101 6.819719 11.814954 95.008246-57.323062-33.095388-148.037797 85.469996-61.73093-35.637188 148.037797-85.475195zM445.418078 199.744468l57.323062-33.09019-164.5621 6.819718-11.814955 95.008246 57.323063-33.095388 148.042995 85.469997 61.730929-35.637189L445.418078 199.744468zM865.501316 513.560686l-57.323063 33.095388 164.5621-6.819718 11.814955-95.008246-57.323062 33.095388-148.037797-85.469997-61.73093 35.637189 148.037797 85.469996z" fill="#FFFFFF" /></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" class="icon" viewBox="0 -127 1278 1278"><path fill="#4467AE" d="M186.97 390.02c249.28-143.93 654.06-143.93 903.34 0 249.28 143.92 249.28 377.62 0 521.54-249.28 143.93-654.06 143.93-903.34 0-249.29-143.92-249.29-377.62 0-521.54"/><path fill="#4467AE" d="M.005 368.72h1277.3v282.07H.005z"/><path fill="#6D8ACA" d="M186.97 107.95c249.28-143.93 654.06-143.93 903.34 0 249.28 143.92 249.28 377.62 0 521.54-249.28 143.93-654.06 143.93-903.34 0-249.29-143.92-249.29-377.62 0-521.54"/><path fill="#fff" d="m436.24 524.26 57.323 33.095-164.56-6.82-11.815-95.008 57.323 33.095 148.04-85.475 61.731 35.642-148.04 85.47zm410.08-308.04-57.323-33.09 164.56 6.82 11.815 95.008-57.323-33.095-148.04 85.47-61.731-35.637 148.04-85.475zm-400.9-16.478 57.323-33.09-164.56 6.82-11.815 95.008 57.323-33.095 148.04 85.47 61.731-35.637-148.04-85.475zm420.08 313.82-57.323 33.095 164.56-6.82 11.815-95.008-57.323 33.095-148.04-85.47-61.731 35.637 148.04 85.47z"/></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1,009 B

Before After
Before After

View file

@ -1,3 +1 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 -166 1356 1356" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M0 389.700161h1353.843886v242.365139H0z" fill="#4467AE" /><path d="M711.710196 249.301199c-19.198737-11.087447-48.289414-12.293043-64.920585-2.693674L11.223644 613.552592c-16.626126 9.599369-14.537772 26.397002 4.660965 37.48445l626.244037 361.557718c19.203781 11.087447 48.294458 12.293043 64.920585 2.693674l635.565967-366.945067c16.631171-9.599369 14.542816-26.397002-4.660965-37.484449L711.710196 249.301199z" fill="#4467AE" /><path d="M711.710196 9.170701c-19.198737-11.082403-48.289414-12.293043-64.920585-2.68863L11.223644 373.427138c-16.626126 9.599369-14.537772 26.391958 4.660965 37.479405l626.244037 361.562763c19.203781 11.087447 48.294458 12.293043 64.920585 2.693674l635.565967-366.945067c16.631171-9.604413 14.542816-26.397002-4.660965-37.48445L711.710196 9.170701z" fill="#6D8ACA" /><path d="M296.203321 413.751548l-60.274753 34.800863 12.424196-99.908088 173.04085-7.173044-60.274753 34.800864 187.139765 108.0446-64.915541 37.479405L296.203321 413.751548zM533.21642 276.913886l-60.274752 34.800864 12.424196-99.908089 173.040849-7.173043-60.274752 34.800863 187.139765 108.0446-64.915541 37.474361-187.139765-108.039556z" fill="#FFFFFF" /><path d="M1057.640566 367.888459l60.274752-34.800864-12.424195 99.908089-173.045895 7.173043 60.279797-34.800863-187.139764-108.0446 64.91554-37.479405 187.139765 108.0446zM820.622422 504.731164l60.279797-34.800863-12.424196 99.908089-173.045894 7.173043 60.279797-34.805908-187.139765-108.039556 64.91554-37.479405 187.134721 108.0446z" fill="#FFFFFF" /></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" class="icon" viewBox="0 -166 1356 1356"><path fill="#4467AE" d="M0 389.7h1353.8v242.37H0z"/><path fill="#4467AE" d="M711.71 249.3c-19.199-11.087-48.289-12.293-64.921-2.694l-635.57 366.95c-16.626 9.6-14.538 26.397 4.661 37.484l626.24 361.56c19.204 11.087 48.294 12.293 64.921 2.694l635.57-366.95c16.631-9.6 14.543-26.397-4.661-37.484z"/><path fill="#6D8ACA" d="M711.71 9.17C692.511-1.91 663.421-3.121 646.789 6.483l-635.57 366.95c-16.626 9.6-14.538 26.392 4.661 37.48l626.24 361.56c19.204 11.086 48.294 12.292 64.921 2.693l635.57-366.95c16.631-9.605 14.543-26.397-4.661-37.484z"/><path fill="#fff" d="m296.2 413.75-60.275 34.801 12.424-99.908 173.04-7.173-60.275 34.801 187.14 108.04-64.916 37.479-187.14-108.04zm237.01-136.84-60.275 34.801 12.424-99.908 173.04-7.173-60.275 34.801 187.14 108.04-64.916 37.474-187.14-108.04zM1057.6 367.89l60.275-34.801-12.424 99.908-173.05 7.173 60.28-34.801-187.14-108.04 64.916-37.479 187.14 108.04zM820.58 504.73l60.28-34.801-12.424 99.908-173.05 7.173 60.28-34.806-187.14-108.04 64.916-37.479 187.13 108.04z"/></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before After
Before After

View file

@ -104,11 +104,9 @@ in
);
}
# If the device type is generic device, try to render as an image
# and set the default image to the deviceIcon.
# If the device type is not a full nixos node, try to render it as an image with name.
(mkIf (elem nodeCfg.deviceType ["router" "switch" "device"]) {
preferredRenderType = mkDefault "image";
hardware.image = mkDefault (config.lib.icons.get nodeCfg.deviceIcon);
})
]);
}));

View file

@ -45,9 +45,9 @@ in {
};
renderer = mkOption {
description = "Which renderer to use for the default output. Availble options: ${toString availableRenderers}";
description = "Which renderer to use for the default output. Available options: ${toString availableRenderers}";
type = types.nullOr (types.enum availableRenderers);
default = "d2";
default = "elk";
};
output = mkOption {

View file

@ -39,7 +39,7 @@
node_${node.id}: "" {
shape: image
width: 680
icon: ${config.lib.renderers.svg.node.mkInfoCardNetwork node}
icon: ${config.lib.renderers.svg.node.mkPreferredRender node}
}
${concatLines (map (nodeInterfaceToD2 node) (attrValues node.interfaces))}

View file

@ -0,0 +1,91 @@
{
config,
lib,
pkgs,
...
}: let
inherit
(lib)
any
attrValues
concatLines
flip
mkOption
optionalString
types
;
toBase64 = text: let
inherit (lib) sublist mod stringToCharacters concatMapStrings;
inherit (lib.strings) charToInt;
inherit (builtins) substring foldl' genList elemAt length concatStringsSep stringLength;
lookup = stringToCharacters "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789__";
sliceN = size: list: n: sublist (n * size) size list;
pows = [(64 * 64 * 64) (64 * 64) 64 1];
intSextets = i: map (j: mod (i / j) 64) pows;
compose = f: g: x: f (g x);
intToChar = elemAt lookup;
convertTripletInt = sliceInt: concatMapStrings intToChar (intSextets sliceInt);
sliceToInt = foldl' (acc: val: acc * 256 + val) 0;
convertTriplet = compose convertTripletInt sliceToInt;
join = concatStringsSep "";
convertLastSlice = slice: let
len = length slice;
in
if len == 1
then (substring 0 2 (convertTripletInt ((sliceToInt slice) * 256 * 256))) + "__"
else if len == 2
then (substring 0 3 (convertTripletInt ((sliceToInt slice) * 256))) + "_"
else "";
len = stringLength text;
nFullSlices = len / 3;
bytes = map charToInt (stringToCharacters text);
tripletAt = sliceN 3 bytes;
head = genList (compose convertTriplet tripletAt) nFullSlices;
tail = convertLastSlice (tripletAt nFullSlices);
in
join (head ++ [tail]);
netToElk = net: ''
node net_${toBase64 net.id} {
label "${net.name}"
}
'';
nodeInterfaceToElk = node: interface:
concatLines (flip map interface.physicalConnections (x:
optionalString (
(!any (y: y.node == node.id && y.interface == interface.id) config.nodes.${x.node}.interfaces.${x.interface}.physicalConnections)
|| (node.id < x.node)
)
''
edge node_${toBase64 node.id} -> node_${toBase64 x.node}
''));
nodeToElk = node: ''
node node_${toBase64 node.id} {
layout [size: 680, 0]
label "${node.name}"
}
${concatLines (map (nodeInterfaceToElk node) (attrValues node.interfaces))}
'';
in {
options.renderers.elk = {
output = mkOption {
description = "The derivation containing the rendered output";
type = types.path;
readOnly = true;
};
};
config.renderers.elk.output = pkgs.writeText "graph.elk" ''
interactiveLayout: true
separateConnectedComponents: false
crossingMinimization.semiInteractive: true
elk.direction: RIGHT
${concatLines (map netToElk (attrValues config.networks))}
${concatLines (map nodeToElk (attrValues config.nodes))}
'';
}

View file

@ -45,11 +45,10 @@
'';
renderHtmlToSvg = card: name: let
drv = pkgs.runCommand "generate-svg-${name}" {} ''
mkdir -p $out
${htmlToSvgCommand (pkgs.writeText "${name}.html" card.html) "$out/${name}.svg" card}
out = pkgs.runCommand "${name}.svg" {} ''
${htmlToSvgCommand (pkgs.writeText "${name}.html" card.html) "$out" card}
'';
in "${drv}/${name}.svg";
in "${out}";
html = rec {
mkImage = twAttrs: file:
@ -63,9 +62,9 @@
content = head (splitString "</svg>" withoutPrefix);
in ''<svg tw="${twAttrs}" ${content}</svg>''
else if hasSuffix ".png" file
then ''<img tw="object-contain ${twAttrs}" src="data:image/png;base64,${builtins.readFile fileBase64 file}/>"''
then ''<img tw="object-contain ${twAttrs}" src="data:image/png;base64,${builtins.readFile (fileBase64 file)}"/>''
else if hasSuffix ".jpg" file || hasSuffix ".jpeg" file
then ''<img tw="object-contain ${twAttrs}" src="data:image/jpeg;base64,${builtins.readFile fileBase64 file}/>"''
then ''<img tw="object-contain ${twAttrs}" src="data:image/jpeg;base64,${builtins.readFile (fileBase64 file)}"/>''
else builtins.throw "Unsupported icon file type: ${file}";
mkImageMaybeIf = cond: twAttrs: file: optionalString (cond && file != null) (mkImage twAttrs file);
@ -164,9 +163,8 @@
''
<div tw="flex flex-row mx-6 mt-2 items-center">
${mkImageMaybe "w-12 h-12 mr-4" (config.lib.icons.get node.icon)}
<h2 tw="grow text-4xl font-bold">${node.name}</h2>
<div tw="flex grow"></div>
<h2 tw="text-4xl">${node.deviceType}</h2>
<h2 tw="text-4xl font-bold">${node.name}</h2>
<div tw="flex grow min-w-8"></div>
${mkImageMaybe "w-16 h-16 ml-4" (config.lib.icons.get node.deviceIcon)}
</div>
'';
@ -214,20 +212,22 @@
html = let
deviceIconImage = config.lib.icons.get node.deviceIcon;
in
mkRootContainer ""
mkRootContainer "items-center"
/*
html
*/
''
<div tw="flex flex-row mx-6 mt-2 items-center">
${mkImageMaybe "w-12 h-12 mr-4" (config.lib.icons.get node.icon)}
<h2 tw="grow text-4xl font-bold">${node.name}</h2>
<div tw="flex grow"></div>
<h2 tw="text-4xl">${node.deviceType}</h2>
${mkImageMaybeIf (node.hardware.image != null -> deviceIconImage != node.hardware.image) "w-16 h-16 ml-4" deviceIconImage}
${mkImageMaybe "w-12 h-12" (config.lib.icons.get node.icon)}
<h2 tw="text-4xl font-bold">${node.name}</h2>
${optionalString (node.hardware.image != null -> deviceIconImage != node.hardware.image)
''
<div tw="flex grow min-w-8"></div>
${mkImageMaybe "w-16 h-16" deviceIconImage}
''}
</div>
${mkImageMaybe "w-full h-24" node.hardware.image}
${mkImageMaybe "h-24" node.hardware.image}
'';
};