feat(meta): Rework and use a module

This commit is contained in:
Tom Hubrecht 2024-02-23 10:50:50 +01:00 committed by thubrecht
parent 7fc5bad1e6
commit 82cafb5fd7
13 changed files with 372 additions and 219 deletions

View file

@ -59,10 +59,9 @@ let
in in
{ {
nodes = nodes = builtins.mapAttrs (host: { site, ... }: "${host}.${site}.infra.dgnum.eu") (
pkgs.lib.concatMapAttrs import ./meta/nodes.nix
(site: builtins.foldl' (acc: host: acc // { ${host} = "${host}.${site}.infra.dgnum.eu"; }) { }) );
(import ./meta/infrastructure.nix);
shells = { shells = {
default = pkgs.mkShell { default = pkgs.mkShell {

View file

@ -1,42 +1,26 @@
let let
sources = import ./npins; sources = import ./npins;
metadata = import ./meta;
lib = import (sources.nix-lib + "/src/trivial.nix"); lib = import (sources.nix-lib + "/src/trivial.nix");
patch = import sources.nix-patches { patchFile = ./patches; }; patch = import sources.nix-patches { patchFile = ./patches; };
mkNode = node: _: { nodes' = import ./meta/nodes.nix;
nodes = builtins.attrNames nodes';
mkNode = node: {
# Import the base configuration for each node # Import the base configuration for each node
imports = builtins.map (lib.mkRel ./machines/${node}) [ imports = builtins.map (lib.mkRel (./machines/${node})) [
"_configuration.nix" "_configuration.nix"
"_hardware-configuration.nix" "_hardware-configuration.nix"
]; ];
# Include default secrets
age-secrets.sources = [ ./machines/${node}/secrets ];
# Deployment config is specified in meta.nodes.${node}.deployment
inherit (metadata.nodes.${node}) deployment;
# Set NIX_PATH to the patched version of nixpkgs
nix.nixPath = [ "nixpkgs=${mkNixpkgs node}" ];
nix.optimise.automatic = true;
# Allow unfree packages
nixpkgs.config.allowUnfree = true;
# Use the stateVersion declared in the metadata
system = {
inherit (metadata.nodes.${node}) stateVersion;
};
}; };
mkNixpkgs = mkNixpkgs =
node: node:
patch.mkNixpkgsSrc rec { patch.mkNixpkgsSrc rec {
src = sources.${version}; src = sources.${version};
version = "nixos-${metadata.nodes.${node}.nixpkgs}"; version = "nixos-${nodes'.${node}.nixpkgs or (import ./meta/nixpkgs.nix)}";
}; };
mkNixpkgs' = node: import (mkNixpkgs node) { }; mkNixpkgs' = node: import (mkNixpkgs node) { };
@ -44,31 +28,56 @@ let
### ###
# Function to create arguments based on the node # Function to create arguments based on the node
# #
mkArgs = node: { mkArgs = node: rec {
lib = import sources.nix-lib { lib = import sources.nix-lib {
inherit (mkNixpkgs' node) lib; inherit (mkNixpkgs' node) lib;
keysRoot = ./keys; keysRoot = ./keys;
}; };
};
nodes = builtins.attrNames metadata.nodes; meta = (import ./meta).meta lib;
};
in in
# nodes = builtins.attrNames metadata.nodes;
{ {
meta = { meta = {
nodeNixpkgs = lib.mapSingleFuse mkNixpkgs' nodes; nodeNixpkgs = lib.mapSingleFuse mkNixpkgs' nodes;
specialArgs = { specialArgs = {
inherit sources; inherit sources;
meta = metadata;
}; };
nodeSpecialArgs = lib.mapSingleFuse mkArgs nodes; nodeSpecialArgs = lib.mapSingleFuse mkArgs nodes;
}; };
defaults = _: { defaults =
{
pkgs,
meta,
name,
...
}:
{
# Import the default modules # Import the default modules
imports = [ ./modules ]; imports = [ ./modules ];
# Include default secrets
age-secrets.sources = [ (./machines + "/${name}/secrets") ];
# Deployment config is specified in meta.nodes.${node}.deployment
inherit (meta.nodes.${name}) deployment;
# Set NIX_PATH to the patched version of nixpkgs
nix.nixPath = [ "nixpkgs=${pkgs.path}" ];
nix.optimise.automatic = true;
# Allow unfree packages
nixpkgs.config.allowUnfree = true;
# Use the stateVersion declared in the metadata
system = {
inherit (meta.nodes.${name}) stateVersion;
};
}; };
} }
// (lib.mapSingleFuse mkNode nodes) // (lib.mapSingleFuse mkNode nodes)

View file

@ -3,60 +3,23 @@
# accessible through the specialArg meta in the config. # accessible through the specialArg meta in the config.
let let
###
# Transforms data from :
# {
# zone01 = [ node01 node02 ];
# zone02 = [ node03 ];
# }
# to :
# {
# node01 = zone01;
# node02 = zone01;
# node03 = zone02;
# }
locations = builtins.foldl' (a: loc: a // loc) { } (
builtins.concatLists (
builtins.attrValues (builtins.mapAttrs (zone: builtins.map (n: { ${n} = zone; })) infra)
)
);
###
# Add computed data about the nodes :
# - zone
# - deployment tags
# - network information
mkNode =
node: attrs:
attrs
// {
zone = locations.${node};
deployment =
let
old = attrs.deployment;
in
old
// {
tags = (old.tags or [ ]) ++ [ "infra-${locations.${node}}" ];
targetHost = old.targetHost or (builtins.head network.${node}.addresses.public);
};
};
infra = import ./infrastructure.nix;
members = import ./members.nix;
network = import ./network.nix;
nodes = builtins.mapAttrs mkNode (import ./nodes.nix);
meta = {
inherit
infra
members
network
nodes
;
};
dns = args: import ./dns.nix (args // { inherit meta; }); dns = args: import ./dns.nix (args // { inherit meta; });
meta =
lib:
(lib.evalModules {
modules = [
./options.nix
{
network = import ./network.nix;
nodes = import ./nodes.nix;
organization = import ./organization.nix;
}
];
class = "dgnumMeta";
}).config;
in in
meta // { inherit dns; }
{
inherit dns meta;
}

View file

@ -10,19 +10,21 @@ let
inherit (dns.lib.combinators) mx spf ttl; inherit (dns.lib.combinators) mx spf ttl;
meta' = meta lib;
mkCNAME = host: { CNAME = [ host ]; }; mkCNAME = host: { CNAME = [ host ]; };
mkRecord = mkRecord =
host: host:
let let
net = meta.network.${host}; net = meta'.network.${host};
in in
{ {
A = net.addresses.publicV4; A = net.addresses.publicV4;
AAAA = net.addresses.publicV6; AAAA = net.addresses.publicV6;
}; };
mkHosted = server: mapSingleFuse (_: mkCNAME "${server}.${meta.nodes.${server}.zone}.infra"); mkHosted = server: mapSingleFuse (_: mkCNAME "${server}.${meta'.nodes.${server}.site}.infra");
cnames = builtins.mapAttrs (_: to: { CNAME = [ to ]; }) { cnames = builtins.mapAttrs (_: to: { CNAME = [ to ]; }) {
dev = "dev.pages.codeberg.page."; dev = "dev.pages.codeberg.page.";

View file

@ -1,25 +0,0 @@
# Description of the infrastructure
{
# Salle serveur sous le pavillon Pasteur
par01 = [
"compute01"
"storage01"
];
# Jourdan
par02 = [
"geo01"
"geo02"
"vault01"
];
# Luj's infra
par03 = [ "rescue01" ];
# VMs du SPI/NPS/Whatever
dmi01 = [
"web01"
"web02"
];
}

View file

@ -1,55 +1,4 @@
let
mkDefaultInterface =
_: attrs:
{ {
ipv4 = [ ];
ipv6 = [ ];
gateways = [ ];
}
// attrs;
mkBase =
config: config // { interfaces = builtins.mapAttrs mkDefaultInterface (config.interfaces or { }); };
getAddresses = version: interface: builtins.map (builtins.getAttr "address") interface.${version};
filterIPv4 = ip: builtins.substring 0 7 ip != "192.168";
filterIPv6 = _: true;
mkNet =
_: value:
let
base = mkBase value;
in
base
// {
addresses =
let
_addresses =
builtins.foldl'
(
{ ipv4, ipv6 }:
net: {
ipv4 = ipv4 ++ getAddresses "ipv4" net;
ipv6 = ipv6 ++ getAddresses "ipv6" net;
}
)
{
ipv4 = [ ];
ipv6 = [ ];
}
(builtins.attrValues base.interfaces);
in
_addresses
// rec {
publicV4 = builtins.filter filterIPv4 _addresses.ipv4;
publicV6 = builtins.filter filterIPv6 _addresses.ipv6;
public = publicV4 ++ publicV6;
};
};
in
builtins.mapAttrs mkNet {
compute01 = { compute01 = {
interfaces = { interfaces = {
eno1 = { eno1 = {
@ -65,6 +14,7 @@ builtins.mapAttrs mkNet {
]; ];
gateways = [ "129.199.146.254" ]; gateways = [ "129.199.146.254" ];
enableDefaultDNS = true;
}; };
}; };
@ -82,16 +32,16 @@ builtins.mapAttrs mkNet {
]; ];
gateways = [ "129.199.210.254" ]; gateways = [ "129.199.210.254" ];
};
};
hostId = "b88fee0c";
dns = [ dns = [
"129.199.96.11" "129.199.96.11"
"129.199.72.99" "129.199.72.99"
]; ];
}; };
};
hostId = "b88fee0c";
};
geo02 = { geo02 = {
interfaces = { interfaces = {
@ -104,16 +54,16 @@ builtins.mapAttrs mkNet {
]; ];
gateways = [ "129.199.210.254" ]; gateways = [ "129.199.210.254" ];
};
};
hostId = "45d65237";
dns = [ dns = [
"129.199.96.11" "129.199.96.11"
"129.199.72.99" "129.199.72.99"
]; ];
}; };
};
hostId = "45d65237";
};
storage01 = { storage01 = {
interfaces = { interfaces = {
@ -130,6 +80,7 @@ builtins.mapAttrs mkNet {
]; ];
gateways = [ "129.199.146.254" ]; gateways = [ "129.199.146.254" ];
enableDefaultDNS = true;
}; };
}; };
@ -166,6 +117,7 @@ builtins.mapAttrs mkNet {
]; ];
gateways = [ "129.199.129.1" ]; gateways = [ "129.199.129.1" ];
enableDefaultDNS = true;
}; };
}; };
@ -183,6 +135,7 @@ builtins.mapAttrs mkNet {
]; ];
gateways = [ "129.199.129.1" ]; gateways = [ "129.199.129.1" ];
enableDefaultDNS = true;
}; };
}; };
@ -198,6 +151,7 @@ builtins.mapAttrs mkNet {
prefixLength = 64; prefixLength = 64;
} }
]; ];
ipv4 = [ ipv4 = [
{ {
address = "192.168.0.232"; address = "192.168.0.232";
@ -205,6 +159,7 @@ builtins.mapAttrs mkNet {
} }
]; ];
gateways = [ "192.168.0.1" ]; gateways = [ "192.168.0.1" ];
enableDefaultDNS = true;
}; };
}; };
hostId = "007f0200"; hostId = "007f0200";

