Better addressing?

This commit is contained in:
Yaro Kasear 2026-05-01 13:07:30 -05:00
parent b5c1a43863
commit f35e402b4d
3 changed files with 394 additions and 261 deletions

View file

@ -10,67 +10,48 @@
outputs = { self, nixpkgs, deploy-rs, disko, nixos-anywhere, ... }: outputs = { self, nixpkgs, deploy-rs, disko, nixos-anywhere, ... }:
let let
# Default architecture if a system doesnt override it
defaultSystem = "x86_64-linux"; defaultSystem = "x86_64-linux";
# pkgs per-system so cross-arch doesnt explode later
pkgsFor = system: import nixpkgs { inherit system; }; pkgsFor = system: import nixpkgs { inherit system; };
lib = nixpkgs.lib; lib = nixpkgs.lib;
# World spec & addressing
meta = import ./meta.nix; meta = import ./meta.nix;
addressing = import ./lib/addressing { inherit lib; }; addressing = import ./lib/addressing { inherit lib; };
# Optional for now; meta.systems can be {} until the systems submodule lands
systemsFromMeta = meta.systems or { }; systemsFromMeta = meta.systems or { };
# Precomputed full network view
network = addressing.mkNetworkFromSpec meta; network = addressing.mkNetworkFromSpec meta;
in in
{ {
########################
# Library exports
########################
lib.metanix = { lib.metanix = {
inherit meta addressing network; inherit meta addressing network;
}; };
########################
# NixOS configurations
########################
nixosConfigurations = nixosConfigurations =
lib.mapAttrs lib.mapAttrs
(name: sysCfg: (name: sysCfg:
let let
# System for this host, fallback to default
system = sysCfg.system or defaultSystem; system = sysCfg.system or defaultSystem;
pkgs = pkgsFor system;
in in
lib.nixosSystem { lib.nixosSystem {
inherit system; inherit system;
# Make meta/addressing/world visible to modules
specialArgs = { specialArgs = {
inherit lib pkgs meta addressing system; inherit lib meta addressing system network;
modulesPath = builtins.toString <nixpkgs/nixos/modules>; modulesPath = "${nixpkgs}/nixos/modules";
}; };
modules = modules =
(sysCfg.modules or [ ]) ++ [ (sysCfg.modules or [ ]) ++ [
# Core Metanix wiring
./modules/metanix/core.nix ./modules/metanix/core.nix
./modules/metanix/networkd.nix ./modules/metanix/networkd.nix
# Identity binding: “this box is <name> in Metanix”
{ {
networking.hostName = sysCfg.hostName or name; networking.hostName = sysCfg.hostName or name;
metanix.thisHost = sysCfg.metanixName or name; metanix.thisHost = sysCfg.metanixName or name;
} }
# Optional Disko integration per host
(if sysCfg ? diskoConfig then (if sysCfg ? diskoConfig then
{ {
imports = [ imports = [
@ -84,10 +65,6 @@
}) })
systemsFromMeta; systemsFromMeta;
########################
# deploy-rs
########################
deploy = { deploy = {
nodes = nodes =
lib.mapAttrs lib.mapAttrs
@ -97,7 +74,10 @@
hostInfo = if hasNetworkHost then network.hosts.${name} else null; hostInfo = if hasNetworkHost then network.hosts.${name} else null;
defaultHostname = defaultHostname =
if hasNetworkHost then hostInfo.fqdn else "${name}.${meta.domain}"; if hasNetworkHost && hostInfo ? fqdn then
hostInfo.fqdn
else
name;
in in
{ {
hostname = sysCfg.deployHost or defaultHostname; hostname = sysCfg.deployHost or defaultHostname;
@ -112,12 +92,10 @@
systemsFromMeta; systemsFromMeta;
}; };
checks.${defaultSystem}.deploy = checks =
deploy-rs.lib.${defaultSystem}.deployChecks self.deploy; builtins.mapAttrs
(system: deployLib: deployLib.deployChecks self.deploy)
######################## deploy-rs.lib;
# nixos-anywhere helper
########################
apps.${defaultSystem}.nixos-anywhere = { apps.${defaultSystem}.nixos-anywhere = {
type = "app"; type = "app";

View file

@ -1,4 +1,4 @@
{ lib ? import <nixpkgs/lib> { } }: { lib, ... }:
let let
inherit (lib) inherit (lib)
@ -6,27 +6,26 @@ let
attrNames attrNames
concatMapAttrs concatMapAttrs
concatStringsSep concatStringsSep
filterAttrs
listToAttrs listToAttrs
mapAttrs'
nameValuePair nameValuePair
optionalAttrs optionalAttrs
imap1 imap1
mapAttrs'
imap0 imap0
length length
filter filter
findFirst findFirst
toLower;# toLower
unique;
mkInitials = mkInitials =
name: name:
let let
lower = toLower name; # was builtins.toLower lower = toLower name;
noApos = builtins.replaceStrings [ "'" ] [ " " ] lower; noApos = builtins.replaceStrings [ "'" ] [ " " ] lower;
words = filter (w: w != "") (builtins.split " +" noApos); words = filter (w: w != "") (builtins.split " +" noApos);
letters = letters = concatStringsSep "" (builtins.map (w: builtins.substring 0 1 w) words);
concatStringsSep ""
(builtins.map (w: builtins.substring 0 1 w) words);
in in
if letters == "" then "loc" else builtins.substring 0 3 letters; if letters == "" then "loc" else builtins.substring 0 3 letters;
@ -38,7 +37,7 @@ let
in in
"${base}-${hash}"; "${base}-${hash}";
# Manual elemIndex so we don't care what nixpkgs version you're on # Manual elemIndex so we do not care what nixpkgs version you are on.
elemIndex = elemIndex =
name: list: name: list:
let let
@ -180,9 +179,9 @@ let
mkRoleRangeNamed = mkRoleRangeNamed =
{ location, typeName, roleName }: { location, typeName, roleName }:
let let
_ = assertMsg (subnetTypes ? typeName) _ = assertMsg (builtins.hasAttr typeName subnetTypes)
"metatron-addressing: unknown subnet type '${typeName}'"; "metatron-addressing: unknown subnet type '${typeName}'";
__ = assertMsg (roles ? roleName) __ = assertMsg (builtins.hasAttr roleName roles)
"metatron-addressing: unknown role '${roleName}'"; "metatron-addressing: unknown role '${roleName}'";
type = subnetTypes.${typeName}; type = subnetTypes.${typeName};
@ -193,9 +192,9 @@ let
mkIpNamed = mkIpNamed =
{ location, typeName, roleName, host }: { location, typeName, roleName, host }:
let let
_ = assertMsg (subnetTypes ? typeName) _ = assertMsg (builtins.hasAttr typeName subnetTypes)
"metatron-addressing: unknown subnet type '${typeName}'"; "metatron-addressing: unknown subnet type '${typeName}'";
__ = assertMsg (roles ? roleName) __ = assertMsg (builtins.hasAttr roleName roles)
"metatron-addressing: unknown role '${roleName}'"; "metatron-addressing: unknown role '${roleName}'";
type = subnetTypes.${typeName}; type = subnetTypes.${typeName};
@ -217,7 +216,7 @@ let
mkSubnetNamed = mkSubnetNamed =
{ location, typeName }: { location, typeName }:
let let
_ = assertMsg (subnetTypes ? typeName) _ = assertMsg (builtins.hasAttr typeName subnetTypes)
"metatron-addressing: unknown subnet type '${typeName}'"; "metatron-addressing: unknown subnet type '${typeName}'";
type = subnetTypes.${typeName}; type = subnetTypes.${typeName};
in in
@ -236,18 +235,59 @@ let
mkVlanNamed = mkVlanNamed =
{ location, typeName }: { location, typeName }:
let let
_ = assertMsg (subnetTypes ? typeName) _ = assertMsg (builtins.hasAttr typeName subnetTypes)
"metatron-addressing: unknown subnet type '${typeName}'"; "metatron-addressing: unknown subnet type '${typeName}'";
type = subnetTypes.${typeName}; type = subnetTypes.${typeName};
in in
mkVlan { inherit location type; }; mkVlan { inherit location type; };
# locationName → numeric id (0, 1, 2, …) asList = value:
if value == null then [ ]
else if builtins.isList value then value
else [ value ];
scopeFromCfg = cfg: {
owners =
asList (cfg.owners or null)
++ asList (cfg.owner or null);
admins =
asList (cfg.admins or null)
++ asList (cfg.admin or null);
users = asList (cfg.users or null);
domain = cfg.domain or null;
};
mergeScopes = parent: child:
let
c = scopeFromCfg child;
in
{
owners = unique (parent.owners ++ c.owners);
admins = unique (parent.admins ++ c.admins);
users = unique (parent.users ++ c.users);
domain = if c.domain != null then c.domain else parent.domain;
};
emptyScope = {
owners = [ ];
admins = [ ];
users = [ ];
domain = null;
};
materializeScope = scope:
{
inherit (scope) owners admins users;
}
// optionalAttrs (scope.domain != null) {
inherit (scope) domain;
};
# locationName -> numeric id (0, 1, 2, ...)
locationIdForSpec = locationIdForSpec =
spec: spec:
let let
locations = locations = spec.locations or (throw "metatron-addressing: spec.locations is required");
spec.locations or(throw "metatron-addressing: spec.locations is required");
locationNames = attrNames locations; locationNames = attrNames locations;
in in
name: name:
@ -259,183 +299,197 @@ let
else else
idx; idx;
# Just the host map: { deimos = { ip-address = "..."; fqdn = "..."; ... }; ... } hostRole = path: hostCfg:
hostCfg.role or (throw "metatron-addressing: host '${path}' is missing required field 'role' for address generation");
hostMapForSubnet =
{ loc, locCode, locationName, networkName, typeName, subnetCfg, scope }:
let
hostsForSubnet = subnetCfg.hosts or { };
hostNames = filter (hn: builtins.substring 0 1 hn != "_") (attrNames hostsForSubnet);
subnetSlug =
if builtins.hasAttr typeName subnetSlugs
then subnetSlugs.${typeName}
else typeName;
in
listToAttrs (imap1
(idx: hostName:
let
path = "${locationName}.${networkName}.${typeName}.${hostName}";
hostCfg = hostsForSubnet.${hostName};
hostScope = mergeScopes scope hostCfg;
roleName = hostRole path hostCfg;
# Count how many hosts of this role exist up to and including this one.
roleIndex =
let
prefix = lib.lists.sublist 0 idx hostNames;
in
length (filter
(hn: (hostsForSubnet.${hn}.role or null) == roleName)
prefix);
hostId = hostCfg.hostId or roleIndex;
ip = mkIpNamed {
location = loc;
inherit typeName;
roleName = roleName;
host = hostId;
};
roleSlug =
if builtins.hasAttr roleName roleSlugs
then roleSlugs.${roleName}
else roleName;
hostnameBase = "${roleSlug}-${builtins.toString hostId}";
hostname = hostCfg.hostname or hostnameBase;
in
nameValuePair hostName (
{
ip-address = ip;
inherit hostname;
location = locationName;
network = networkName;
subnetType = typeName;
subnetKey = "${locationName}-${networkName}-${typeName}";
}
// optionalAttrs (hostScope.domain != null) {
fqdn = "${hostname}.${subnetSlug}.${locCode}.${hostScope.domain}";
}
// materializeScope hostScope
// optionalAttrs (hostCfg ? hw-address) {
inherit (hostCfg) hw-address;
}
// optionalAttrs (hostCfg ? dns) {
inherit (hostCfg) dns;
}
// optionalAttrs (hostCfg ? aliases) {
inherit (hostCfg) aliases;
}
// optionalAttrs (hostCfg ? interface) {
inherit (hostCfg) interface;
}
// optionalAttrs (hostCfg ? tags) {
inherit (hostCfg) tags;
}
))
hostNames);
mkHostsFromSpec = mkHostsFromSpec =
spec: spec:
let let
locations = locations = spec.locations or (throw "metatron-addressing: spec.locations is required");
spec.locations or (throw "metatron-addressing: spec.locations is required");
locationId = locationIdForSpec spec; locationId = locationIdForSpec spec;
domain =
spec.domain or (throw "metatron-addressing: spec.domain is required for FQDN generation");
in in
concatMapAttrs concatMapAttrs
(locationName: locationCfg: (locationName: locationCfg:
let let
loc = locationId locationName; loc = locationId locationName;
locCode = mkLocationCode locationName; locCode = mkLocationCode locationName;
locationScope = mergeScopes emptyScope locationCfg;
# Only treat attributes that are attrsets with a `hosts` attr as subnets networks = locationCfg.networks or { };
subnets =
lib.filterAttrs (_: v: builtins.isAttrs v && v ? hosts) locationCfg;
in in
concatMapAttrs concatMapAttrs
(typeName: subnetCfg: (networkName: networkCfg:
let let
hostsForSubnet = subnetCfg.hosts or { }; networkScope = mergeScopes locationScope networkCfg;
subnets = networkCfg.subnets or { };
# Only treat non-underscore-prefixed keys as hosts
hostNames =
filter (hn: builtins.substring 0 1 hn != "_") (attrNames hostsForSubnet);
in in
listToAttrs (imap1 concatMapAttrs
(idx: hostName: (typeName: subnetCfg:
let let
hostCfg = hostsForSubnet.${hostName}; subnetScope = mergeScopes networkScope subnetCfg;
roleName = hostCfg.role; in
hostMapForSubnet {
inherit loc locCode locationName networkName typeName subnetCfg;
scope = subnetScope;
})
subnets)
networks)
locations;
# Count how many hosts of this role exist up to *and including* this one mkSubnetsFromSpec =
roleIndex = spec:
let let
prefix = lib.lists.sublist 0 idx hostNames; locations = spec.locations or (throw "metatron-addressing: spec.locations is required");
in locationId = locationIdForSpec spec;
length (filter in
(hn: (hostsForSubnet.${hn}.role or null) == roleName) concatMapAttrs
prefix); (locationName: locationCfg:
let
loc = locationId locationName;
locCode = mkLocationCode locationName;
locationScope = mergeScopes emptyScope locationCfg;
networks = locationCfg.networks or { };
in
concatMapAttrs
(networkName: networkCfg:
let
networkScope = mergeScopes locationScope networkCfg;
subnets = networkCfg.subnets or { };
in
mapAttrs'
(typeName: subnetCfg:
let
subnetScope = mergeScopes networkScope subnetCfg;
hostId = hostCfg.hostId or roleIndex; cidr = mkSubnetNamed { location = loc; inherit typeName; };
ip = mkIpNamed {
location = loc;
inherit typeName;
roleName = hostCfg.role;
host = hostId;
};
subnetSlug = subnetSlug =
if builtins.hasAttr typeName subnetSlugs if builtins.hasAttr typeName subnetSlugs
then subnetSlugs.${typeName} then subnetSlugs.${typeName}
else typeName; else typeName;
roleSlug = vlan =
if builtins.hasAttr roleName roleSlugs subnetCfg.vlan or
then roleSlugs.${roleName} subnetCfg._vlan or
else roleName; (mkVlanNamed { location = loc; inherit typeName; });
hostnameBase = "${roleSlug}-${builtins.toString hostId}"; dhcpCfg = subnetCfg.dhcp or null;
hostname = hostCfg.hostname or hostnameBase;
fqdn = "${hostname}.${subnetSlug}.${locCode}.${domain}"; dhcpRange =
if dhcpCfg == null then null else {
startIp = mkIpNamed {
location = loc;
inherit typeName;
roleName = "pool";
host = dhcpCfg.start;
};
endIp = mkIpNamed {
location = loc;
inherit typeName;
roleName = "pool";
host = dhcpCfg.end;
};
};
in in
nameValuePair hostName ( nameValuePair
{ "${locationName}-${networkName}-${typeName}"
ip-address = ip; (
inherit hostname fqdn; {
inherit cidr locationName networkName typeName vlan;
# New context fields: }
location = locationName; // optionalAttrs (subnetScope.domain != null) {
subnetType = typeName; zone = "${subnetSlug}.${locCode}.${subnetScope.domain}";
subnetKey = "${locationName}-${typeName}"; }
} // materializeScope subnetScope
// optionalAttrs (hostCfg ? hw-address) { // optionalAttrs (dhcpCfg != null) {
inherit (hostCfg) hw-address; dhcp = dhcpCfg;
} dhcpRange = dhcpRange;
// optionalAttrs (hostCfg ? dns) { }
inherit (hostCfg) dns; ))
} subnets)
// optionalAttrs (hostCfg ? aliases) { networks)
inherit (hostCfg) aliases;
}
// optionalAttrs (hostCfg ? interface) {
inherit (hostCfg) interface;
}
)
)
hostNames))
subnets)
locations; locations;
# Subnet map: { "home-dmz" = "10.1.0.0/19"; "home-main" = "..."; ... } mkNetworkFromSpec = spec: {
mkSubnetsFromSpec = hosts = mkHostsFromSpec spec;
spec: subnets = mkSubnetsFromSpec spec;
let };
locations =
spec.locations or (throw "metatron-addressing: spec.locations is required");
locationId = locationIdForSpec spec;
domain =
spec.domain or (throw "metatron-addressing: spec.domain is required");
in
concatMapAttrs
(locationName: locationCfg:
let
loc = locationId locationName;
locCode = mkLocationCode locationName;
# Only attributes with `hosts` are subnets
subnets =
lib.filterAttrs (_: v: builtins.isAttrs v && v ? hosts) locationCfg;
in
mapAttrs'
(typeName: subnetCfg:
let
cidr = mkSubnetNamed { location = loc; inherit typeName; };
subnetSlug =
if builtins.hasAttr typeName subnetSlugs
then subnetSlugs.${typeName}
else typeName;
zone = "${subnetSlug}.${locCode}.${domain}";
vlan =
subnetCfg.vlan or
subnetCfg._vlan or
(mkVlanNamed { location = loc; inherit typeName; });
dhcpCfg = subnetCfg.dhcp or null;
dhcpRange =
if dhcpCfg == null then null else {
startIp = mkIpNamed {
location = loc;
inherit typeName;
roleName = "pool";
host = dhcpCfg.start;
};
endIp = mkIpNamed {
location = loc;
inherit typeName;
roleName = "pool";
host = dhcpCfg.end;
};
};
in
nameValuePair
"${locationName}-${typeName}"
(
{
inherit cidr locationName typeName zone vlan;
}
// optionalAttrs (dhcpCfg != null) {
dhcp = dhcpCfg;
dhcpRange = dhcpRange;
}
))
subnets)
locations;
# Combined view, if you want both
mkNetworkFromSpec =
spec:
let
domain =
spec.domain or (throw "metatron-addressing: spec.domain is required");
in
{
inherit domain;
hosts = mkHostsFromSpec spec;
subnets = mkSubnetsFromSpec spec;
};
in in
{ {
@ -448,12 +502,15 @@ in
mkIpNamed mkIpNamed
mkSubnet mkSubnet
mkSubnetNamed mkSubnetNamed
mkVlan
mkVlanNamed
mkHostsFromSpec mkHostsFromSpec
mkSubnetsFromSpec mkSubnetsFromSpec
mkNetworkFromSpec mkNetworkFromSpec
mkRoleRange mkRoleRange
mkRoleRangeNamed; mkRoleRangeNamed
mergeScopes;
# Shorthand; you were calling mkHosts before # Shorthand; you were calling mkHosts before.
mkHosts = mkNetworkFromSpec; mkHosts = mkNetworkFromSpec;
} }

218
meta.nix
View file

@ -3,22 +3,23 @@
locations = { locations = {
cloud = { cloud = {
owner = "yaro"; domain = "kasear.net";
dmz = {
hosts = { networks.default.subnets = {
dmz.hosts = {
eris = { eris = {
role = "router"; role = "router";
aliases = [ "frontend.kasear.net" ]; aliases = [
"frontend.kasear.net"
];
}; };
deimos-cloud = { deimos-cloud = {
role = "server"; role = "server";
}; };
}; };
};
infra = { infra.hosts = {
hosts = {
metatron = { metatron = {
role = "coreServer"; role = "coreServer";
}; };
@ -26,15 +27,28 @@
loki-cloud = { loki-cloud = {
role = "adminWorkstation"; role = "adminWorkstation";
}; };
io-cloud = {
role = "router";
};
europa-cloud = {
role = "router";
};
vpn-container = {
role = "server";
dns = false;
};
}; };
}; };
}; };
home = { norfolk = {
dmz = { domain = "kasear.net";
vlan = 1;
hosts = { networks.default.subnets = {
dmz.hosts = {
io = { io = {
role = "router"; role = "router";
aliases = [ "external.kasear.net" ]; aliases = [ "external.kasear.net" ];
@ -58,7 +72,6 @@
"test.kasear.net" "test.kasear.net"
"vault.kasear.net" "vault.kasear.net"
"vikali.kasear.net" "vikali.kasear.net"
"vpn.kasear.net"
"www.kasear.net" "www.kasear.net"
"yaro.kasear.net" "yaro.kasear.net"
]; ];
@ -69,27 +82,60 @@
dns = false; dns = false;
}; };
cloud-container = { role = "server"; dns = false; }; cloud-container = {
default-container = { role = "server"; dns = false; }; role = "server";
foregejo-container = { role = "server"; dns = false; }; dns = false;
majike-container = { role = "server"; dns = false; }; };
media-container = { role = "server"; dns = false; };
vault-container = { role = "server"; dns = false; };
vikali-container = { role = "server"; dns = false; };
vpn-container = { role = "server"; dns = false; };
yaro-container = { role = "server"; dns = false; };
};
};
main = { default-container = {
vlan = 10; role = "server";
dns = false;
};
dhcp = { foregejo-container = {
start = 1; role = "server";
end = 250; dns = false;
};
majike-container = {
role = "server";
dns = false;
};
media-container = {
role = "server";
dns = false;
};
vault-container = {
role = "server";
dns = false;
};
vikali-container = {
role = "server";
dns = false;
};
yaro-container = {
role = "server";
dns = false;
};
norfolk-dmz-dhcp-start = {
role = "pool";
hostId = 1;
dns = false;
};
norfolk-dmz-dhcp-end = {
role = "pool";
hostId = 250;
dns = false;
};
}; };
hosts = { main.hosts = {
europa = { europa = {
role = "router"; role = "router";
aliases = [ "internal.kasear.net" ]; aliases = [ "internal.kasear.net" ];
@ -106,6 +152,11 @@
hw-address = "54:af:97:02:2f:15"; hw-address = "54:af:97:02:2f:15";
}; };
loki = {
role = "adminWorkstation";
hw-address = "70:85:c2:f4:1a:58";
};
luna = { luna = {
role = "infraDevice"; role = "infraDevice";
hw-address = "30:23:03:48:4c:75"; hw-address = "30:23:03:48:4c:75";
@ -114,7 +165,6 @@
phobos = { phobos = {
role = "server"; role = "server";
hw-address = "10:98:36:a9:4a:26"; hw-address = "10:98:36:a9:4a:26";
interface = "eno2";
aliases = [ aliases = [
"pbx.kasear.net" "pbx.kasear.net"
"private.kasear.net" "private.kasear.net"
@ -137,28 +187,39 @@
role = "phone"; role = "phone";
hw-address = "80:5e:c0:de:3d:66"; hw-address = "80:5e:c0:de:3d:66";
}; };
};
};
guest = { norfolk-main-dhcp-start = {
vlan = 20; role = "pool";
hostId = 1;
dns = false;
};
dhcp = { norfolk-main-dhcp-end = {
start = 1; role = "pool";
end = 250; hostId = 250;
dns = false;
};
}; };
hosts = { guest.hosts = {
europa-guest = { europa-guest = {
role = "router"; role = "router";
}; };
norfolk-guest-dhcp-start = {
role = "pool";
hostId = 1;
dns = false;
};
norfolk-guest-dhcp-end = {
role = "pool";
hostId = 250;
dns = false;
};
}; };
};
iot = { iot.hosts = {
vlan = 30;
hosts = {
europa-iot = { europa-iot = {
role = "router"; role = "router";
}; };
@ -183,6 +244,11 @@
hw-address = "08:84:9d:74:4d:c6"; hw-address = "08:84:9d:74:4d:c6";
}; };
loki-iot = {
role = "adminWorkstation";
hw-address = "70:85:c2:f4:1a:58";
};
camera1 = { camera1 = {
role = "camera"; role = "camera";
hw-address = "9c:8e:cd:38:95:1f"; hw-address = "9c:8e:cd:38:95:1f";
@ -204,18 +270,26 @@
role = "appliance"; role = "appliance";
hw-address = "04:e4:b6:23:81:fc"; hw-address = "04:e4:b6:23:81:fc";
}; };
};
};
storage = { mercury-iot = {
vlan = 40; role = "mobile";
hw-address = "ac:3e:b1:77:65:2e";
};
dhcp = { norfolk-iot-dhcp-start = {
start = 1; role = "pool";
end = 250; hostId = 1;
dns = false;
};
norfolk-iot-dhcp-end = {
role = "pool";
hostId = 250;
dns = false;
};
}; };
hosts = { storage.hosts = {
europa-storage = { europa-storage = {
role = "router"; role = "router";
}; };
@ -224,13 +298,30 @@
role = "nas"; role = "nas";
aliases = [ "storage.kasear.net" ]; aliases = [ "storage.kasear.net" ];
}; };
loki-storage = {
role = "adminWorkstation";
hw-address = "00:07:43:13:c4:90";
};
norfolk-storage-dhcp-start = {
role = "pool";
hostId = 1;
dns = false;
};
norfolk-storage-dhcp-end = {
role = "pool";
hostId = 250;
dns = false;
};
}; };
};
management = { management.hosts = {
vlan = 70; europa-management = {
role = "router";
};
hosts = {
deimos-idrac = { deimos-idrac = {
role = "oobMgmt"; role = "oobMgmt";
hw-address = "10:98:36:a0:2c:b3"; hw-address = "10:98:36:a0:2c:b3";
@ -245,13 +336,20 @@
role = "oobMgmt"; role = "oobMgmt";
hw-address = "14:18:77:51:4b:b5"; hw-address = "14:18:77:51:4b:b5";
}; };
norfolk-management-dhcp-start = {
role = "pool";
hostId = 1;
dns = false;
};
norfolk-management-dhcp-end = {
role = "pool";
hostId = 250;
dns = false;
};
}; };
}; };
}; };
}; };
# You can add these later if you want to match the bigger design:
# systems = { };
# consumers = { };
# policy = { };
} }