mirror of
https://github.com/oddlama/nix-config.git
synced 2025-10-10 14:50:40 +02:00
feat(topology): begin writing elk based renderer
This commit is contained in:
parent
8f66df0238
commit
3e14f82952
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 |
|
@ -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 |
|
@ -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 |
|
@ -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);
|
||||
})
|
||||
]);
|
||||
}));
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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))}
|
||||
|
|
91
topology/topology/renderers/elk/default.nix
Normal file
91
topology/topology/renderers/elk/default.nix
Normal 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))}
|
||||
'';
|
||||
}
|
|
@ -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}
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue