WiP! Synit support

This commit is contained in:
Emery Hemingway 2023-11-24 19:13:04 +02:00
parent 0e9ec77cc6
commit b4302c3fe8
9 changed files with 474 additions and 0 deletions

View File

@ -34,6 +34,7 @@ Currently, the following process managers are supported:
* `cygrunsrv`: Cygwin's [cygrunsrv](http://web.mit.edu/cygwin/cygwin_v1.3.2/usr/doc/Cygwin/cygrunsrv.README) * `cygrunsrv`: Cygwin's [cygrunsrv](http://web.mit.edu/cygwin/cygwin_v1.3.2/usr/doc/Cygwin/cygrunsrv.README)
* `s6-rc`: [s6-rc](https://skarnet.org/software/s6-rc) for managing services * `s6-rc`: [s6-rc](https://skarnet.org/software/s6-rc) for managing services
supervised by [s6](https://skarnet.org/software/s6) supervised by [s6](https://skarnet.org/software/s6)
* `synit`: [Synit](https://synit.org/)
It can also work with the following solutions that are technically not It can also work with the following solutions that are technically not
categorized as process managers (but can still be used as such): categorized as process managers (but can still be used as such):

View File

@ -0,0 +1,37 @@
{ pkgs ? import <nixpkgs> { inherit system; }
, system ? builtins.currentSystem
, stateDir ? "/var"
, runtimeDir ? "${stateDir}/run"
, logDir ? "${stateDir}/log"
, cacheDir ? "${stateDir}/cache"
, spoolDir ? "${stateDir}/spool"
, lockDir ? "${stateDir}/lock"
, libDir ? "${stateDir}/lib"
, tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
, forceDisableUserChange ? false
, callingUser ? null
, callingGroup ? null
, extraParams ? {}
, exprFile ? null
}@args:
let
processesFun = import exprFile;
processesFormalArgs = builtins.functionArgs processesFun;
processesArgs = builtins.intersectAttrs processesFormalArgs (args // {
processManager = "synit";
} // extraParams);
processes = if exprFile == null then {} else processesFun processesArgs;
in
pkgs.buildEnv {
name = "synit";
paths = map (processName:
let
process = builtins.getAttr processName processes;
in
process.pkg
) (builtins.attrNames processes);
}

View File

@ -0,0 +1,30 @@
{ stdenv, lib, execline, writeTextFile }:
{ name, description, initialize, daemon, daemonArgs, instanceName, pidFile
, foregroundProcess, foregroundProcessArgs, path, environment, directory, umask
, nice, user, dependencies, credentials, overrides, postInstall }:
let
util = import ../util { inherit lib; };
generator = import ./preserves-generator.nix { inherit lib; };
toPreserves = generator.toPreserves { };
escapeArgs = args:
lib.concatMapStringsSep " "
(arg: ''"${lib.replaceStrings [ ''"'' ] [ ''\"'' ] (toString arg)}"'') args;
processSpec = {
argv = "${daemon} ${toString daemonArgs}";
env = environment;
} // (lib.attrsets.optionalAttrs (directory != null) { dir = directory; });
in writeTextFile {
name = "services-${name}";
destination = "/services/${name}.pr";
text = ''
<metadata <daemon ${name}> { description: "${description}" }>
<require-service <daemon ${name}>>
<daemon ${name} ${toPreserves processSpec}>
'';
}

View File

@ -0,0 +1,52 @@
{ lib }:
let inherit (lib) isAttrs isBool isFunction isList;
in rec {
/* Generates text-encoded Preserves from an arbitrary value.
Records are generated for lists with a final element in
the form of `{ record = «label»; }`.
Type: toPreserves :: a -> string
Example:
toPreserves { } [{ a = 0; b = 1; } "c" [ true false ] { record = "foo"; }]
=> "<foo { a: 0 b: 1 } \"c\" [ #t #f ]>"
*/
toPreserves = { }@args:
let
toPreserves' = toPreserves args;
concatItems = toString;
recordLabel = list:
with builtins;
let len = length list;
in if len == 0 then
null
else
let end = elemAt list (len - 1);
in if (isAttrs end) && (attrNames end) == [ "record" ] then
end
else
null;
in v:
if isAttrs v then
"{ ${
concatItems
(lib.attrsets.mapAttrsToList (key: val: "${key}: ${toPreserves' val}")
v)
} }"
else if isList v then
let label = recordLabel v;
in if label == null then
"[ ${concatItems (map toPreserves' v)} ]"
else
"<${label.record} ${concatItems (map toPreserves' (lib.lists.init v))}>"
else if isBool v then
(if v then "#t" else "#f")
else if isFunction v then
abort "generators.toPreserves: cannot convert a function to Preserves"
else if isNull v then
"null"
else
builtins.toJSON v;
}

View File

@ -113,6 +113,11 @@ let
inherit (pkgs) stdenv writeTextFile lib execline s6; inherit (pkgs) stdenv writeTextFile lib execline s6;
inherit s6-rc basePackages tmpDir runtimeDir forceDisableUserChange; inherit s6-rc basePackages tmpDir runtimeDir forceDisableUserChange;
}; };
generateSynitService = import ../../backends/synit/generate-synit-service.nix {
inherit (pkgs) stdenv lib execline writeTextFile;
};
in in
import ../agnostic/create-managed-process.nix { import ../agnostic/create-managed-process.nix {
inherit processManager; inherit processManager;
@ -128,5 +133,6 @@ import ../agnostic/create-managed-process.nix {
supervisord = generateSupervisordProgram; supervisord = generateSupervisordProgram;
systemd = generateSystemdService; systemd = generateSystemdService;
sysvinit = generateSystemVInitScript; sysvinit = generateSystemVInitScript;
synit = generateSynitService;
}; };
} }

