mirror of
https://github.com/oddlama/nix-config.git
synced 2025-10-10 23:00:39 +02:00
feat(topology): implement nixos-extra-modules wireguard extractor
This commit is contained in:
parent
b20376f2e4
commit
65890181e9
12 changed files with 418 additions and 77 deletions
18
topology/nixos/extractors/services.nix
Normal file
18
topology/nixos/extractors/services.nix
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit
|
||||||
|
(lib)
|
||||||
|
mkIf
|
||||||
|
;
|
||||||
|
in {
|
||||||
|
topology.self.services = {
|
||||||
|
vaultwarden = mkIf config.services.vaultwarden.enable {
|
||||||
|
name = "Vaultwarden";
|
||||||
|
icon = "${pkgs.vaultwarden.webvault}/share/vaultwarden/vault/images/safari-pinned-tab.svg";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,2 +1,47 @@
|
||||||
{
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit
|
||||||
|
(lib)
|
||||||
|
concatLists
|
||||||
|
flip
|
||||||
|
mkDefault
|
||||||
|
mkIf
|
||||||
|
mkMerge
|
||||||
|
optional
|
||||||
|
;
|
||||||
|
in {
|
||||||
|
#config = mkIf config.systemd.network.enable {
|
||||||
|
# topology.interfaces = mkMerge (
|
||||||
|
# # Create interfaces based on systemd.network.netdevs
|
||||||
|
# concatLists (
|
||||||
|
# flip mapAttrsToList config.systemd.network.netdevs (
|
||||||
|
# _unit: netdev:
|
||||||
|
# optional (netdev ? netdevConfig.Name) {
|
||||||
|
# ${netdev.netdevConfig.Name} = {
|
||||||
|
# physical = mkDefault false;
|
||||||
|
# };
|
||||||
|
# }
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# # Add interface configuration based on systemd.network.networks
|
||||||
|
# #++ concatLists (
|
||||||
|
# # flip mapAttrsToList config.systemd.network.networks (
|
||||||
|
# # _unit: network:
|
||||||
|
# # optional (network ? matchConfig.Name) {
|
||||||
|
# # ${network.networkConfig.Name} = {
|
||||||
|
# # };
|
||||||
|
# # }
|
||||||
|
# # )
|
||||||
|
# #)
|
||||||
|
# );
|
||||||
|
|
||||||
|
# #self.interfaces = {
|
||||||
|
# #};
|
||||||
|
# #networks.somenet = {
|
||||||
|
# # connections = [];
|
||||||
|
# #};
|
||||||
|
#};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,84 @@
|
||||||
{
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
inputs ? {},
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit
|
||||||
|
(lib)
|
||||||
|
flip
|
||||||
|
mapAttrsToList
|
||||||
|
mkDefault
|
||||||
|
mkIf
|
||||||
|
mkMerge
|
||||||
|
filter
|
||||||
|
optionals
|
||||||
|
;
|
||||||
|
|
||||||
|
headOrNull = xs:
|
||||||
|
if xs == []
|
||||||
|
then null
|
||||||
|
else builtins.head xs;
|
||||||
|
|
||||||
|
networkId = wgName: "wireguard-${wgName}";
|
||||||
|
in {
|
||||||
|
config = mkIf (config ? wireguard) {
|
||||||
|
# Create networks (this will be duplicated by each node,
|
||||||
|
# but it doesn't matter and will be merged anyway)
|
||||||
|
topology.networks = mkMerge (
|
||||||
|
flip mapAttrsToList config.wireguard (
|
||||||
|
wgName: _: let
|
||||||
|
inherit (lib.wireguard inputs wgName) networkCidrs;
|
||||||
|
in {
|
||||||
|
${networkId wgName} = {
|
||||||
|
name = mkDefault "Wireguard network '${wgName}'";
|
||||||
|
cidrv4 = headOrNull (filter lib.net.ip.isv4 networkCidrs);
|
||||||
|
cidrv6 = headOrNull (filter lib.net.ip.isv6 networkCidrs);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
# Assign network and physical connections to related interfaces
|
||||||
|
topology.self.interfaces = mkMerge (
|
||||||
|
flip mapAttrsToList config.wireguard (
|
||||||
|
wgName: wgCfg: let
|
||||||
|
inherit
|
||||||
|
(lib.wireguard inputs wgName)
|
||||||
|
participatingClientNodes
|
||||||
|
participatingServerNodes
|
||||||
|
wgCfgOf
|
||||||
|
;
|
||||||
|
|
||||||
|
isServer = wgCfg.server.host != null;
|
||||||
|
filterSelf = filter (x: x != config.node.name);
|
||||||
|
|
||||||
|
# All nodes that use our node as the via into the wireguard network
|
||||||
|
ourClientNodes =
|
||||||
|
optionals isServer
|
||||||
|
(filter (n: (wgCfgOf n).client.via == config.node.name) participatingClientNodes);
|
||||||
|
|
||||||
|
# The list of peers that are "physically" connected in the wireguard network,
|
||||||
|
# meaning they communicate directly with each other.
|
||||||
|
connectedPeers =
|
||||||
|
if isServer
|
||||||
|
then
|
||||||
|
# Other servers in the same network
|
||||||
|
filterSelf participatingServerNodes
|
||||||
|
# Our clients
|
||||||
|
++ ourClientNodes
|
||||||
|
else [wgCfg.client.via];
|
||||||
|
in {
|
||||||
|
${wgCfg.linkName} = {
|
||||||
|
network = networkId wgName;
|
||||||
|
virtual = true;
|
||||||
|
physicalConnections = flip map connectedPeers (peer: {
|
||||||
|
node = peer;
|
||||||
|
interface = (wgCfgOf peer).linkName;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,9 @@ in {
|
||||||
# Allow simple alias to set/get attributes of this node
|
# Allow simple alias to set/get attributes of this node
|
||||||
(mkAliasOptionModule ["topology" "self"] ["topology" "nodes" config.topology.id])
|
(mkAliasOptionModule ["topology" "self"] ["topology" "nodes" config.topology.id])
|
||||||
]
|
]
|
||||||
|
# Include extractors
|
||||||
|
++ map (x: ./extractors/${x}) (attrNames (builtins.readDir ./extractors))
|
||||||
|
# Include common topology options
|
||||||
++ flip map (attrNames (builtins.readDir ../options)) (x:
|
++ flip map (attrNames (builtins.readDir ../options)) (x:
|
||||||
import ../options/${x} (
|
import ../options/${x} (
|
||||||
module:
|
module:
|
||||||
|
@ -48,49 +51,4 @@ in {
|
||||||
# Ensure a node exists for this host
|
# Ensure a node exists for this host
|
||||||
nodes.${config.topology.id} = {};
|
nodes.${config.topology.id} = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
#config.topology = mkMerge [
|
|
||||||
# {
|
|
||||||
# ################### TODO user config! #################
|
|
||||||
# id = config.node.name;
|
|
||||||
# ################### END user config #################
|
|
||||||
|
|
||||||
# guests =
|
|
||||||
# flip mapAttrsToList (config.microvm.vms or {})
|
|
||||||
# (_: vmCfg: vmCfg.config.config.topology.id);
|
|
||||||
# # TODO: container
|
|
||||||
|
|
||||||
# disks =
|
|
||||||
# flip mapAttrs (config.disko.devices.disk or {})
|
|
||||||
# (_: _: {});
|
|
||||||
# # TODO: zfs pools from disko / fileSystems
|
|
||||||
# # TODO: microvm shares
|
|
||||||
# # TODO: container shares
|
|
||||||
# # TODO: OCI containers shares
|
|
||||||
|
|
||||||
# interfaces = let
|
|
||||||
# isNetwork = netDef: (netDef.matchConfig != {}) && (netDef.address != [] || netDef.DHCP != null);
|
|
||||||
# macsByName = mapAttrs' (flip nameValuePair) (config.networking.renameInterfacesByMac or {});
|
|
||||||
# netNameFor = netName: netDef:
|
|
||||||
# netDef.matchConfig.Name
|
|
||||||
# or (
|
|
||||||
# if netDef ? matchConfig.MACAddress && macsByName ? ${netDef.matchConfig.MACAddress}
|
|
||||||
# then macsByName.${netDef.matchConfig.MACAddress}
|
|
||||||
# else lib.trace "Could not derive network name for systemd network ${netName} on host ${config.node.name}, using unit name as fallback." netName
|
|
||||||
# );
|
|
||||||
# netMACFor = netDef: netDef.matchConfig.MACAddress or null;
|
|
||||||
# networks = filterAttrs (_: isNetwork) (config.systemd.network.networks or {});
|
|
||||||
# in
|
|
||||||
# flip mapAttrs' networks (netName: netDef:
|
|
||||||
# nameValuePair (netNameFor netName netDef) {
|
|
||||||
# mac = netMACFor netDef;
|
|
||||||
# addresses =
|
|
||||||
# if netDef.address != []
|
|
||||||
# then netDef.address
|
|
||||||
# else ["DHCP"];
|
|
||||||
# });
|
|
||||||
|
|
||||||
# # TODO: for each nftable zone show open ports
|
|
||||||
# }
|
|
||||||
#];
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@ in
|
||||||
default = {};
|
default = {};
|
||||||
type = types.attrsOf (types.submodule (submod: {
|
type = types.attrsOf (types.submodule (submod: {
|
||||||
options = {
|
options = {
|
||||||
name = mkOption {
|
id = mkOption {
|
||||||
description = "The name of this disk";
|
description = "The id of this disk";
|
||||||
default = submod.config._module.args.name;
|
default = submod.config._module.args.name;
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
type = types.str;
|
type = types.str;
|
||||||
|
|
|
@ -18,8 +18,8 @@ in
|
||||||
default = {};
|
default = {};
|
||||||
type = types.attrsOf (types.submodule (submod: {
|
type = types.attrsOf (types.submodule (submod: {
|
||||||
options = {
|
options = {
|
||||||
name = mkOption {
|
id = mkOption {
|
||||||
description = "The name of this firewall rule";
|
description = "The id of this firewall rule";
|
||||||
type = types.str;
|
type = types.str;
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
default = submod.config._module.args.name;
|
default = submod.config._module.args.name;
|
||||||
|
|
|
@ -5,6 +5,9 @@ f: {
|
||||||
}: let
|
}: let
|
||||||
inherit
|
inherit
|
||||||
(lib)
|
(lib)
|
||||||
|
attrValues
|
||||||
|
flatten
|
||||||
|
flip
|
||||||
mkOption
|
mkOption
|
||||||
types
|
types
|
||||||
;
|
;
|
||||||
|
@ -18,36 +21,83 @@ in
|
||||||
default = {};
|
default = {};
|
||||||
type = types.attrsOf (types.submodule (submod: {
|
type = types.attrsOf (types.submodule (submod: {
|
||||||
options = {
|
options = {
|
||||||
name = mkOption {
|
id = mkOption {
|
||||||
description = "The name of this interface";
|
description = "The id of this interface";
|
||||||
type = types.str;
|
type = types.str;
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
default = submod.config._module.args.name;
|
default = submod.config._module.args.name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
virtual = mkOption {
|
||||||
|
description = "Whether this is a virtual interface.";
|
||||||
|
type = types.bool;
|
||||||
|
};
|
||||||
|
|
||||||
mac = mkOption {
|
mac = mkOption {
|
||||||
description = "The MAC address of this interface, if known.";
|
description = "The MAC address of this interface, if known.";
|
||||||
default = null;
|
default = null;
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
};
|
};
|
||||||
|
|
||||||
addresses = mkOption {
|
#addresses = mkOption {
|
||||||
description = "The configured address(es), or a descriptive string (like DHCP).";
|
# description = "The configured address(es), or a descriptive string (like DHCP).";
|
||||||
type = types.listOf types.str;
|
# type = types.listOf types.str;
|
||||||
};
|
#};
|
||||||
|
|
||||||
|
#gateway = mkOption {
|
||||||
|
# description = "The configured gateway, if any";
|
||||||
|
# type = types.nullOr types.str;
|
||||||
|
# default = null;
|
||||||
|
#};
|
||||||
|
|
||||||
network = mkOption {
|
network = mkOption {
|
||||||
description = ''
|
description = "The id of the network to which this interface belongs, if any.";
|
||||||
The global name of the attached/spanned network.
|
|
||||||
If this is given, this interface can be shown in the network graph.
|
|
||||||
'';
|
|
||||||
default = null;
|
default = null;
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
physicalConnections = mkOption {
|
||||||
|
description = "A list of other node interfaces to which this node is physically connected.";
|
||||||
|
default = [];
|
||||||
|
type = types.listOf (types.submodule {
|
||||||
|
options = {
|
||||||
|
node = mkOption {
|
||||||
|
description = "The other node id.";
|
||||||
|
type = types.str;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface = mkOption {
|
||||||
|
description = "The other node's interface id.";
|
||||||
|
type = types.str;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
assertions = flatten (flip map (attrValues config.nodes) (
|
||||||
|
node:
|
||||||
|
flip map (attrValues node.interfaces) (
|
||||||
|
interface:
|
||||||
|
[
|
||||||
|
{
|
||||||
|
assertion = config.networks ? ${interface.network};
|
||||||
|
message = "topology: nodes.${node.id}.interfaces.${interface.id} refers to an unknown network '${interface.network}'";
|
||||||
|
}
|
||||||
|
]
|
||||||
|
++ flip map interface.physicalConnections (
|
||||||
|
physicalConnection: {
|
||||||
|
assertion = config.nodes ? ${physicalConnection.node} && config.nodes.${physicalConnection.node}.interfaces ? ${physicalConnection.interface};
|
||||||
|
message = "topology: nodes.${node.id}.interfaces.${interface.id}.physicalConnections refers to an unknown node/interface nodes.${physicalConnection.node}.interfaces.${physicalConnection.interface}";
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
57
topology/options/networks.nix
Normal file
57
topology/options/networks.nix
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
f: {
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit
|
||||||
|
(lib)
|
||||||
|
mkOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
in
|
||||||
|
f {
|
||||||
|
options.networks = mkOption {
|
||||||
|
default = {};
|
||||||
|
description = ''
|
||||||
|
'';
|
||||||
|
type = types.attrsOf (types.submodule (networkSubmod: {
|
||||||
|
options = {
|
||||||
|
id = mkOption {
|
||||||
|
description = "The id of this network";
|
||||||
|
default = networkSubmod.config._module.args.name;
|
||||||
|
readOnly = true;
|
||||||
|
type = types.str;
|
||||||
|
};
|
||||||
|
|
||||||
|
name = mkOption {
|
||||||
|
description = "The name of this network";
|
||||||
|
type = types.str;
|
||||||
|
default = "Unnamed network '${networkSubmod.config.id}'";
|
||||||
|
};
|
||||||
|
|
||||||
|
color = mkOption {
|
||||||
|
description = "The color of this network";
|
||||||
|
default = "random";
|
||||||
|
type = types.either (types.strMatching "^#[0-9a-f]{6}$") (types.enum ["random"]);
|
||||||
|
};
|
||||||
|
|
||||||
|
cidrv4 = mkOption {
|
||||||
|
description = "The CIDRv4 address space of this network or null if it doesn't use ipv4";
|
||||||
|
default = null;
|
||||||
|
#type = types.nullOr types.net.cidrv4;
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
};
|
||||||
|
|
||||||
|
cidrv6 = mkOption {
|
||||||
|
description = "The CIDRv6 address space of this network or null if it doesn't use ipv6";
|
||||||
|
default = null;
|
||||||
|
#type = types.nullOr types.net.cidrv6;
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
};
|
||||||
|
|
||||||
|
# FIXME: vlan ids
|
||||||
|
# FIXME: nat to [other networks] (happening on node XY)
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ f: {
|
||||||
}: let
|
}: let
|
||||||
inherit
|
inherit
|
||||||
(lib)
|
(lib)
|
||||||
|
literalExpression
|
||||||
mkOption
|
mkOption
|
||||||
types
|
types
|
||||||
;
|
;
|
||||||
|
@ -16,17 +17,28 @@ in
|
||||||
'';
|
'';
|
||||||
type = types.attrsOf (types.submodule (nodeSubmod: {
|
type = types.attrsOf (types.submodule (nodeSubmod: {
|
||||||
options = {
|
options = {
|
||||||
name = mkOption {
|
id = mkOption {
|
||||||
description = "The name of this node";
|
description = "The id of this node";
|
||||||
default = nodeSubmod.config._module.args.name;
|
default = nodeSubmod.config._module.args.name;
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
type = types.str;
|
type = types.str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
name = mkOption {
|
||||||
|
description = "The name of this node";
|
||||||
|
type = types.str;
|
||||||
|
default = nodeSubmod.config.id;
|
||||||
|
defaultText = literalExpression ''"<name>"'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# FIXME: TODO emoji / icon
|
||||||
|
# FIXME: TODO hardware description "Odroid H3"
|
||||||
|
# FIXME: TODO hardware image
|
||||||
|
|
||||||
|
# FIXME: TODO are these good types? how about nixos vs router vs ...
|
||||||
type = mkOption {
|
type = mkOption {
|
||||||
description = "TODO";
|
description = "TODO";
|
||||||
default = "normal";
|
type = types.enum ["nixos" "microvm" "nixos-container"];
|
||||||
type = types.enum ["normal" "microvm" "nixos-container"];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
parent = mkOption {
|
parent = mkOption {
|
||||||
|
|
56
topology/options/services.nix
Normal file
56
topology/options/services.nix
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
f: {
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit
|
||||||
|
(lib)
|
||||||
|
mkOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
in
|
||||||
|
f {
|
||||||
|
options.nodes = mkOption {
|
||||||
|
type = types.attrsOf (types.submodule {
|
||||||
|
options = {
|
||||||
|
services = mkOption {
|
||||||
|
description = "TODO";
|
||||||
|
default = {};
|
||||||
|
type = types.attrsOf (types.submodule (submod: {
|
||||||
|
options = {
|
||||||
|
id = mkOption {
|
||||||
|
description = "The id of this service";
|
||||||
|
type = types.str;
|
||||||
|
readOnly = true;
|
||||||
|
default = submod.config._module.args.name;
|
||||||
|
};
|
||||||
|
|
||||||
|
name = mkOption {
|
||||||
|
description = "The name of this service";
|
||||||
|
type = types.str;
|
||||||
|
};
|
||||||
|
|
||||||
|
icon = mkOption {
|
||||||
|
description = "The icon for this service";
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
url = mkOption {
|
||||||
|
description = "The URL under which the service is reachable, if any.";
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
listenAddresses = mkOption {
|
||||||
|
description = "The addresses on which this service listens.";
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
|
@ -7,6 +7,8 @@
|
||||||
(lib)
|
(lib)
|
||||||
attrNames
|
attrNames
|
||||||
concatLists
|
concatLists
|
||||||
|
concatStringsSep
|
||||||
|
filter
|
||||||
filterAttrs
|
filterAttrs
|
||||||
flip
|
flip
|
||||||
getAttrFromPath
|
getAttrFromPath
|
||||||
|
@ -54,6 +56,35 @@ in {
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
defaultText = literalExpression ''config.renderers.${config.renderer}.output'';
|
defaultText = literalExpression ''config.renderers.${config.renderer}.output'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
assertions = mkOption {
|
||||||
|
internal = true;
|
||||||
|
default = [];
|
||||||
|
example = [
|
||||||
|
{
|
||||||
|
assertion = false;
|
||||||
|
message = "you can't enable this for that reason";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
This option allows modules to express conditions that must
|
||||||
|
hold for the evaluation of the topology configuration to
|
||||||
|
succeed, along with associated error messages for the user.
|
||||||
|
'';
|
||||||
|
type = types.listOf (types.submodule {
|
||||||
|
options = {
|
||||||
|
assertion = mkOption {
|
||||||
|
description = "The thing to assert.";
|
||||||
|
type = types.bool;
|
||||||
|
};
|
||||||
|
|
||||||
|
message = mkOption {
|
||||||
|
description = "The error message.";
|
||||||
|
type = types.str;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = let
|
config = let
|
||||||
|
@ -68,10 +99,14 @@ in {
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
in {
|
in {
|
||||||
output =
|
output = let
|
||||||
mkIf (config.renderer != null)
|
failedAssertions = map (x: x.message) (filter (x: !x.assertion) config.assertions);
|
||||||
(mkDefault config.renderers.${config.renderer}.output);
|
in
|
||||||
|
if failedAssertions != []
|
||||||
|
then throw "\nFailed assertions:\n${concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}"
|
||||||
|
else mkIf (config.renderer != null) (mkDefault config.renderers.${config.renderer}.output);
|
||||||
|
|
||||||
nodes = aggregate ["nodes"];
|
nodes = aggregate ["nodes"];
|
||||||
|
networks = aggregate ["networks"];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,25 +6,53 @@
|
||||||
}: let
|
}: let
|
||||||
inherit
|
inherit
|
||||||
(lib)
|
(lib)
|
||||||
|
attrValues
|
||||||
concatLines
|
concatLines
|
||||||
mapAttrsToList
|
|
||||||
;
|
;
|
||||||
|
|
||||||
toD2 = _nodeName: node: ''
|
#toD2 = _nodeName: node: ''
|
||||||
${node.name}: |md
|
# ${node.id}: |md
|
||||||
# ${node.name}
|
# # ${node.id}
|
||||||
|
|
||||||
## Disks:
|
# ## Disks:
|
||||||
${concatLines (mapAttrsToList (_: v: "- ${v.name}") node.disks)}
|
# ${concatLines (mapAttrsToList (_: v: "- ${v.id}") node.disks)}
|
||||||
|
|
||||||
## Interfaces:
|
# ## Interfaces:
|
||||||
${concatLines (mapAttrsToList (_: v: "- ${v.name}, mac ${toString v.mac}, addrs ${toString v.addresses}, network ${toString v.network}") node.interfaces)}
|
# ${concatLines (mapAttrsToList (_: v: "- ${v.id}, mac ${toString v.mac}, addrs ${toString v.addresses}, network ${toString v.network}") node.interfaces)}
|
||||||
|
|
||||||
## Firewall Zones:
|
# ## Firewall Zones:
|
||||||
${concatLines (mapAttrsToList (_: v: "- ${v.name}, mac ${toString v.mac}, addrs ${toString v.addresses}, network ${toString v.network}") node.firewallRules)}
|
# ${concatLines (mapAttrsToList (_: v: "- ${v.id}, mac ${toString v.mac}, addrs ${toString v.addresses}, network ${toString v.network}") node.firewallRules)}
|
||||||
|
|
||||||
|
# ## Services:
|
||||||
|
# ${concatLines (mapAttrsToList (_: v: "- ${v.id}, name ${toString v.name}, icon ${toString v.icon}, url ${toString v.url}") node.services)}
|
||||||
|
# |
|
||||||
|
#'';
|
||||||
|
|
||||||
|
netToD2 = net: ''
|
||||||
|
${net.id}: |md
|
||||||
|
# ${net.name}
|
||||||
|
${net.cidrv4}
|
||||||
|
${net.cidrv6}
|
||||||
|
|
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
nodeInterfaceToD2 = node: interface: ''
|
||||||
|
${node.id}.${interface.id}: |md
|
||||||
|
## ${interface.id}
|
||||||
|
|
|
||||||
|
|
||||||
|
${node.id}.${interface.id} -> ${interface.network}
|
||||||
|
'';
|
||||||
|
|
||||||
|
nodeToD2 = node: ''
|
||||||
|
${node.id}: |md
|
||||||
|
# ${node.name}
|
||||||
|
|
|
||||||
|
|
||||||
|
${concatLines (map (nodeInterfaceToD2 node) (attrValues node.interfaces))}
|
||||||
|
'';
|
||||||
in
|
in
|
||||||
pkgs.writeText "network.d2" ''
|
pkgs.writeText "network.d2" ''
|
||||||
${concatLines (mapAttrsToList toD2 config.nodes)}
|
${concatLines (map netToD2 (attrValues config.networks))}
|
||||||
|
${concatLines (map nodeToD2 (attrValues config.nodes))}
|
||||||
''
|
''
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue