{
nixpkgs,
mkCommand,
}: let
l = nixpkgs.lib // builtins;
/*
Use the `nomadJobsManifest` Blocktype for rendering job descriptions
for the Nomad Cluster scheduler. Each named attribtute-set under the
block contains a valid Nomad job description, written in Nix.
Available actions:
- render
- deploy
- explore
*/
nomadJobManifests = name: {
__functor = import ./__functor.nix;
inherit name;
type = "nomadJobManifests";
actions = {
system,
fragment,
fragmentRelPath,
target,
}: let
fx = "${nixpkgs.legacyPackages.${system}.fx}/bin";
nomad = "${nixpkgs.legacyPackages.${system}.nomad}/bin";
jq = "${nixpkgs.legacyPackages.${system}.jq}/bin";
job = baseNameOf fragmentRelPath;
nixExpr = ''
x: let
job = builtins.mapAttrs (_: v: v // {meta = v.meta or {} // {rev = "\"$(git rev-parse --short HEAD)\"";};}) x.job;
in
builtins.toFile \"${job}.json\" (builtins.unsafeDiscardStringContext (builtins.toJSON {inherit job;}))
'';
layout = ''
if test -z "$PRJ_ROOT"; then
echo "PRJ_ROOT is not set. Action aborting."
exit 1
fi
if test -z "$PRJ_DATA_DIR"; then
echo "PRJ_DATA_DIR is not set. Action aborting."
exit 1
fi
job_path="$PRJ_DATA_DIR/${dirOf fragmentRelPath}/${job}.json"
# use Nomad bin in path if it exists, and only fallback on nixpkgs if it doesn't
PATH="$PATH:${nomad}"
'';
render = ''
if test -z "$PRJ_ROOT"; then
echo "PRJ_ROOT is not set. Action aborting."
exit 1
fi
echo "Rendering to $job_path..."
# use `PRJ_ROOT` to capture dirty state
if ! out="$(nix eval --no-allow-dirty --raw $PRJ_ROOT\#${fragment} --apply "${nixExpr}")"; then
>&2 echo "error: Will not render jobs from a dirty tree, otherwise we cannot keep good track of deployment history."
exit 1
fi
nix build "$out" --out-link "$job_path" 2>/dev/null
if status=$(nomad validate "$job_path"); then
echo "$status for $job_path"
fi
'';
in [
/*
The `render` action will take this Nix job descrition, convert it to JSON,
inject the git revision validate the manifest, after which it can be run or
planned with the Nomad cli or the `deploy` action.
*/
(mkCommand system {
name = "render";
description = "build the JSON job description";
command =
# bash
''
set -e
${layout}
${render}
'';
})
(mkCommand system {
name = "deploy";
description = "Deploy the job to Nomad";
command =
# bash
''
set -e
${layout}
PATH=$PATH:${jq}
if ! [[ -h "$job_path" ]] \
|| [[ "$(jq -r '.job[].meta.rev' "$job_path")" != "$(git rev-parse --short HEAD)" ]]
then ${render}
fi
if ! plan_results=$(nomad plan -force-color "$job_path"); then
echo "$plan_results"
cmd="$(echo "$plan_results" | grep 'nomad job run -check-index')"
# prompt user interactiely except in CI
if ! [[ -v CI ]]; then
read -rp "Deploy this job? (y/N)" deploy
case "$deploy" in
[Yy])
eval "$cmd"
;;
*)
echo "Exiting without deploying"
;;
esac
else
eval "$cmd"
fi
else
echo "Job hasn't changed since last deployment, nothing to deploy"
fi
'';
})
(mkCommand system {
name = "explore";
description = "interactively explore the Job defintion";
command =
# bash
''
set -e
${layout}
if ! [[ -h "$job_path" ]]; then
${render}
fi
PATH=$PATH:${fx}
fx "$job_path"
'';
})
];
};
in
nomadJobManifests