View File

@ -47,6 +47,10 @@ rec {
inherit (pkgs) stdenv getopt; inherit (pkgs) stdenv getopt;
}; };
synit = import ./synit {
inherit (pkgs) stdenv getopt;
};
systemd = import ./systemd { systemd = import ./systemd {
inherit (pkgs) stdenv getopt; inherit (pkgs) stdenv getopt;
}; };

20
tools/synit/default.nix Normal file
View File

@ -0,0 +1,20 @@
{ stdenv, getopt }:
stdenv.mkDerivation {
name = "nixproc-synit-tools";
buildCommand = ''
mkdir -p $out/bin
sed -e "s|/bin/bash|$SHELL|" \
-e "s|@getopt@|${getopt}/bin/getopt|" \
-e "s|@commonchecks@|${../commonchecks}|" \
${./nixproc-synit-switch.in} > $out/bin/nixproc-synit-switch
chmod +x $out/bin/nixproc-synit-switch
sed -e "s|/bin/bash|$SHELL|" \
-e "s|@getopt@|${getopt}/bin/getopt|" \
-e "s|@commonchecks@|${../commonchecks}|" \
${./nixproc-synit-deploy.in} > $out/bin/nixproc-synit-deploy
chmod +x $out/bin/nixproc-synit-deploy
'';
}

View File

