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>
202 lines
6.1 KiB
Nix
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;
|
|
};
|
|
};
|
|
})
|
|
];
|
|
});
|
|
};
|
|
}
|