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

feat(topology): add services overview card

This commit is contained in:
oddlama 2024-03-28 01:39:31 +01:00
parent 07191bac9b
commit b822b4e812
No known key found for this signature in database
GPG key ID: 14EFE510775FE39A
8 changed files with 177 additions and 67 deletions

1
cloud.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="400" aria-hidden="true" class="iconify iconify--noto" viewBox="0 0 128 128"><path fill="#e4eaee" d="M23.45 62.3c.72-.72-1.27-9.29 7.6-15.91s14.92-2.67 15.77-2.96c.84-.28 4.79-17.6 21.4-22.1s33.93 3.94 38.01 18.02c3.73 12.87.84 21.54 1.27 22.1.42.56 8.45.28 13.09 7.74s2.96 12.11 2.96 12.11l-29.56 9.15h-47.3S5.02 79.47 4.6 77.5s.53-8.37 7.32-12.25c5.9-3.37 10.26-1.68 11.53-2.95"/><path fill="#bacdd2" d="M35.16 92.84s-15.78 3.3-26.45-4.96C2.29 82.9 4.63 74.83 4.63 74.83s4.6 4.65 13.89 5.91c9.29 1.27 19.71.84 19.71.84s2.6 4.44 12.39 6.48c12.27 2.55 18.74-3.73 18.74-3.73s3.36 4.02 15.19 4.3 18.46-7.98 19.57-8.17c.56-.09 3.82 2.87 10.28 1.83 6.15-.99 9.39-3.66 9.39-3.66s.89 6.62-5.3 10.7c-4.83 3.18-13.23 3.52-13.23 3.52s-1.28 4.91-7.05 8.48c-5.36 3.33-14.6 4.44-21.44 2.4-8.59-2.56-10.72-6.47-10.72-6.47s-6.4 3.75-16.4 2.48c-9.45-1.18-14.49-6.9-14.49-6.9"/></svg>

After

Width:  |  Height:  |  Size: 929 B

View file

@ -192,47 +192,69 @@
deviceType = "router";
hardware.image = ./fritzbox.png;
# interfaces.wan0.network = "internet";
interfaces.wan0.physicalConnections = [
interfaces.wan0 = {};
interfaces.lan0.physicalConnections = [
{
node = "ward";
interface = "wan";
}
{
node = "sire";
interface = "lan";
}
];
};
nodes.internet = {
name = "Internet";
deviceType = "internet";
hardware.image = ./cloud.svg;
# interfaces.wan0.network = "internet";
interfaces.wan0.physicalConnections = [
{
node = "fritzbox";
interface = "wan0";
}
{
node = "sentinel";
interface = "wan";
}
];
};
nodes.fritzbox-no-img = {
name = "FritzBox No HImg";
deviceType = "router";
interfaces.wan0.physicalConnections = [
{
node = "ward";
interface = "wan";
}
];
};
#nodes.fritzbox-no-img = {
# name = "FritzBox No HImg";
# deviceType = "router";
# interfaces.wan0.physicalConnections = [
# {
# node = "ward";
# interface = "wan";
# }
# ];
#};
nodes.fritzbox-device-nd = {
name = "FritzBox No DImg";
deviceType = "device";
hardware.image = ./fritzbox.png;
interfaces.wan0.physicalConnections = [
{
node = "ward";
interface = "wan";
}
];
};
#nodes.fritzbox-device-nd = {
# name = "FritzBox No DImg";
# deviceType = "device";
# hardware.image = ./fritzbox.png;
# interfaces.wan0.physicalConnections = [
# {
# node = "ward";
# interface = "wan";
# }
# ];
#};
nodes.fritzbox-device = {
name = "FritzBox No D&HImg";
deviceType = "device";
interfaces.wan0.physicalConnections = [
{
node = "ward";
interface = "wan";
}
];
};
#nodes.fritzbox-device = {
# name = "FritzBox No D&HImg";
# deviceType = "device";
# interfaces.wan0.physicalConnections = [
# {
# node = "ward";
# interface = "wan";
# }
# ];
#};
# TODO:
#nodes.fritzbox = config.lib.nodes.mkRouter {};

View file

@ -64,10 +64,6 @@
networking.nftables.firewall = {
zones.untrusted.interfaces = [config.guests.${guestName}.networking.mainLinkName];
};
# TODO: FIXME: remove!!!!
topology.self.guestType = "microvm";
topology.self.parent = config.node.name;
}
];
};

