167 lines
4.8 KiB
Nix
167 lines
4.8 KiB
Nix
{ rawHive }:
|
|
with builtins;
|
|
let
|
|
defaultHive = {
|
|
# Will be set in defaultHiveMeta
|
|
meta = {};
|
|
|
|
# Like in NixOps, there is a special host named `defaults`
|
|
# containing configurations that will be applied to all
|
|
# hosts.
|
|
defaults = {};
|
|
};
|
|
|
|
defaultMeta = {
|
|
name = "hive";
|
|
description = "A Colmena Hive";
|
|
|
|
# Can be a path, a lambda, or an initialized Nixpkgs attrset
|
|
nixpkgs = <nixpkgs>;
|
|
|
|
# Per-node Nixpkgs overrides
|
|
# Keys are hostnames.
|
|
nodeNixpkgs = {};
|
|
};
|
|
|
|
# Colmena-specific options
|
|
#
|
|
# Largely compatible with NixOps/Morph.
|
|
deploymentOptions = { name, lib, ... }:
|
|
let
|
|
types = lib.types;
|
|
in {
|
|
options = {
|
|
deployment = {
|
|
targetHost = lib.mkOption {
|
|
description = ''
|
|
The target SSH node for deployment.
|
|
|
|
By default, the node's attribute name will be used.
|
|
If set to null, only local deployment will be supported.
|
|
'';
|
|
type = types.nullOr types.str;
|
|
default = name;
|
|
};
|
|
targetUser = lib.mkOption {
|
|
description = ''
|
|
The user to use to log into the remote node.
|
|
'';
|
|
type = types.str;
|
|
default = "root";
|
|
};
|
|
allowLocalDeployment = lib.mkOption {
|
|
description = ''
|
|
Allow the configuration to be applied locally on the host running
|
|
Colmena.
|
|
|
|
For local deployment to work, all of the following must be true:
|
|
- The node must be running NixOS.
|
|
- The node must have deployment.allowLocalDeployment set to true.
|
|
- The node's networking.hostName must match the hostname.
|
|
|
|
To apply the configurations locally, run `colmena apply-local`.
|
|
You can also set deployment.targetHost to null if the nost is not
|
|
accessible over SSH (only local deployment will be possible).
|
|
'';
|
|
type = types.bool;
|
|
default = false;
|
|
};
|
|
tags = lib.mkOption {
|
|
description = ''
|
|
A list of tags for the node.
|
|
|
|
Can be used to select a group of nodes for deployment.
|
|
'';
|
|
type = types.listOf types.str;
|
|
default = [];
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
userMeta = if rawHive ? meta then rawHive.meta
|
|
else if rawHive ? network then rawHive.network
|
|
else {};
|
|
|
|
# The final hive will always have the meta key instead of network.
|
|
hive = let
|
|
mergedHive = removeAttrs (defaultHive // rawHive) [ "meta" "network" ];
|
|
meta = {
|
|
meta = lib.recursiveUpdate defaultMeta userMeta;
|
|
};
|
|
in mergedHive // meta;
|
|
|
|
mkNixpkgs = configName: pkgConf:
|
|
if typeOf pkgConf == "path" then
|
|
import pkgConf {}
|
|
else if typeOf pkgConf == "lambda" then
|
|
pkgConf {}
|
|
else if typeOf pkgConf == "set" then
|
|
pkgConf
|
|
else throw ''
|
|
${configName} must be one of:
|
|
|
|
- A path to Nixpkgs (e.g., <nixpkgs>)
|
|
- A Nixpkgs lambda (e.g., import <nixpkgs>)
|
|
- A Nixpkgs attribute set
|
|
'';
|
|
|
|
pkgs = mkNixpkgs "meta.nixpkgs" (defaultMeta // userMeta).nixpkgs;
|
|
lib = pkgs.lib;
|
|
reservedNames = [ "defaults" "network" "meta" ];
|
|
|
|
evalNode = name: config: let
|
|
npkgs =
|
|
if hasAttr name hive.meta.nodeNixpkgs
|
|
then mkNixpkgs "meta.nodeNixpkgs.${name}" hive.meta.nodeNixpkgs.${name}
|
|
else pkgs;
|
|
evalConfig = import (npkgs.path + "/nixos/lib/eval-config.nix");
|
|
in evalConfig {
|
|
modules = [
|
|
deploymentOptions
|
|
hive.defaults
|
|
config
|
|
] ++ (import (npkgs.path + "/nixos/modules/module-list.nix"));
|
|
specialArgs = {
|
|
inherit name nodes;
|
|
modulesPath = npkgs.path + "/nixos/modules";
|
|
};
|
|
};
|
|
|
|
nodeNames = filter (name: ! elem name reservedNames) (attrNames hive);
|
|
|
|
# Exported attributes
|
|
#
|
|
# Functions are intended to be called with `nix-instantiate --eval --json`
|
|
|
|
nodes = listToAttrs (map (name: {
|
|
inherit name;
|
|
value = evalNode name hive.${name};
|
|
}) nodeNames);
|
|
|
|
deploymentConfigJson = toJSON (lib.attrsets.mapAttrs (name: eval: eval.config.deployment) nodes);
|
|
|
|
toplevel = lib.attrsets.mapAttrs (name: eval: eval.config.system.build.toplevel) nodes;
|
|
|
|
buildAll = buildSelected {
|
|
names = nodeNames;
|
|
};
|
|
buildSelected = { names ? null }: let
|
|
# Change in the order of the names should not cause a derivation to be created
|
|
selected = lib.attrsets.filterAttrs (name: _: elem name names) toplevel;
|
|
in derivation rec {
|
|
name = "colmena-${hive.meta.name}";
|
|
system = currentSystem;
|
|
json = toJSON (lib.attrsets.mapAttrs (k: v: toString v) selected);
|
|
builder = pkgs.writeScript "${name}.sh" ''
|
|
#!/bin/sh
|
|
echo "$json" > $out
|
|
'';
|
|
};
|
|
|
|
introspect = function: function {
|
|
inherit pkgs lib nodes;
|
|
};
|
|
in {
|
|
inherit nodes deploymentConfigJson toplevel buildAll buildSelected introspect;
|
|
}
|