mirror of
https://github.com/oddlama/nix-config.git
synced 2025-10-10 14:50:40 +02:00
feat(topology): add services overview card
This commit is contained in:
parent
07191bac9b
commit
b822b4e812
8 changed files with 177 additions and 67 deletions
29
topology/nixos/extractors/microvm.nix
Normal file
29
topology/nixos/extractors/microvm.nix
Normal 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;
|
||||
};
|
||||
}
|
||||
));
|
||||
};
|
||||
}
|
|
@ -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)}";
|
||||
|
|
|
@ -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";
|
||||
})
|
||||
]);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
}
|
||||
]
|
||||
|
|
|
@ -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,10 +309,14 @@ in {
|
|||
};
|
||||
|
||||
config = {
|
||||
lib.renderers.svg.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}";
|
||||
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" {} ''
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue