Skip to content

Commit

Permalink
workbench: Add nomad backend (single container version)
Browse files Browse the repository at this point in the history
  • Loading branch information
fmaste committed Nov 25, 2022
1 parent 6d6d01d commit d2ce189
Show file tree
Hide file tree
Showing 6 changed files with 971 additions and 0 deletions.
18 changes: 18 additions & 0 deletions nix/pkgs.nix
Expand Up @@ -84,6 +84,9 @@ final: prev: with final; {
supervisord-workbench-nix =
{ workbench ? pkgs.workbench, ... }@args: pkgs.callPackage ./workbench/backend/supervisor.nix args;

nomad-workbench =
{ workbench ? pkgs.workbench, ... }@args: pkgs.callPackage ./workbench/backend/nomad.nix (args // { inherit nix2container; });

all-profiles-json = (workbench.all-profiles{ inherit (supervisord-workbench-nix) backend; }).JSON;

# An instance of the workbench, specialised to the supervisord backend and a profile,
Expand All @@ -103,6 +106,21 @@ final: prev: with final; {
inherit batchName profileName supervisord-workbench cardano-node-rev;
};

nomad-workbench-for-profile =
{ batchName ? customConfig.localCluster.batchName
, profileName ? customConfig.localCluster.profileName
# FIXME: Makes no sense for this backend!
, useCabalRun ? false
, workbenchDevMode ? false
, profiled ? false
, nomad-workbench ? pkgs.callPackage ./workbench/backend/nomad.nix { inherit nix2container; }
, cardano-node-rev ? null
}:
pkgs.callPackage ./workbench/backend/nomad-run.nix
{
inherit batchName profileName nomad-workbench cardano-node-rev;
};

# Disable failing python uvloop tests
python38 = prev.python38.override {
packageOverrides = pythonFinal: pythonPrev: {
Expand Down
81 changes: 81 additions & 0 deletions nix/workbench/backend/nomad-conf.nix
@@ -0,0 +1,81 @@
{ pkgs
# Cardano packages/executables.
, cardano-node, cardano-tracer, tx-generator
# OCI Image builder.
, nix2container
}:

let

# Why `nix2container` instead of the built-in `dockerTools` ?:
# - https://lewo.abesis.fr/posts/nix-build-container-image/
# - https://discourse.nixos.org/t/nix2container-another-dockertools-buildimage-implementation-based-on-skopeo/21688
n2c = nix2container.outputs.packages.x86_64-linux.nix2container;

clusterImage = n2c.buildImage {
name = "registry.workbench.iog.io/cluster";
# Adds `/etc/protocols` and ``/etc/services` to the root directory.
# FIXME: Inside the container still can't resolve `localhost` but can
# resolve WAN domains using public DNS servers.
# Running `bash-5.1# /nix/store/*-glibc-#-bin/bin/getent hosts localhost`
# inside the container returns nothing and python stuff like `supervisord`
# breaks: "error: <class 'socket.gaierror'>, [Errno -2] Name or service not known: file: /nix/store/hb1lzaisgx2m9n29hqhh6yp6hasplq1v-python3-3.9.10/lib/python3.9/socket.py line: 954"
# Further reading for hints:
# https://stackoverflow.com/questions/39965432/docker-container-unable-to-resolve-localhost
copyToRoot = with pkgs; [ iana-etc ];
# All these layers are added to /nix/store, nothing is in `$PATH`.
maxLayers = 25;
layers = with pkgs; [
# Runtime to be able run bash commands from `podman`/`nomad`.
(n2c.buildLayer {deps = [ bashInteractive coreutils ];})
# Supervisor.
(n2c.buildLayer {deps = [ python3Packages.supervisor ];})
# Cardano packages.
(n2c.buildLayer {deps = [ cardano-node ];})
(n2c.buildLayer {deps = [ cardano-tracer ];})
(n2c.buildLayer {deps = [ tx-generator ];})
];
# OCI container specification:
# https://github.com/opencontainers/image-spec/blob/3a7f492d3f1bcada656a7d8c08f3f9bbd05e7406/specs-go/v1/config.go#L24
config = {
# Volumes are mounted as user `0:0`, I have no choice here.
User = "0:0";
# The stanza `WorkingDir` is not used because the config file of
# `supervisord` depends on the working directory.
Entrypoint =
let
entrypoint = pkgs.writeShellApplication {
name = "entrypoint";
runtimeInputs = with pkgs; [
coreutils
bashInteractive
python3Packages.supervisor
];
text = ''
# The SUPERVISOR_NIX variable must be set
[ -z "''${SUPERVISOR_NIX:-}" ] && echo "SUPERVISOR_NIX env var must be set -- aborting" && exit 1
# The SUPERVISORD_CONFIG variable must be set
[ -z "''${SUPERVISORD_CONFIG:-}" ] && echo "SUPERVISORD_CONFIG env var must be set -- aborting" && exit 1
# Create a link to the `supervisor` Nix folder.
# First check if already exists to be able to restart containers.
if ! test -e "$SUPERVISOR_NIX"
then
"${pkgs.coreutils}"/bin/ln -s "${pkgs.python3Packages.supervisor}" "$SUPERVISOR_NIX"
fi
# Start `supervisord` on the foreground.
"${pkgs.python3Packages.supervisor}"/bin/supervisord --nodaemon --configuration "$SUPERVISORD_CONFIG"
'';
};
in
[ "${entrypoint}/bin/entrypoint" ];
};
};

in {

inherit clusterImage;

}
152 changes: 152 additions & 0 deletions nix/workbench/backend/nomad-run.nix
@@ -0,0 +1,152 @@
let
batchNameDefault = "plain";
profileNameDefault = "default-bage";
in
{ pkgs
, cardanoNodePackages
, nomad-workbench
##
, profileName ? profileNameDefault
, batchName ? batchNameDefault
##
, workbenchDevMode ? false
, cardano-node-rev ? "0000000000000000000000000000000000000000"
}:
let
inherit (nomad-workbench) workbench backend cacheDir stateDir basePort;

with-nomad-profile =
{ envArgsOverride ? {} }: ## TODO: envArgsOverride is not used!
workbench.with-profile
{ inherit backend profileName; };

inherit (with-nomad-profile {}) profileNix profile topology genesis;
in
let

inherit (profile.value) era composition monetary;

path = pkgs.lib.makeBinPath path';
path' =
[ cardanoNodePackages.bech32 pkgs.jq pkgs.gnused pkgs.coreutils pkgs.bash pkgs.moreutils
]
## In dev mode, call the script directly:
++ pkgs.lib.optionals (!workbenchDevMode)
[ workbench.workbench ];

interactive-start = pkgs.writeScriptBin "start-cluster" ''
set -euo pipefail
export PATH=$PATH:${path}
unset WB_MODE_CABAL=
wb start \
--batch-name ${batchName} \
--profile-name ${profileName} \
--profile ${profile} \
--cache-dir ${cacheDir} \
--base-port ${toString basePort} \
''${WB_MODE_CABAL:+--cabal} \
"$@"
'';

interactive-stop = pkgs.writeScriptBin "stop-cluster" ''
set -euo pipefail
wb finish "$@"
'';

interactive-restart = pkgs.writeScriptBin "restart-cluster" ''
set -euo pipefail
wb run restart "$@" && \
echo "workbench: alternate command for this action: wb run restart" >&2
'';

nodeBuildProduct =
name:
"report ${name}-log $out ${name}/stdout";

profile-run =
{ trace ? false }:
let
inherit
(with-nomad-profile
{ envArgsOverride = { cacheDir = "./cache"; stateDir = "./"; }; })
profileNix profile topology genesis;

run = pkgs.runCommand "workbench-run-nomad-${profileName}"
{ requiredSystemFeatures = [ "benchmark" ];
nativeBuildInputs = with cardanoNodePackages; with pkgs; [
bash
bech32
coreutils
gnused
jq
moreutils
nixWrapped
pstree
# TODO: nomad
workbench.workbench
zstd
];
}
''
mkdir -p $out/{cache,nix-support}
cd $out
export HOME=$out
export WB_BACKEND=nomad
export CARDANO_NODE_SOCKET_PATH=$(wb backend get-node-socket-path ${stateDir} node-0)
cmd=(
wb
${pkgs.lib.optionalString trace "--trace"}
start
--profile-name ${profileName}
--profile ${profile}
--topology ${topology}
--genesis-cache-entry ${genesis}
--batch-name smoke-test
--base-port ${toString basePort}
--node-source ${cardanoNodePackages.cardano-node.src.origSrc}
--node-rev ${cardano-node-rev}
--cache-dir ./cache
)
echo "''${cmd[*]}" > $out/wb-start.sh
time "''${cmd[@]}" 2>&1 |
tee $out/wb-start.log
## Convert structure from $out/run/RUN-ID/* to $out/*:
rm -rf cache
rm -f run/{current,-current}
find $out -type s | xargs rm -f
run=$(cd run; ls)
(cd run; tar c $run --zstd) > archive.tar.zst
mv run/$run/* .
rmdir run/$run run
cat > $out/nix-support/hydra-build-products <<EOF
report workbench-log $out wb-start.log
report meta $out meta.json
${pkgs.lib.concatStringsSep "\n"
(map nodeBuildProduct (__attrNames profileNix.node-specs.value))}
report archive-tar-zst $out archive.tar.zst
EOF
echo "workbench-test: completed run $run"
'';
in
run // {
analysis = workbench.run-analysis { inherit pkgs workbench profileNix run; };
};
in
{
inherit stateDir;
inherit workbench nomad-workbench;
inherit (nomad-workbench) backend;
inherit profileNix profile topology genesis;
inherit interactive-start interactive-stop interactive-restart;
inherit profile-run;
}
78 changes: 78 additions & 0 deletions nix/workbench/backend/nomad.nix
@@ -0,0 +1,78 @@
let
basePort = 30000;
cacheDirDefault = "${__getEnv "HOME"}/.cache/cardano-workbench";
stateDir = "run/current";
in
{ pkgs
, lib, nix2container
, workbench
##
, cacheDir ? cacheDirDefault
, extraBackendConfig ? {}
## `useCabalRun` not used here like in `supervisor.nix`.
, enableEKG ? true
##
, ...
}:
let
backend =
rec
{ name = "nomad";

services-config = import ./services-config.nix {inherit lib workbench basePort stateDir; useCabalRun = false; inherit enableEKG;};

extraShellPkgs = with pkgs; [
# https://docs.podman.io/en/latest/markdown/podman.1.html#rootless-mode
podman
# Was not needed even thou it says so!
# https://docs.podman.io/en/latest/markdown/podman.1.html#note-unsupported-file-systems-in-rootless-mode
# fuse-overlayfs
nomad
nomad-driver-podman
];

materialise-profile =
{ profileNix }:
let
supervisorConfPath =
import ./supervisor-conf.nix
{ inherit (profileNix) node-services;
inherit
pkgs lib stateDir
basePort
extraBackendConfig;
};
nomadConf =
import ./nomad-conf.nix
{ inherit pkgs;
inherit
(pkgs.cardanoNodePackages)
cardano-node cardano-tracer tx-generator;
inherit nix2container;
};
in pkgs.runCommand "workbench-backend-output-${profileNix.name}-${name}"
(rec {
inherit supervisorConfPath;
# All In One
clusterImage = nomadConf.clusterImage;
clusterImageCopyToPodman = clusterImage.copyToPodman;
clusterImageName = clusterImage.imageName;
clusterImageTag = clusterImage.imageTag;
})
''
mkdir $out
ln -s $supervisorConfPath $out/supervisor.conf
ln -s $clusterImage $out/clusterImage
echo $clusterImageName > $out/clusterImageName
echo $clusterImageTag > $out/clusterImageTag
ln -s $clusterImageCopyToPodman/bin/copy-to-podman $out/clusterImageCopyToPodman
'';
};
in
{
inherit cacheDir stateDir basePort;
inherit workbench;
inherit backend;
}

0 comments on commit d2ce189

Please sign in to comment.