@ -0,0 +1,132 @@
#!/bin/bash -e
showUsage()
{
me="$(basename "$0")"
cat <<EOF
Usage: $me [OPTION] PATH
Deploys a prebuilt Synit configuration profile.
Options:
-p, --profile=NAME Name of the Nix profile that stores the sysvinit scripts
(defaults to: processes)
-o, --old-profile=PATH
Path to the previously deployed Nix profile (by default,
it gets auto detected)
--state-dir Changes the directory in which the state of the
processes are stored
--runtime-dir Changes the directory in which the PID files are stored
--log-dir Changes the directory in which the log files are stored
--tmp-dir Changes the directory in which temp files are stored
--cache-dir Changes the directory in which cache files are stored
--spool-dir Changes the directory in which spool files are stored
--lock-dir Changes the directory in which lock files are stored
--lib-dir Changes the directory in which state files are stored
--force-disable-user-change
Forces to not create users, groups or change user
permissions
--runlevel=LEVEL Specifies which runlevel to activate (defaults to the
runlevel of the system)
-h, --help Shows the usage of this command
Environment:
NIX_STATE_DIR Overrides the location of the Nix state directory
NIXPROC_STATE_DIR Changes the directory in which the state of the
processes is stored
NIXPROC_RUNTIME_DIR Changes the directory in which the PID files are stored
NIXPROC_LOG_DIR Changes the directory in which log files are stored
NIXPROC_TMP_DIR Changes the directory in which temp files are stored
NIXPROC_CACHE_DIR Changes the directory in which cache files are stored
NIXPROC_SPOOL_DIR Changes the directory in which spool files are stored
NIXPROC_LOCK_DIR Changes the directory in which lock files are stored
NIXPROC_LIB_DIR Changes the directory in which state files are stored
NIXPROC_FORCE_DISABLE_USER_CHANGE
Forces to not create users, groups or change user
permissions
EOF
}
# Parse valid argument options
PARAMS=`@getopt@ -n $0 -o p:o:h -l profile:,old-profile:,state-dir:,runtime-dir:,log-dir:,tmp-dir:,cache-dir:,spool-dir:,lock-dir:,lib-dir:,force-disable-user-change,runlevel:,help -- "$@"`
if [ $? != 0 ]
then
showUsage
exit 1
fi
# Evaluate valid options
eval set -- "$PARAMS"
while [ "$1" != "--" ]
do
case "$1" in
-p|--profile)
profile="$2"
;;
-o|--old-profile)
oldProfilePath="$2"
;;
--state-dir)
stateDirArg="--state-dir $2"
;;
--runtime-dir)
runtimeDirArg="--runtime-dir $2"
;;
--log-dir)
logDirArg="--log-dir $2"
;;
--tmp-dir)
tmpDirArg="--tmp-dir $2"
;;
--cache-dir)
cacheDirArg="--cache-dir $2"
;;
--spool-dir)
spoolDirArg="--spool-dir $2"
;;
--lock-dir)
lockDirArg="--lock-dir $2"
;;
--lib-dir)
libDirArg="--lib-dir $2"
;;
--force-disable-user-change)
forceDisableUserChangeArg="--force-disable-user-change"
;;
--runlevel)
runlevel="$2"
;;
-h|--help)
showUsage
exit 0
;;
esac
shift
done
shift
profilePath="$1"
# Validate the given options
source @commonchecks@
checkNixStateDir
checkProfile
composeOldProfilePath
# TODO
# Delete obsolete users and groups
deleteObsoleteUsers
deleteObsoleteGroups
# Set new profile
setNixProfile

View File

