mirror of
https://github.com/oddlama/nix-config.git
synced 2025-10-10 14:50:40 +02:00
feat(topology): add network-centric view and port labels
This commit is contained in:
parent
f24fd89ae5
commit
ecaea9b906
6 changed files with 183 additions and 61 deletions
|
@ -60,6 +60,7 @@ in {
|
|||
optional (interfaceName != null) {
|
||||
${interfaceName} = {
|
||||
mac = network.matchConfig.MACAddress or null;
|
||||
# TODO: FIXME: remove cidr mask
|
||||
addresses = network.address ++ (network.networkConfig.Address or []);
|
||||
gateways = network.gateway ++ (network.networkConfig.Gateway or []);
|
||||
};
|
||||
|
|
|
@ -35,6 +35,7 @@ in {
|
|||
in {
|
||||
${networkId wgName} = {
|
||||
name = mkDefault "Wireguard network '${wgName}'";
|
||||
icon = "interfaces.wireguard";
|
||||
cidrv4 = headOrNull (filter lib.net.ip.isv4 networkCidrs);
|
||||
cidrv6 = headOrNull (filter lib.net.ip.isv6 networkCidrs);
|
||||
};
|
||||
|
|
|
@ -5,6 +5,9 @@ f: {
|
|||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
attrValues
|
||||
flatten
|
||||
flip
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
|
@ -28,6 +31,12 @@ in
|
|||
default = "Unnamed network '${networkSubmod.config.id}'";
|
||||
};
|
||||
|
||||
icon = mkOption {
|
||||
description = "The icon representing this network. Must be a path to an image or a valid icon name (<category>.<name>).";
|
||||
type = types.nullOr (types.either types.path types.str);
|
||||
default = null;
|
||||
};
|
||||
|
||||
color = mkOption {
|
||||
description = "The color of this network";
|
||||
default = "random";
|
||||
|
@ -53,4 +62,15 @@ in
|
|||
};
|
||||
}));
|
||||
};
|
||||
|
||||
config = {
|
||||
assertions = flatten (
|
||||
flip map (attrValues config.networks) (
|
||||
network: [
|
||||
(config.lib.assertions.iconValid
|
||||
network.icon "networks.${network.id}.icon")
|
||||
]
|
||||
)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -42,8 +42,8 @@ in
|
|||
|
||||
hardware = {
|
||||
description = mkOption {
|
||||
description = "A description of this node's hardware. Usually the device name or lost of the most important components.";
|
||||
type = types.lines;
|
||||
description = "A description of this node's hardware. Usually the model name or a description the most important components.";
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
|
||||
|
|
|
@ -55,74 +55,145 @@
|
|||
else value
|
||||
);
|
||||
|
||||
netToElk = net: {
|
||||
children."net:${net.id}" = {
|
||||
width = 50;
|
||||
height = 50;
|
||||
};
|
||||
mkEdge = from: to: extra: {
|
||||
edges."${from}__${to}" =
|
||||
{
|
||||
sources = [from];
|
||||
targets = [to];
|
||||
}
|
||||
// extra;
|
||||
};
|
||||
|
||||
idForInterface = node: interfaceId:
|
||||
if (node.preferredRenderType == "card")
|
||||
then "children.node:${node.id}.ports.interface:${interfaceId}"
|
||||
else "children.node:${node.id}";
|
||||
mkLabel = text: scale: extraStyle: {
|
||||
height = scale * 12;
|
||||
width = scale * 7.3 * (stringLength text);
|
||||
inherit text;
|
||||
style =
|
||||
{
|
||||
style = "font: ${toString (scale * 12)}px JetBrains Mono;";
|
||||
}
|
||||
// extraStyle;
|
||||
};
|
||||
|
||||
netToElk = net: [
|
||||
{
|
||||
children.network.children."net:${net.id}" = {
|
||||
svg = {
|
||||
file = config.lib.renderers.svg.net.mkCard net;
|
||||
scale = 0.8;
|
||||
};
|
||||
properties."portLabels.placement" = "OUTSIDE";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
idForInterface = node: interfaceId: "children.node:${node.id}.ports.interface:${interfaceId}";
|
||||
|
||||
nodeInterfaceToElk = node: interface:
|
||||
[
|
||||
(optionalAttrs (node.preferredRenderType == "card") {
|
||||
# Interface for node in main view
|
||||
{
|
||||
children."node:${node.id}".ports."interface:${interface.id}" = {
|
||||
properties."port.side" = "WEST";
|
||||
properties = optionalAttrs (node.preferredRenderType == "card") {
|
||||
"port.side" = "WEST";
|
||||
};
|
||||
width = 8;
|
||||
height = 8;
|
||||
style.stroke = "#70a5eb";
|
||||
style.fill = "#74bee9";
|
||||
labels.name = {
|
||||
height = 12;
|
||||
width = 7.5 * (stringLength interface.id);
|
||||
text = interface.id;
|
||||
};
|
||||
labels =
|
||||
{
|
||||
"00-name" = mkLabel interface.id 1 {};
|
||||
}
|
||||
// optionalAttrs (interface.mac != null) {
|
||||
"50-mac" = mkLabel interface.mac 1 {fill = "#70a5eb";};
|
||||
};
|
||||
};
|
||||
})
|
||||
}
|
||||
# Interface for node in network-centric view
|
||||
{
|
||||
children.network.children."node:${node.id}".ports."interface:${interface.id}" = {
|
||||
width = 8;
|
||||
height = 8;
|
||||
style.stroke = "#70a5eb";
|
||||
style.fill = "#74bee9";
|
||||
labels =
|
||||
{
|
||||
"00-name" = mkLabel interface.id 1 {};
|
||||
}
|
||||
// optionalAttrs (interface.mac != null) {
|
||||
"50-mac" = mkLabel interface.mac 1 {fill = "#70a5eb";};
|
||||
}
|
||||
// optionalAttrs (interface.addresses != []) {
|
||||
"60-addrs" = mkLabel (toString interface.addresses) 1 {fill = "#f9a872";};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
# Edge in network-centric view
|
||||
(optionalAttrs (interface.network != null) (
|
||||
mkEdge ("children.network." + idForInterface node interface.id) "children.network.children.net:${interface.network}" {}
|
||||
))
|
||||
]
|
||||
++ 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 = [(idForInterface node interface.id)];
|
||||
targets = [(idForInterface config.nodes.${x.node} x.interface)];
|
||||
};
|
||||
}));
|
||||
++ optionals (!interface.virtual) (flip map interface.physicalConnections (
|
||||
conn:
|
||||
optionalAttrs (
|
||||
(!any (y: y.node == node.id && y.interface == interface.id) config.nodes.${conn.node}.interfaces.${conn.interface}.physicalConnections)
|
||||
|| (node.id < conn.node)
|
||||
) (
|
||||
# Edge in main view
|
||||
mkEdge
|
||||
(idForInterface node interface.id)
|
||||
(idForInterface config.nodes.${conn.node} conn.interface)
|
||||
{}
|
||||
)
|
||||
));
|
||||
|
||||
nodeToElk = node:
|
||||
[
|
||||
# Add node to main view
|
||||
{
|
||||
children."node:${node.id}" = {
|
||||
svg = {
|
||||
file = config.lib.renderers.svg.node.mkPreferredRender node;
|
||||
scale = 0.8;
|
||||
};
|
||||
properties."portConstraints" = "FIXED_SIDE";
|
||||
properties =
|
||||
{
|
||||
"portLabels.placement" = "OUTSIDE";
|
||||
}
|
||||
// optionalAttrs (node.preferredRenderType == "card") {
|
||||
"portConstraints" = "FIXED_SIDE";
|
||||
};
|
||||
};
|
||||
}
|
||||
# Add node to network-centric view
|
||||
{
|
||||
children.network.children."node:${node.id}" = {
|
||||
svg = {
|
||||
file = config.lib.renderers.svg.node.mkImageWithName node;
|
||||
scale = 0.8;
|
||||
};
|
||||
properties."portLabels.placement" = "OUTSIDE";
|
||||
};
|
||||
}
|
||||
]
|
||||
++ optional (node.parent != null) {
|
||||
children."node:${node.parent}".ports.guests = {
|
||||
properties."port.side" = "EAST";
|
||||
width = 8;
|
||||
height = 8;
|
||||
style.stroke = "#49d18d";
|
||||
style.fill = "#78dba9";
|
||||
};
|
||||
edges."node:${node.parent}.ports.guests-to-node:${node.id}" = {
|
||||
sources = ["children.node:${node.parent}.ports.guests"];
|
||||
targets = ["children.node:${node.id}"];
|
||||
++ optional (node.parent != null) (
|
||||
{
|
||||
children."node:${node.parent}".ports.guests = {
|
||||
properties."port.side" = "EAST";
|
||||
width = 8;
|
||||
height = 8;
|
||||
style.stroke = "#49d18d";
|
||||
style.fill = "#78dba9";
|
||||
labels."00-name" = mkLabel "guests" 1 {};
|
||||
};
|
||||
}
|
||||
// mkEdge "children.node:${node.parent}.ports.guests" "children.node:${node.id}" {
|
||||
style.stroke-dasharray = "10,8";
|
||||
style.stroke-linecap = "round";
|
||||
};
|
||||
}
|
||||
}
|
||||
)
|
||||
++ map (nodeInterfaceToElk node) (attrValues node.interfaces);
|
||||
in {
|
||||
options.renderers.elk = {
|
||||
|
@ -151,6 +222,19 @@ in {
|
|||
};
|
||||
}
|
||||
|
||||
# Add network-centric section
|
||||
{
|
||||
children.network = {
|
||||
style = {
|
||||
stroke = "#101419";
|
||||
stroke-width = 2;
|
||||
fill = "#080a0d";
|
||||
rx = 12;
|
||||
};
|
||||
labels."00-name" = mkLabel "Network View" 1 {};
|
||||
};
|
||||
}
|
||||
|
||||
# Add service overview
|
||||
{
|
||||
children.services-overview = {
|
||||
|
|
|
@ -1,4 +1,13 @@
|
|||
# TODO:
|
||||
# - systemd extractor remove cidr mask
|
||||
# - address port label render make newline capable (multiple port labels)
|
||||
# - mac address show!
|
||||
# - split network layout or make rectpacking of childs
|
||||
# - NAT indication
|
||||
# - bottom hw image distorted in card view (move to top anyway)
|
||||
# - embed font
|
||||
# - network overview card (list all networks with name and cidr, legend style)
|
||||
# - colors!
|
||||
# - ip labels on edges
|
||||
# - network centric view
|
||||
# - better layout for interfaces in svg
|
||||
|
@ -106,6 +115,28 @@
|
|||
<div tw="flex mt-2"></div>
|
||||
'';
|
||||
|
||||
net = rec {
|
||||
mkCard = net: {
|
||||
width = 480;
|
||||
html =
|
||||
mkCardContainer
|
||||
/*
|
||||
html
|
||||
*/
|
||||
''
|
||||
<div tw="flex flex-row mx-6 mt-2 items-center">
|
||||
${mkImageMaybe "w-8 h-8 mr-4" (config.lib.icons.get net.icon)}
|
||||
<h2 tw="text-2xl font-bold">${net.name}</h2>
|
||||
<div tw="flex grow min-w-8"></div>
|
||||
<div tw="flex flex-none bg-[#ff0000] w-12 h-12 ml-4 rounded-lg"></div>
|
||||
</div>
|
||||
<div tw="flex flex-col mx-6 my-2 grow">
|
||||
${optionalString (net.cidrv4 != null) ''<div tw="flex flex-row"><span tw="text-lg m-0"><b>CIDRv4</b></span><span tw="text-lg m-0 ml-4">${net.cidrv4}</span></div>''}
|
||||
${optionalString (net.cidrv6 != null) ''<div tw="flex flex-row"><span tw="text-lg m-0"><b>CIDRv6</b></span><span tw="text-lg m-0 ml-4">${net.cidrv6}</span></div>''}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
node = rec {
|
||||
mkInterface = interface: let
|
||||
color =
|
||||
|
@ -193,23 +224,6 @@
|
|||
</div>
|
||||
'';
|
||||
|
||||
mkNetCard = node: {
|
||||
width = 480;
|
||||
html =
|
||||
mkCardContainer
|
||||
/*
|
||||
html
|
||||
*/
|
||||
''
|
||||
${mkTitle node}
|
||||
|
||||
${concatLines (map mkInterface (attrValues node.interfaces))}
|
||||
${optionalString (node.interfaces != {}) spacingMt2}
|
||||
|
||||
${mkImageMaybe "w-full h-24" node.hardware.image}
|
||||
'';
|
||||
};
|
||||
|
||||
mkCard = node: let
|
||||
services = filter (x: !x.hidden) (attrValues node.services);
|
||||
guests = filter (x: x.parent == node.id) (attrValues config.nodes);
|
||||
|
@ -314,8 +328,10 @@ in {
|
|||
# FIXME: networks.mkOverview = renderHtmlToSvg html.networks.mkOverview "networks-overview";
|
||||
services.mkOverview = renderHtmlToSvg html.services.mkOverview "services-overview";
|
||||
|
||||
net.mkCard = net: renderHtmlToSvg (html.net.mkCard net) "card-net-${net.id}";
|
||||
|
||||
node = {
|
||||
mkNetCard = node: renderHtmlToSvg (html.node.mkNetCard node) "card-network-${node.id}";
|
||||
mkImageWithName = node: renderHtmlToSvg (html.node.mkImageWithName node) "image-with-name-${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}";
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue