rigging/flake-module.nix
Christopher Mühl 892161eae2
feat: initial rigging — multi-repo NixOS + Nomad infrastructure management
Flake-parts module that repos import to declare hosts, jobs, and secrets.
Nushell CLI (rigging) aggregates multiple repos and provides unified
management: host deploy/build, job run/plan/stop, secret list/rekey.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 01:09:32 +01:00

202 lines
6.1 KiB
Nix

# Rigging flake-parts module
# Import this in your flake to get Nomad job management + multi-repo infrastructure CLI
topArgs @ {
lib,
config,
flake-parts-lib,
...
}: let
inherit (lib) mkOption mkIf mkMerge types;
inherit (flake-parts-lib) mkPerSystemOption;
# Top-level bosun config — accessed lazily via closure
topCfg = topArgs.config.bosun;
in {
options = {
bosun = {
meta.name = mkOption {
type = types.str;
description = "Short name identifying this repo (e.g. 'infra', 'dotfiles')";
};
hosts = mkOption {
type = types.attrsOf (types.submodule {
options = {
system = mkOption {
type = types.str;
default = "x86_64-linux";
description = "System architecture";
};
class = mkOption {
type = types.enum ["nixos" "darwin"];
default = "nixos";
description = "Host class (nixos or darwin)";
};
targetHost = mkOption {
type = types.nullOr types.str;
default = null;
description = "SSH target for remote deployment (null = local)";
};
buildHost = mkOption {
type = types.nullOr types.str;
default = null;
description = "SSH host for remote building (null = local)";
};
tags = mkOption {
type = types.listOf types.str;
default = [];
description = "Freeform tags for filtering (e.g. 'server', 'desktop', 'contabo')";
};
};
});
default = {};
description = "Host declarations for this repo";
};
};
perSystem = mkPerSystemOption ({
config,
pkgs,
system,
...
}: {
options.bosun = {
enable = mkOption {
type = types.bool;
default = false;
description = "Enable bosun Nomad job management";
};
jobsDir = mkOption {
type = types.nullOr types.path;
default = null;
description = "Directory containing job definitions (auto-discovered)";
};
jobs = mkOption {
type = types.lazyAttrsOf types.raw;
default = {};
description = "Explicit job definitions (merged with discovered jobs)";
};
nomadLib = mkOption {
type = types.lazyAttrsOf types.raw;
default = {};
description = "Additional nomadLib helpers to merge";
};
defaultVars = mkOption {
type = types.attrsOf types.str;
default = {};
description = "Default variables passed to all jobs";
};
nomadAddress = mkOption {
type = types.str;
default = "http://127.0.0.1:4646";
description = "Nomad server address";
};
flakeRef = mkOption {
type = types.nullOr types.str;
default = null;
description = "Flake reference for runtime evaluation (auto-detected if null)";
};
};
config = let
cfg = config.bosun;
bosunLib = import ./lib;
nomadLib =
(bosunLib.nomad {inherit lib;})
// cfg.nomadLib;
# Discover jobs from directory if specified
discoveredJobs =
if cfg.jobsDir != null
then bosunLib.discoverJobs {
path = cfg.jobsDir;
inherit lib nomadLib;
}
else {};
# Merge discovered with explicit jobs (explicit takes precedence)
allJobModules = discoveredJobs // cfg.jobs;
# Evaluate all jobs with default vars (for static compilation)
evaluatedJobs = lib.mapAttrs (name: jobModule:
bosunLib.evalJob {
job = jobModule;
inherit lib nomadLib;
vars = cfg.defaultVars;
}
) allJobModules;
# Compile jobs to JSON files in nix store (static, no runtime vars)
compiledJobs = bosunLib.compileJobs {
inherit pkgs lib;
jobs = evaluatedJobs;
};
# Job metadata for the manifest
jobManifest = lib.mapAttrs (name: evaluated:
let jobSpec = builtins.head (builtins.attrValues evaluated.job);
in {
type = jobSpec.type or "service";
datacenters = jobSpec.datacenters or [];
parameterized = (builtins.functionArgs allJobModules.${name}) ? vars;
}
) evaluatedJobs;
# The main bosun CLI with runtime variable support
bosunCli = import ./cli {
inherit pkgs lib nomadLib;
jobs = evaluatedJobs;
jobModules = allJobModules;
inherit compiledJobs;
nomadAddress = cfg.nomadAddress;
flakeRef = cfg.flakeRef;
defaultVars = cfg.defaultVars;
};
# Rigging CLI (multi-repo orchestrator)
riggingCli = import ./cli/rigging.nix {inherit pkgs lib;};
in
mkMerge [
# Always available: manifest + rigging
{
packages.bosun-manifest = pkgs.writeText "bosun-manifest.json" (builtins.toJSON {
name = topCfg.meta.name;
hosts = topCfg.hosts;
jobs = if cfg.enable then jobManifest else {};
nomad = lib.optionalAttrs cfg.enable {address = cfg.nomadAddress;};
});
packages.rigging = riggingCli;
}
# Only when Nomad jobs are enabled
(mkIf cfg.enable {
packages.bosun = bosunCli;
apps.bosun = {
type = "app";
program = "${bosunCli}/bin/bosun";
};
# Expose job modules for runtime evaluation with variables
legacyPackages.bosun = {
jobModules = allJobModules;
inherit evaluatedJobs compiledJobs nomadLib;
evalJobWithVars = name: vars:
bosunLib.evalJob {
job = allJobModules.${name};
inherit lib nomadLib vars;
};
};
})
];
});
};
}