clan-core/lib/build-clan/default.nix

271 lines
8.9 KiB
Nix
Raw Normal View History

2024-03-17 18:48:49 +00:00
{
clan-core,
nixpkgs,
lib,
}:
{
directory, # The directory containing the machines subdirectory
specialArgs ? { }, # Extra arguments to pass to nixosSystem i.e. useful to make self available
machines ? { }, # allows to include machine-specific modules i.e. machines.${name} = { ... }
2024-05-31 15:22:38 +00:00
# DEPRECATED: use meta.name instead
clanName ? null, # Needs to be (globally) unique, as this determines the folder name where the flake gets downloaded to.
# DEPRECATED: use meta.icon instead
2024-03-17 18:48:49 +00:00
clanIcon ? null, # A path to an icon to be used for the clan, should be the same for all machines
2024-05-31 15:22:38 +00:00
meta ? { }, # A set containing clan meta: name :: string, icon :: string, description :: string
2024-06-21 20:46:12 +00:00
# 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
# Internal inventory, this is the result of merging all potential inventory sources:
# - Default instances configured via 'services'
# - The inventory overrides
# - Machines that exist in inventory.machines
# - Machines explicitly configured via 'machines' argument
# - Machines that exist in the machines directory
# Checks on the module level:
# - Each service role must reference a valid machine after all machines are merged
mergedInventory =
(lib.evalModules {
modules = [
./interface.nix
{ inherit meta; }
# Default instances configured via 'services'
{
services = lib.mapAttrs (_name: value: {
default = value // {
meta.name = lib.mkDefault _name;
};
}) services;
}
# The inventory overrides
2024-06-21 20:46:12 +00:00
inventory
# Machines explicitly configured via 'machines' argument
{
# { ${name} :: meta // { name, tags } }
machines = lib.mapAttrs (
name: config:
(lib.attrByPath [
2024-06-21 20:46:12 +00:00
"clan"
"meta"
] { } config)
// {
# meta.name default is the attribute name of the machine
name = lib.mkDefault (
lib.attrByPath [
"clan"
"meta"
"name"
] name config
);
tags = lib.attrByPath [
"clan"
"tags"
] [ ] config;
}
) machines;
2024-06-21 20:46:12 +00:00
}
# Machines that exist in the machines directory
{ machines = lib.mapAttrs (name: _: { inherit name; }) machinesDirs; }
];
}).config;
2024-06-21 20:46:12 +00:00
buildInventory = import ./inventory.nix { inherit lib clan-core; };
serviceConfigs = buildInventory mergedInventory;
2024-06-21 20:46:12 +00:00
2024-05-31 15:22:38 +00:00
deprecationWarnings = [
(lib.warnIf (
clanName != null
) "clanName is deprecated, please use meta.name instead. ${clanName}" null)
(lib.warnIf (clanIcon != null) "clanIcon is deprecated, please use meta.icon instead" null)
];
2024-03-17 18:48:49 +00:00
machinesDirs = lib.optionalAttrs (builtins.pathExists "${directory}/machines") (
builtins.readDir (directory + /machines)
);
2024-05-31 15:22:38 +00:00
mergedMeta =
let
metaFromFile =
if (builtins.pathExists "${directory}/clan/meta.json") then
let
settings = builtins.fromJSON (builtins.readFile "${directory}/clan/meta.json");
in
settings
else
{ };
legacyMeta = lib.filterAttrs (_: v: v != null) {
name = clanName;
icon = clanIcon;
};
optionsMeta = lib.filterAttrs (_: v: v != null) meta;
warnings =
builtins.map (
name:
if
metaFromFile.${name} or null != optionsMeta.${name} or null && optionsMeta.${name} or null != null
then
lib.warn "meta.${name} is set in different places. (exlicit option meta.${name} overrides ${directory}/clan/meta.json)" null
else
null
) (builtins.attrNames metaFromFile)
++ [ (if (res.name or null == null) then (throw "meta.name should be set") else null) ];
res = metaFromFile // legacyMeta // optionsMeta;
in
# Print out warnings before returning the merged result
builtins.deepSeq warnings res;
2024-03-17 18:48:49 +00:00
machineSettings =
machineName:
# CLAN_MACHINE_SETTINGS_FILE allows to override the settings file temporarily
# This is useful for doing a dry-run before writing changes into the settings.json
# Using CLAN_MACHINE_SETTINGS_FILE requires passing --impure to nix eval
2024-03-17 18:48:49 +00:00
if builtins.getEnv "CLAN_MACHINE_SETTINGS_FILE" != "" then
builtins.fromJSON (builtins.readFile (builtins.getEnv "CLAN_MACHINE_SETTINGS_FILE"))
else
2024-03-17 18:48:49 +00:00
lib.optionalAttrs (builtins.pathExists "${directory}/machines/${machineName}/settings.json") (
builtins.fromJSON (builtins.readFile (directory + /machines/${machineName}/settings.json))
);
# Read additional imports specified via a config option in settings.json
# This is not an infinite recursion, because the imports are discovered here
# before calling evalModules.
# It is still useful to have the imports as an option, as this allows for type
# checking and easy integration with the config frontend(s)
2024-03-17 18:48:49 +00:00
machineImports =
machineSettings: map (module: clan-core.clanModules.${module}) (machineSettings.clanImports or [ ]);
# TODO: remove default system once we have a hardware-config mechanism
2024-03-17 18:48:49 +00:00
nixosConfiguration =
{
system ? "x86_64-linux",
name,
pkgs ? null,
extraConfig ? { },
}:
nixpkgs.lib.nixosSystem {
modules =
let
settings = machineSettings name;
in
(machineImports settings)
++ [
settings
clan-core.nixosModules.clanCore
extraConfig
(machines.${name} or { })
# Inherit the inventory assertions ?
{ inherit (mergedInventory) assertions; }
2024-06-21 20:46:12 +00:00
{ imports = serviceConfigs.${name} or { }; }
2024-03-17 18:48:49 +00:00
(
{
2024-05-31 15:22:38 +00:00
# Settings
2024-06-17 10:42:28 +00:00
clan.core.clanDir = directory;
2024-05-31 15:22:38 +00:00
# Inherited from clan wide settings
2024-06-17 10:42:28 +00:00
clan.core.clanName = meta.name or clanName;
clan.core.clanIcon = meta.icon or clanIcon;
2024-05-31 15:22:38 +00:00
# Machine specific settings
2024-06-17 10:42:28 +00:00
clan.core.machineName = name;
2024-05-31 15:22:38 +00:00
networking.hostName = lib.mkDefault name;
2024-03-17 18:48:49 +00:00
nixpkgs.hostPlatform = lib.mkDefault system;
2024-03-17 18:48:49 +00:00
# speeds up nix commands by using the nixpkgs from the host system (especially useful in VMs)
nix.registry.nixpkgs.to = {
type = "path";
path = lib.mkDefault nixpkgs;
};
}
// lib.optionalAttrs (pkgs != null) { nixpkgs.pkgs = lib.mkForce pkgs; }
)
];
specialArgs = {
inherit clan-core;
} // specialArgs;
2024-03-17 18:48:49 +00:00
};
allMachines = machinesDirs // machines;
supportedSystems = [
"x86_64-linux"
"aarch64-linux"
"riscv64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
nixosConfigurations = lib.mapAttrs (name: _: nixosConfiguration { inherit name; }) allMachines;
# This instantiates nixos for each system that we support:
# configPerSystem = <system>.<machine>.nixosConfiguration
# We need this to build nixos secret generators for each system
2024-03-17 18:48:49 +00:00
configsPerSystem = builtins.listToAttrs (
builtins.map (
system:
lib.nameValuePair system (
lib.mapAttrs (
name: _:
nixosConfiguration {
inherit name system;
pkgs = pkgsForSystem system;
2024-03-17 18:48:49 +00:00
}
) allMachines
)
) supportedSystems
);
2024-03-17 18:48:49 +00:00
configsFuncPerSystem = builtins.listToAttrs (
builtins.map (
system:
lib.nameValuePair system (
lib.mapAttrs (
name: _: args:
nixosConfiguration (
args
// {
inherit name system;
pkgs = pkgsForSystem system;
}
)
) allMachines
)
) supportedSystems
);
in
2024-05-31 15:22:38 +00:00
builtins.deepSeq deprecationWarnings {
inherit nixosConfigurations;
clanInternals = {
2024-05-31 15:22:38 +00:00
# Evaluated clan meta
# Merged /clan/meta.json with overrides from buildClan
meta = mergedMeta;
inventory = mergedInventory;
2024-05-31 15:22:38 +00:00
# machine specifics
machines = configsPerSystem;
machinesFunc = configsFuncPerSystem;
2024-03-17 18:48:49 +00:00
all-machines-json = lib.mapAttrs (
system: configs:
nixpkgs.legacyPackages.${system}.writers.writeJSON "machines.json" (
lib.mapAttrs (_: m: m.config.system.clan.deployment.data) configs
)
) configsPerSystem;
};
}