@ -0,0 +1,192 @@
#!/bin/bash
set -e
shopt -s nullglob
# Shows the usage of this command to the user
showUsage()
{
me="$(basename "$0")"
cat <<EOF
Usage: $me [OPTION] [PATH]
or: $me --undeploy [OPTION]
or: $me --rollback [OPTION]
or: $me --switch-generation NUM [OPTION]
or: $me --list-generations [OPTION]
or: $me --delete-generations NUM [OPTION]
or: $me --delete-all-generations NUM [OPTION]
This command repopulates a folder with Synit configuration files and updates
the configuration so that obsolete services will be stoppped and new services
will be started.
If the provided path is a file then it is considered a Nix expression that
produces a Nix profile. If the provided path is a directory, then it is
considered a pre-built Nix profile.
Options:
--undeploy Undeploys all previously deployed processes
--rollback Rolls back to the previous deployment
--switch-generation=NUM
Switches to a previous deployment generation
--list-generations
Lists all profile generations of the current deployment
--delete-generations=NUM
Deletes the specified generations. The number can
correspond to generation numbers, days (d postfix) or
'old'.
--delete-all-generations
Deletes all profile generations. This is useful when a
deployment has been discarded
-p, --profile=NAME Name of the Nix profile that stores the sysvinit scripts
(defaults to: processes)
-o, --old-profile=PATH
Path to the previously deployed Nix profile (by default,
it gets auto detected)
--runlevel=LEVEL Specifies which runlevel to activate (defaults to the
runlevel of the system)
--state-dir Changes the directory in which the state of the
processes are stored
--runtime-dir Changes the directory in which the PID files are stored
--log-dir Changes the directory in which the log files are stored
--tmp-dir Changes the directory in which temp files are stored
--cache-dir Changes the directory in which cache files are stored
--spool-dir Changes the directory in which spool files are stored
--lock-dir Changes the directory in which lock files are stored
--lib-dir Changes the directory in which state files are stored
--force-disable-user-change
Forces to not create users, groups or change user
permissions
--show-trace Shows a trace of the output
--extra-params=PARAMS
A string with an attribute set in the Nix expression
language propagating extra parameters to the input models
-h, --help Shows the usage of this command
Environment:
NIX_STATE_DIR Overrides the location of the Nix state directory
NIXPROC_PROCESSES Path to a processes model
NIXPROC_STATE_DIR Changes the directory in which the state of the
processes is stored
NIXPROC_RUNTIME_DIR Changes the directory in which the PID files are stored
NIXPROC_LOG_DIR Changes the directory in which log files are stored
NIXPROC_TMP_DIR Changes the directory in which temp files are stored
NIXPROC_CACHE_DIR Changes the directory in which cache files are stored
NIXPROC_SPOOL_DIR Changes the directory in which spool files are stored
NIXPROC_LOCK_DIR Changes the directory in which lock files are stored
NIXPROC_LIB_DIR Changes the directory in which state files are stored
NIXPROC_FORCE_DISABLE_USER_CHANGE
Forces to not create users, groups or change user
permissions
EOF
}
# Parse valid argument options
PARAMS=`@getopt@ -n $0 -o p:o:h -l undeploy,rollback,switch-generation:,list-generations,delete-generations:,delete-all-generations,profile:,old-profile:,state-dir:,runtime-dir:,log-dir:,tmp-dir:,cache-dir:,spool-dir:,lock-dir:,lib-dir:,force-disable-user-change,runlevel:,show-trace,extra-params:,help -- "$@"`
if [ $? != 0 ]
then
showUsage
exit 1
fi
# Evaluate valid options
eval set -- "$PARAMS"
while [ "$1" != "--" ]
do
case "$1" in
--undeploy)
undeploy=1
;;
--rollback)
operation="switchGenerations"
;;
--switch-to-generation)
operation="switchGenerations"
generationId=$2
;;
--list-generations)
operation="listGenerations"
;;
--delete-generations)
operation="deleteGenerations"
generations="$2"
;;
--delete-all-generations)
operation="deleteAllGenerations"
;;
-p|--profile)
profileArg="-p $2"
;;
-o|--old-profile)
oldProfileArg="-o $2"
;;
--state-dir)
stateDirArg="--state-dir $2"
;;
--runtime-dir)
runtimeDirArg="--runtime-dir $2"
;;
--log-dir)
logDirArg="--log-dir $2"
;;
--tmp-dir)
tmpDirArg="--tmp-dir $2"
;;
--cache-dir)
cacheDirArg="--cache-dir $2"
;;
--spool-dir)
spoolDirArg="--spool-dir $2"
;;
--lock-dir)
lockDirArg="--lock-dir $2"
;;
--lib-dir)
libDirArg="--lib-dir $2"
;;
--force-disable-user-change)
forceDisableUserChangeArg="--force-disable-user-change"
;;
--runlevel)
runlevel="$2"
runlevelArg="--runlevel $runlevel"
;;
--show-trace)
showTraceArg="--show-trace"
;;
--extra-params)
extraParamsArg=("--extra-params" "$2")
;;
-h|--help)
showUsage
exit 0
;;
esac
shift
done
shift
# Validate the given options
source @commonchecks@
checkProcessesFile "$1"
checkNixStateDir
checkProfile
composeProfileBaseDir
# Execute the deployment
deploy()
{
nixproc-synit-deploy $runlevelArg $profileArg $oldProfileArg $profilePath $stateDirArg $runtimeDirArg $logDirArg $tmpDirArg $cacheDirArg $spoolDirArg $lockDirArg $libDirArg $forceDisableUserChange
}
executeDeploymentOperation synit