nix-processmgmt/nixproc/create-managed-process/systemd/create-systemd-service.nix

118 lines
3.7 KiB
Nix

{ writeTextFile
, stdenv
, createCredentials
, basePackages
# Specifies whether user changing functionality should be disabled or not
, forceDisableUserChange ? false
# Prefix that is in front of all systemd units generated by this function
, prefix ? "nix-process-"
}:
{
# A name that identifies the process instance
name
# An attribute set specifying arbitrary environment variables
, environment ? {}
# List of supervisord services that this configuration depends on.
# These properties are translated to Wants= and After= properties to ensure
# proper activation ordering and that the dependencies are started first
, dependencies ? []
# Specifies which packages need to be in the PATH
, path ? []
# Specifies which groups and users that need to be created.
, credentials ? {}
# The remainder of the parameters directly get translated to sections and properties
# See: https://www.freedesktop.org/software/systemd/man/systemd.unit.html
# and: https://www.freedesktop.org/software/systemd/man/systemd.service.html
, ...
}@args:
let
sections = removeAttrs args [ "name" "environment" "dependencies" "path" "credentials" ];
_environment = {
PATH = builtins.concatStringsSep ":" (map (package: "${package}/bin") (basePackages ++ path));
} // environment;
generateEnvironmentVariables = environment:
stdenv.lib.concatMapStrings (name:
let
value = builtins.getAttr name _environment;
in
''Environment=${name}=${toString value}
''
) (builtins.attrNames _environment);
mapDependencies = dependencies:
if dependencies == [] then ""
else
''
Wants=${toString (map (dependency: "${dependency.name}.service") dependencies)}
After=${toString (map (dependency: "${dependency.name}.service") dependencies)}
'';
generateSection = {title, properties}:
''
[${title}]
${stdenv.lib.concatMapStrings (name:
let
value = builtins.getAttr name properties;
in
if forceDisableUserChange && (name == "User" || name == "Group") then "" else # Don't change user privileges when we force it to be disabled
''${name}=${toString value}
''
) (builtins.attrNames properties)}''
+ (if title == "Service" then generateEnvironmentVariables _environment else "")
+ (if title == "Unit" then mapDependencies dependencies else "");
generateSections = sections:
stdenv.lib.concatMapStrings (title:
let
properties = builtins.getAttr title sections;
in
generateSection {
inherit title properties;
}
) (builtins.attrNames sections);
service = writeTextFile {
name = "${name}.service";
text = ''
${generateSections sections}
${stdenv.lib.optionalString (!(sections ? Service) && _environment != {}) ''
[Service]
${generateEnvironmentVariables _environment}''}
${stdenv.lib.optionalString (!(sections ? Unit) && dependencies != []) ''
[Unit]
${mapDependencies dependencies}
''}
'';
};
credentialsSpec = if credentials == {} || forceDisableUserChange then null else createCredentials credentials;
in
stdenv.mkDerivation {
name = "${prefix}${name}";
buildCommand = ''
mkdir -p $out/etc/systemd/system
ln -s ${service} $out/etc/systemd/system/${prefix}${name}.service
${stdenv.lib.optionalString (dependencies != []) ''
mkdir -p $out/etc/systemd/system/${prefix}${name}.service.wants
${stdenv.lib.concatMapStrings (dependency: ''
ln -s ${dependency}/etc/systemd/system/${dependency.name}.service $out/etc/systemd/system/${prefix}${name}.service.wants
'') dependencies}
''}
${stdenv.lib.optionalString (credentialsSpec != null) ''
ln -s ${credentialsSpec}/dysnomia-support $out/dysnomia-support
''}
'';
}