2
meta/nixpkgs.nix Normal file
View file

@ -0,0 +1,2 @@
# Default version of nixpkgs to use
"23.11"

View file

@ -10,32 +10,30 @@
# nixpkgs = "unstable" or "22.11"; # nixpkgs version # nixpkgs = "unstable" or "22.11"; # nixpkgs version
# } # }
let /* Liste des différents sites :
mkNode = - dmi01 -> VM du NPSPI
_: attrs: - par01 -> Salle serveur sous le pavillon Pasteur
- par02 -> Local DGNum Jourdan
- par03 -> VM de Luj
*/
{ {
adminGroups = [ ];
admins = [ ];
deployment = { };
nixpkgs = "23.11";
}
// attrs;
in
builtins.mapAttrs mkNode {
web01 = { web01 = {
site = "dmi01";
deployment.tags = [ "web" ]; deployment.tags = [ "web" ];
stateVersion = "23.05"; stateVersion = "23.05";
}; };
compute01 = { compute01 = {
site = "par01";
stateVersion = "23.05"; stateVersion = "23.05";
}; };
geo01 = { geo01 = {
site = "par02";
deployment.tags = [ "geo" ]; deployment.tags = [ "geo" ];
stateVersion = "24.05"; stateVersion = "24.05";
@ -43,6 +41,7 @@ builtins.mapAttrs mkNode {
}; };
geo02 = { geo02 = {
site = "par02";
deployment.tags = [ "geo" ]; deployment.tags = [ "geo" ];
stateVersion = "24.05"; stateVersion = "24.05";
@ -50,20 +49,27 @@ builtins.mapAttrs mkNode {
}; };
storage01 = { storage01 = {
site = "par01";
stateVersion = "23.11"; stateVersion = "23.11";
}; };
vault01 = { vault01 = {
site = "par02";
stateVersion = "23.11"; stateVersion = "23.11";
nixpkgs = "unstable"; nixpkgs = "unstable";
}; };
web02 = { web02 = {
site = "dmi01";
stateVersion = "24.05"; stateVersion = "24.05";
nixpkgs = "unstable"; nixpkgs = "unstable";
}; };
rescue01 = { rescue01 = {
site = "par03";
stateVersion = "23.11"; stateVersion = "23.11";
}; };
} }

256
meta/options.nix Normal file
View file

@ -0,0 +1,256 @@
{ lib, ... }@args:
let
inherit (lib)
mkEnableOption
mkDefault
mkIf
mkOption
;
inherit (lib.types)
attrs
attrsOf
ints
listOf
nullOr
str
submodule
;
addressType =
max:
submodule {
options = {
address = mkOption {
type = str;
description = "IP address.";
};
prefixLength = mkOption {
type = ints.between 8 max;
description = "Length of the prefix used in the local network.";
};
};
};
in
{
options = {
organization = {
members = mkOption {
type = attrsOf (
submodule {
options = {
name = mkOption {
type = str;
description = ''
Name of the member.
'';
};
email = mkOption {
type = str;
description = ''
Main e-mail address of the member.
'';
};
};
}
);
description = ''
Members of the DGNum organization.
'';
};
groups = mkOption {
type = attrsOf (listOf str);
description = ''
Groups of the DGNum organization.
'';
};
};
nodes = mkOption {
type = attrsOf (
submodule (
{ config, name, ... }:
{
options = {
deployment = mkOption {
type = attrs;
default = { };
};
stateVersion = mkOption {
type = str;
description = ''
State version of the node.
'';
};
nixpkgs = mkOption {
type = str;
default = import ./nixpkgs.nix;
description = ''
Version of nixpkgs to use.
'';
};
admins = mkOption {
type = listOf str;
default = [ ];
description = ''
List of members to be given root access to this node.
'';
};
adminGroups = mkOption {
type = listOf str;
default = [ ];
description = ''
List of groups to be given root access to this node.
'';
};
site = mkOption {
type = str;
description = ''
Geographical site where the node is located.
'';
};
};
config = {
deployment = {
tags = [ "infra-${config.site}" ];
targetHost =
let
ip = with args.config.network.${name}.addresses; ipv4 ++ ipv6;
in
mkIf (ip != [ ]) (mkDefault (builtins.head ip));
};
};
}
)
);
description = ''
Nodes of the infrastructure.
'';
};
network = mkOption {
type = attrsOf (
submodule (
{ config, ... }:
{
options = {
interfaces = mkOption {
type = attrsOf (
submodule (
{ config, ... }:
{
options = {
ipv4 = mkOption {
type = listOf (addressType 32);
default = [ ];
description = ''
List of ipv4 addresses assigned to the interface.
'';
};
ipv6 = mkOption {
type = listOf (addressType 64);
default = [ ];
description = ''
List of ipv6 addresses assigned to the interface.
'';
};
gateways = mkOption {
type = listOf str;
default = [ ];
description = ''
List of gateways used by the interface.
'';
};
DHCP = mkOption {
type = nullOr str;
default = null;
description = "Whether to enable DHCP on the interface.";
};
dns = mkOption {
type = listOf str;
default = [ ];
};
enableDefaultDNS = mkEnableOption "default DNS servers.";
};
config.dns = mkIf config.enableDefaultDNS [
"1.1.1.1#cloudflare-dns.com"
"8.8.8.8#dns.google"
"1.0.0.1#cloudflare-dns.com"
"8.8.4.4#dns.google"
"2606:4700:4700::1111#cloudflare-dns.com"
"2001:4860:4860::8888#dns.google"
"2606:4700:4700::1001#cloudflare-dns.com"
"2001:4860:4860::8844#dns.google"
];
}
)
);
};
addresses = {
ipv4 = mkOption {
type = listOf str;
default = [ ];
description = ''
List of public ipv4 addresses of the node.
'';
};
ipv6 = mkOption {
type = listOf str;
default = [ ];
description = ''
List of public ipv6 addresses of the node.
'';
};
};
hostId = mkOption {
type = str;
description = ''
Network Id of the node.
'';
};
};
config =
let
getAddresses =
version: builtins.concatMap (int: builtins.map (builtins.getAttr "address") int.${version});
in
{
addresses = {
ipv4 = builtins.filter (ip: builtins.substring 0 7 ip != "192.168") (
getAddresses "ipv4" (builtins.attrValues config.interfaces)
);
ipv6 = builtins.filter (_: true) ((getAddresses "ipv4") (builtins.attrValues config.interfaces));
};
};
}
)
);
description = ''
Network configuration for the different machines.
'';
};
};
config = { };
}

View file

@ -1,7 +1,8 @@
/* To add a new member add an attribute to `members` /* To add a new member add an attribute to `members`
Then add the key to the required groups. Then add the key to the required groups.
*/ */
let
{
members = { members = {
mdebray = { mdebray = {
name = "Maurice Debray"; name = "Maurice Debray";
@ -50,7 +51,4 @@ let
bureau = [ "gdd" ]; bureau = [ "gdd" ];
}; };
in
{
inherit groups members;
} }

6
meta/verify.nix Normal file
View file

@ -0,0 +1,6 @@
let
sources = import ../npins;
pkgs = import sources.nixpkgs { };
in
builtins.deepSeq ((import ./.).meta pkgs.lib) { }

View file

@ -51,9 +51,9 @@ let
nodeMeta = meta.nodes.${name}; nodeMeta = meta.nodes.${name};
admins = admins =
meta.members.groups.root meta.organization.groups.root
++ nodeMeta.admins ++ nodeMeta.admins
++ (builtins.concatMap (g: meta.members.groups.${g}) nodeMeta.adminGroups); ++ (builtins.concatMap (g: meta.organization.groups.${g}) nodeMeta.adminGroups);
cfg = config.dgn-access-control; cfg = config.dgn-access-control;
in in

View file

@ -7,12 +7,7 @@
}: }:
let let
inherit (lib) inherit (lib) mapAttrs' mkEnableOption mkIf;
mapAttrs'
mkEnableOption
mkIf
optionalAttrs
;
net' = meta.network.${name}; net' = meta.network.${name};
@ -31,20 +26,7 @@ let
address = builtins.map mkAddress (net.ipv4 ++ net.ipv6); address = builtins.map mkAddress (net.ipv4 ++ net.ipv6);
routes = builtins.map mkRoute net.gateways; routes = builtins.map mkRoute net.gateways;
# Add default DNS servers inherit (net) DHCP dns;
dns =
net'.dns or [
"1.1.1.1#cloudflare-dns.com"
"8.8.8.8#dns.google"
"1.0.0.1#cloudflare-dns.com"
"8.8.4.4#dns.google"
"2606:4700:4700::1111#cloudflare-dns.com"
"2001:4860:4860::8888#dns.google"
"2606:4700:4700::1001#cloudflare-dns.com"
"2001:4860:4860::8844#dns.google"
];
networkConfig = optionalAttrs (net ? DHCP) { inherit (net) DHCP; };
}; };
}; };
@ -60,7 +42,7 @@ in
inherit (net') hostId; inherit (net') hostId;
hostName = name; hostName = name;
domain = "${meta.nodes.${name}.zone}.infra.dgnum.eu"; domain = "${meta.nodes.${name}.site}.infra.dgnum.eu";
useNetworkd = true; useNetworkd = true;
firewall.logRefusedConnections = false; firewall.logRefusedConnections = false;