View file

@ -0,0 +1,29 @@
{
config,
lib,
...
}: let
inherit
(lib)
attrValues
flip
mkEnableOption
mkIf
mkMerge
optionalAttrs
;
in {
options.topology.extractors.microvm.enable = mkEnableOption "topology microvm extractor" // {default = true;};
config = mkIf (config.topology.extractors.microvm.enable && config ? microvm && config.microvm.host.enable) {
topology.nodes = mkMerge (flip map (attrValues config.microvm.vms) (
vm:
optionalAttrs (vm.config.config ? topology) {
${vm.config.config.topology.id} = {
guestType = "microvm";
parent = config.topology.id;
};
}
));
};
}

View file

@ -60,7 +60,7 @@ in {
};
openssh = mkIf config.services.openssh.enable {
hidden = mkDefault true; # Causes a lot of much clutter
hidden = mkDefault true; # Causes a lot of clutter
name = "OpenSSH";
icon = "services.openssh";
info = "port: ${concatStringsSep ", " (map toString config.services.openssh.ports)}";

View file

@ -66,7 +66,7 @@ in
values exist that will automatically set some other defaults, most notably
the deviceIcon and preferredRenderType.
'';
type = types.either (types.enum ["nixos" "router" "switch" "device"]) types.str;
type = types.either (types.enum ["nixos" "internet" "router" "switch" "device"]) types.str;
};
guestType = mkOption {
@ -111,7 +111,7 @@ in
}
# 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"]) {
(mkIf (elem nodeCfg.deviceType ["internet" "router" "switch" "device"]) {
preferredRenderType = mkDefault "image";
})
]);

View file

@ -19,6 +19,7 @@
mapAttrsToList
mkOption
optional
optionals
optionalAttrs
recursiveUpdate
types
@ -60,28 +61,39 @@
};
};
idForInterface = node: interfaceId:
if (node.preferredRenderType == "card")
then "children.node:${node.id}.ports.interface:${interfaceId}"
else "children.node:${node.id}";
nodeInterfaceToElk = node: interface:
[
{
(optionalAttrs (node.preferredRenderType == "card") {
children."node:${node.id}".ports."interface:${interface.id}" = {
properties = {
"port.side" = "WEST";
};
properties."port.side" = "WEST";
#x = 0;
#y = 82 + 42 * lib.lists.findFirstIndex (x: x == interface.id) 0 (builtins.attrNames node.interfaces); # FIXME: just pass index along in function call
width = 8;
height = 8;
# TODO: FIXME: not shown currently in svg
# labels.name = {
# text = interface.id;
# width = 33.0;
# height = 15.0;
# };
};
}
})
]
++ flip map interface.physicalConnections (x:
++ optionals (!interface.virtual) (flip map interface.physicalConnections (x:
optionalAttrs (
(!any (y: y.node == node.id && y.interface == interface.id) config.nodes.${x.node}.interfaces.${x.interface}.physicalConnections)
|| (node.id < x.node)
) {
edges."node:${node.id}.ports.interface:${interface.id}-to-node:${x.node}.ports.interface:${x.interface}" = {
sources = ["children.node:${node.id}.ports.interface:${interface.id}"];
targets = ["children.node:${x.node}.ports.interface:${x.interface}"];
sources = [(idForInterface node interface.id)];
targets = [(idForInterface config.nodes.${x.node} x.interface)];
};
});
}));
nodeToElk = node:
[
@ -91,23 +103,21 @@
file = config.lib.renderers.svg.node.mkPreferredRender node;
scale = 0.8;
};
properties = {
"portConstraints" = "FIXED_SIDE";
};
properties."portConstraints" = "FIXED_SIDE";
};
}
]
++ optional (node.parent != null) {
children."node:${node.parent}".ports.guests = {
properties = {
"port.side" = "EAST";
};
properties."port.side" = "EAST";
width = 8;
height = 8;
};
edges."node:${node.parent}.ports.guests-to-node:${node.id}" = {
sources = ["children.node:${node.parent}.ports.guests"];
targets = ["children.node:${node.id}"];
style.stroke-dasharray = "10,8";
style.stroke-linecap = "round";
};
}
++ map (nodeInterfaceToElk node) (attrValues node.interfaces);
@ -128,10 +138,23 @@ in {
layoutOptions = {
"org.eclipse.elk.algorithm" = "layered";
"org.eclipse.elk.edgeRouting" = "ORTHOGONAL";
"org.eclipse.elk.direction" = "RIGHT";
"org.eclipse.elk.layered.crossingMinimization.strategy" = true;
"org.eclipse.elk.layered.nodePlacement.strategy" = "NETWORK_SIMPLEX";
"org.eclipse.elk.layered.spacing.edgeNodeBetweenLayers" = 40;
"org.eclipse.elk.direction" = "RIGHT";
"org.eclipse.elk.layered.spacing.edgeEdgeBetweenLayers" = 25;
"org.eclipse.elk.spacing.edgeEdge" = 50;
"org.eclipse.elk.spacing.edgeNode" = 50;
};
}
# Add service overview
{
children.services-overview = {
svg = {
file = config.lib.renderers.svg.services.mkOverview;
scale = 0.8;
};
};
}
]

