Extend build-clan interface
This commit is contained in:
committed by
hsjobeki
parent
4db65921fe
commit
eb221244e6
@@ -12,10 +12,79 @@
|
||||
# DEPRECATED: use meta.icon instead
|
||||
clanIcon ? null, # A path to an icon to be used for the clan, should be the same for all machines
|
||||
meta ? { }, # A set containing clan meta: name :: string, icon :: string, description :: string
|
||||
pkgsForSystem ? (_system: null), # A map from arch to pkgs, if specified this nixpkgs will be only imported once for each system.
|
||||
# This improves performance, but all nipxkgs.* options will be ignored.
|
||||
# A map from arch to pkgs, if specified this nixpkgs will be only imported once for each system.
|
||||
# This improves performance, but all nipxkgs.* options will be ignored.
|
||||
pkgsForSystem ? (_system: null),
|
||||
/*
|
||||
Distributed services configuration.
|
||||
|
||||
This configures a default instance in the inventory with the name "default".
|
||||
|
||||
If you need multiple instances of a service configure them via:
|
||||
inventory.services.[serviceName].[instanceName] = ...
|
||||
*/
|
||||
services ? { },
|
||||
/*
|
||||
Low level inventory configuration.
|
||||
Overrides the services configuration.
|
||||
*/
|
||||
inventory ? { },
|
||||
}:
|
||||
let
|
||||
_inventory =
|
||||
(
|
||||
if services != { } && inventory == { } then
|
||||
{ services = lib.mapAttrs (_name: value: { default = value; }) services; }
|
||||
else if services == { } && inventory != { } then
|
||||
inventory
|
||||
else if services != { } && inventory != { } then
|
||||
throw "Either services or inventory should be set, but not both."
|
||||
else
|
||||
{ }
|
||||
)
|
||||
// {
|
||||
machines = lib.mapAttrs (
|
||||
name: config:
|
||||
(lib.attrByPath [
|
||||
"clan"
|
||||
"meta"
|
||||
] { } config)
|
||||
// {
|
||||
name = (
|
||||
lib.attrByPath [
|
||||
"clan"
|
||||
"meta"
|
||||
"name"
|
||||
] name config
|
||||
);
|
||||
tags = lib.attrByPath [
|
||||
"clan"
|
||||
"tags"
|
||||
] [ ] config;
|
||||
}
|
||||
) machines;
|
||||
};
|
||||
|
||||
buildInventory = import ./inventory.nix { inherit lib clan-core; };
|
||||
|
||||
pkgs = import nixpkgs { };
|
||||
|
||||
inventoryFile = builtins.toFile "inventory.json" (builtins.toJSON _inventory);
|
||||
|
||||
# a Derivation that can be forced to validate the inventory
|
||||
# It is not used directly here.
|
||||
validatedFile = pkgs.stdenv.mkDerivation {
|
||||
name = "validated-inventory";
|
||||
src = ../../inventory/src;
|
||||
buildInputs = [ pkgs.cue ];
|
||||
installPhase = ''
|
||||
cue vet ${inventoryFile} root.cue -d "#Root"
|
||||
cp ${inventoryFile} $out
|
||||
'';
|
||||
};
|
||||
|
||||
serviceConfigs = buildInventory _inventory;
|
||||
|
||||
deprecationWarnings = [
|
||||
(lib.warnIf (
|
||||
clanName != null
|
||||
@@ -98,6 +167,7 @@ let
|
||||
clan-core.nixosModules.clanCore
|
||||
extraConfig
|
||||
(machines.${name} or { })
|
||||
{ imports = serviceConfigs.${name} or { }; }
|
||||
(
|
||||
{
|
||||
# Settings
|
||||
@@ -180,6 +250,7 @@ builtins.deepSeq deprecationWarnings {
|
||||
# Evaluated clan meta
|
||||
# Merged /clan/meta.json with overrides from buildClan
|
||||
meta = mergedMeta;
|
||||
inherit _inventory validatedFile;
|
||||
|
||||
# machine specifics
|
||||
machines = configsPerSystem;
|
||||
|
||||
106
lib/build-clan/inventory.nix
Normal file
106
lib/build-clan/inventory.nix
Normal file
@@ -0,0 +1,106 @@
|
||||
# Generate partial NixOS configurations for every machine in the inventory
|
||||
# This function is responsible for generating the module configuration for every machine in the inventory.
|
||||
{ lib, clan-core }:
|
||||
inventory:
|
||||
let
|
||||
machines = machinesFromInventory inventory;
|
||||
|
||||
resolveTags =
|
||||
# Inventory, { machines :: [string], tags :: [string] }
|
||||
inventory: members: {
|
||||
machines =
|
||||
members.machines or [ ]
|
||||
++ (builtins.foldl' (
|
||||
acc: tag:
|
||||
let
|
||||
tagMembers = builtins.attrNames (
|
||||
lib.filterAttrs (_n: v: builtins.elem tag v.tags or [ ]) inventory.machines
|
||||
);
|
||||
in
|
||||
# throw "Machine tag ${tag} not found. Not machine with: tag ${tagName} not in inventory.";
|
||||
if tagMembers == [ ] then
|
||||
throw "Machine tag ${tag} not found. Not machine with: tag ${tag} not in inventory."
|
||||
else
|
||||
acc ++ tagMembers
|
||||
) [ ] members.tags or [ ]);
|
||||
};
|
||||
|
||||
/*
|
||||
Returns a NixOS configuration for every machine in the inventory.
|
||||
|
||||
machinesFromInventory :: Inventory -> { ${machine_name} :: NixOSConfiguration }
|
||||
*/
|
||||
machinesFromInventory =
|
||||
inventory:
|
||||
# For every machine in the inventory, build a NixOS configuration
|
||||
# For each machine generate config, forEach service, if the machine is used.
|
||||
builtins.mapAttrs (
|
||||
machineName: _:
|
||||
lib.foldlAttrs (
|
||||
# [ Modules ], String, { ${instance_name} :: ServiceConfig }
|
||||
acc: moduleName: serviceConfigs:
|
||||
acc
|
||||
# Collect service config
|
||||
++ (lib.foldlAttrs (
|
||||
# [ Modules ], String, ServiceConfig
|
||||
acc2: instanceName: serviceConfig:
|
||||
let
|
||||
resolvedRoles = builtins.mapAttrs (
|
||||
_roleName: members: resolveTags inventory members
|
||||
) serviceConfig.roles;
|
||||
|
||||
isInService = builtins.any (members: builtins.elem machineName members.machines) (
|
||||
builtins.attrValues resolvedRoles
|
||||
);
|
||||
|
||||
# Inverse map of roles. Allows for easy lookup of roles for a given machine.
|
||||
# { ${machine_name} :: [roles]
|
||||
inverseRoles = lib.foldlAttrs (
|
||||
acc: roleName:
|
||||
{ machines }:
|
||||
acc
|
||||
// builtins.foldl' (
|
||||
acc2: machineName: acc2 // { ${machineName} = (acc.${machineName} or [ ]) ++ [ roleName ]; }
|
||||
) { } machines
|
||||
) { } resolvedRoles;
|
||||
|
||||
machineServiceConfig = (serviceConfig.machines.${machineName} or { }).config or { };
|
||||
globalConfig = serviceConfig.config or { };
|
||||
|
||||
# TODO: maybe optimize this dont lookup the role in inverse roles. Imports are not lazy
|
||||
roleModules = builtins.map (
|
||||
role:
|
||||
let
|
||||
path = "${clan-core.clanModules.${moduleName}}/roles/${role}.nix";
|
||||
in
|
||||
if builtins.pathExists path then
|
||||
path
|
||||
else
|
||||
throw "Role doesnt have a module: ${role}. Path: ${path} not found."
|
||||
) inverseRoles.${machineName} or [ ];
|
||||
in
|
||||
if isInService then
|
||||
acc2
|
||||
++ [
|
||||
{
|
||||
imports = [ clan-core.clanModules.${moduleName} ] ++ roleModules;
|
||||
config.clan.${moduleName} = lib.mkMerge [
|
||||
globalConfig
|
||||
machineServiceConfig
|
||||
];
|
||||
}
|
||||
{
|
||||
config.clan.services.${moduleName}.${instanceName} = {
|
||||
roles = resolvedRoles;
|
||||
# TODO: Add inverseRoles to the service config if needed
|
||||
# inherit inverseRoles;
|
||||
};
|
||||
}
|
||||
]
|
||||
else
|
||||
acc2
|
||||
) [ ] serviceConfigs)
|
||||
) [ ] inventory.services
|
||||
) inventory.machines;
|
||||
in
|
||||
machines
|
||||
Reference in New Issue
Block a user