View file

@ -10,6 +10,7 @@
# - search todo and do
# - podman / docker harvesting
# - adjust device icon based on guest type
# - nixos-container extractor
{
config,
lib,
@ -116,8 +117,7 @@
*/
''
<div tw="flex flex-row items-center my-2">
<div tw="flex flex-row flex-none bg-[${color}] w-4 h-1"></div>
<div tw="flex flex-row flex-none items-center bg-[${color}] text-[#101419] rounded-lg px-2 py-1 w-46 h-8 mr-4">
<div tw="flex flex-row flex-none items-center bg-[${color}] text-[#101419] rounded-lg px-2 py-1 w-46 h-8 mx-4">
${mkImage "w-6 h-6 mr-2" (config.lib.icons.get interface.icon)}
<span tw="font-bold">${interface.id}</span>
</div>
@ -141,7 +141,11 @@
# FIXME: order not respected
+ concatLines ((map serviceDetail) (attrValues service.details));
mkService = service:
mkService = {
additionalInfo ? "",
includeDetails ? true,
...
}: service:
/*
html
*/
@ -152,9 +156,10 @@
<div tw="flex flex-col grow">
<h1 tw="text-lg font-bold m-0">${service.name}</h1>
${optionalString (service.info != "") ''<p tw="text-sm m-0">${service.info}</p>''}
${additionalInfo}
</div>
</div>
${serviceDetails service}
${optionalString includeDetails (serviceDetails service)}
</div>
'';
@ -223,7 +228,7 @@
${concatLines (map mkGuest guests)}
${optionalString (guests != []) spacingMt2}
${concatLines (map mkService services)}
${concatLines (map (mkService {}) services)}
${optionalString (services != []) spacingMt2}
${mkImageMaybe "w-full h-24" node.hardware.image}
@ -240,12 +245,12 @@
*/
''
<div tw="flex flex-row mx-6 mt-2 items-center">
${mkImageMaybe "w-12 h-12" (config.lib.icons.get node.icon)}
${mkImageMaybe "w-8 h-8" (config.lib.icons.get node.icon)}
<h2 tw="text-2xl 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 tw="flex grow min-w-4"></div>
${mkImageMaybe "w-12 h-12" deviceIconImage}
''}
</div>
@ -261,6 +266,36 @@
)
node;
};
services.mkOverview = {
width = 480;
html =
mkCardContainer
/*
html
*/
''
<div tw="flex flex-row mx-6 mt-2 items-center">
<h2 tw="text-2xl font-bold">Services Overview</h2>
</div>
${concatLines (flip map (attrValues config.nodes) (
node: let
services = filter (x: !x.hidden) (attrValues node.services);
in
concatLines (
flip map services (
html.node.mkService {
additionalInfo = ''<p tw="text-sm text-[#7a899f] m-0">${node.name}</p>'';
includeDetails = false;
}
)
)
))}
${spacingMt2}
'';
};
};
in {
options.renderers.svg = {
@ -274,11 +309,15 @@ in {
};
config = {
lib.renderers.svg.node = {
lib.renderers.svg = {
services.mkOverview = renderHtmlToSvg html.services.mkOverview "services-overview";
node = {
mkNetCard = node: renderHtmlToSvg (html.node.mkNetCard node) "card-network-${node.id}";
mkCard = node: renderHtmlToSvg (html.node.mkCard node) "card-node-${node.id}";
mkPreferredRender = node: renderHtmlToSvg (html.node.mkPreferredRender node) "preferred-render-node-${node.id}";
};
};
renderers.svg.output = pkgs.runCommand "topology-svgs" {} ''
mkdir -p $out/nodes