Share option definitions between the systemd and Upstart compatibility modules

This commit is contained in:
Eelco Dolstra 2012-08-06 11:45:59 -04:00
parent f74ffe3550
commit 9f9ae7c7e9
4 changed files with 145 additions and 213 deletions

View file

@ -36,7 +36,7 @@ let
''; '';
pre84 = versionOlder (builtins.parseDrvName postgresql.name).version "8.4"; pre84 = versionOlder (builtins.parseDrvName postgresql.name).version "8.4";
in in
{ {
@ -139,7 +139,7 @@ in
host all all 127.0.0.1/32 md5 host all all 127.0.0.1/32 md5
host all all ::1/128 md5 host all all ::1/128 md5
''; '';
users.extraUsers = singleton users.extraUsers = singleton
{ name = "postgres"; { name = "postgres";
description = "PostgreSQL server user"; description = "PostgreSQL server user";
@ -181,20 +181,19 @@ in
postStart = postStart =
'' ''
while ! psql postgres -c ""; do while ! psql postgres -c ""; do
stop_check
sleep 1 sleep 1
done done
''; '';
extraConfig = serviceConfig =
'' ''
# Shut down Postgres using SIGINT ("Fast Shutdown mode"). See # Shut down Postgres using SIGINT ("Fast Shutdown mode"). See
# http://www.postgresql.org/docs/current/static/server-shutdown.html # http://www.postgresql.org/docs/current/static/server-shutdown.html
kill signal INT KillSignal=SIGINT
# Give Postgres a decent amount of time to clean up after # Give Postgres a decent amount of time to clean up after
# receiving Upstart's SIGINT. # receiving systemd's SIGINT.
kill timeout 60 TimeoutSec=60
''; '';
}; };

View file

@ -0,0 +1,101 @@
{ config, pkgs }:
with pkgs.lib;
{
serviceOptions = {
description = mkOption {
default = "";
types = types.uniq types.string;
description = "Description of this unit used in systemd messages and progress indicators.";
};
requires = mkOption {
default = [];
types = types.listOf types.string;
description = ''
Start the specified units when this unit is started, and stop
this unit when the specified units are stopped or fail.
'';
};
wants = mkOption {
default = [];
types = types.listOf types.string;
description = ''
Start the specified units when this unit is started.
'';
};
after = mkOption {
default = [];
types = types.listOf types.string;
description = ''
If the specified units are started at the same time as
this unit, delay this unit until they have started.
'';
};
before = mkOption {
default = [];
types = types.listOf types.string;
description = ''
If the specified units are started at the same time as
this unit, delay them until this unit has started.
'';
};
wantedBy = mkOption {
default = [];
types = types.listOf types.string;
description = "Units that want (i.e. depend on) this unit.";
};
environment = mkOption {
default = {};
type = types.attrs;
example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; };
description = "Environment variables passed to the services's processes.";
};
path = mkOption {
default = [];
apply = ps: "${makeSearchPath "bin" ps}:${makeSearchPath "sbin" ps}";
description = ''
Packages added to the service's <envar>PATH</envar>
environment variable. Both the <filename>bin</filename>
and <filename>sbin</filename> subdirectories of each
package are added.
'';
};
serviceConfig = mkOption {
default = "";
type = types.string;
description = ''
Contents of the <literal>[Service]</literal> section of the unit.
See <citerefentry><refentrytitle>systemd.unit</refentrytitle>
<manvolnum>5</manvolnum></citerefentry> for details.
'';
};
script = mkOption {
type = types.uniq types.string;
default = "";
description = "Shell commands executed as the service's main process.";
};
preStart = mkOption {
type = types.string;
default = "";
description = ''
Shell commands executed before the service's main process
is started.
'';
};
};
}

View file

@ -1,122 +1,10 @@
{ config, pkgs, ... }: { config, pkgs, ... }:
with pkgs.lib; with pkgs.lib;
with import ./systemd-unit-options.nix { inherit config pkgs; };
let let
servicesOptions = {
description = mkOption {
default = "";
types = types.uniq types.string;
description = "Description of this unit used in systemd messages and progress indicators.";
};
requires = mkOption {
default = [];
types = types.listOf types.string;
description = ''
Start the specified units when this unit is started, and stop
this unit when the specified units are stopped or fail.
'';
};
wants = mkOption {
default = [];
types = types.listOf types.string;
description = ''
Start the specified units when this unit is started.
'';
};
after = mkOption {
default = [];
types = types.listOf types.string;
description = ''
If the specified units are started at the same time as
this unit, delay this unit until they have started.
'';
};
before = mkOption {
default = [];
types = types.listOf types.string;
description = ''
If the specified units are started at the same time as
this unit, delay them until this unit has started.
'';
};
wantedBy = mkOption {
default = [];
types = types.listOf types.string;
description = "Start this unit when the specified units are started.";
};
environment = mkOption {
default = {};
type = types.attrs;
example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; };
description = "Environment variables passed to the services's processes.";
};
path = mkOption {
default = [];
apply = ps: "${makeSearchPath "bin" ps}:${makeSearchPath "sbin" ps}";
description = ''
Packages added to the service's <envar>PATH</envar>
environment variable. Both the <filename>bin</filename>
and <filename>sbin</filename> subdirectories of each
package are added.
'';
};
serviceConfig = mkOption {
default = "";
type = types.string;
description = ''
Contents of the <literal>[Service]</literal> section of the unit.
See <citerefentry><refentrytitle>systemd.unit</refentrytitle>
<manvolnum>5</manvolnum></citerefentry> for details.
'';
};
script = mkOption {
type = types.uniq types.string;
default = "";
description = "Shell commands executed as the service's main process.";
};
preStart = mkOption {
type = types.string;
default = "";
description = ''
Shell commands executed before the service's main process
is started.
'';
};
};
servicesConfig = { name, config, ... }: {
config = {
# Default path for systemd services. Should be quite minimal.
path =
[ pkgs.coreutils
pkgs.findutils
pkgs.gnugrep
pkgs.gnused
systemd
];
};
};
cfg = config.boot.systemd; cfg = config.boot.systemd;
systemd = pkgs.systemd; systemd = pkgs.systemd;
@ -178,7 +66,7 @@ let
# Utmp maintenance. # Utmp maintenance.
"systemd-update-utmp-runlevel.service" "systemd-update-utmp-runlevel.service"
"systemd-update-utmp-shutdown.service" "systemd-update-utmp-shutdown.service"
# Filesystems. # Filesystems.
"systemd-fsck@.service" "systemd-fsck@.service"
"systemd-fsck-root.service" "systemd-fsck-root.service"
@ -260,6 +148,19 @@ let
makeJobScript = name: content: "${pkgs.writeScriptBin name content}/bin/${name}"; makeJobScript = name: content: "${pkgs.writeScriptBin name content}/bin/${name}";
serviceConfig = { name, config, ... }: {
config = {
# Default path for systemd services. Should be quite minimal.
path =
[ pkgs.coreutils
pkgs.findutils
pkgs.gnugrep
pkgs.gnused
systemd
];
};
};
serviceToUnit = name: def: serviceToUnit = name: def:
{ inherit (def) wantedBy; { inherit (def) wantedBy;
@ -277,7 +178,7 @@ let
[Service] [Service]
Environment=PATH=${def.path} Environment=PATH=${def.path}
${concatMapStrings (n: "Environment=${n}=${getAttr n def.environment}\n") (attrNames def.environment)} ${concatMapStrings (n: "Environment=${n}=${getAttr n def.environment}\n") (attrNames def.environment)}
${optionalString (def.preStart != "") '' ${optionalString (def.preStart != "") ''
ExecStartPre=${makeJobScript "${name}-prestart.sh" '' ExecStartPre=${makeJobScript "${name}-prestart.sh" ''
#! ${pkgs.stdenv.shell} -e #! ${pkgs.stdenv.shell} -e
@ -297,7 +198,7 @@ let
}; };
nixosUnits = mapAttrsToList makeUnit cfg.units; nixosUnits = mapAttrsToList makeUnit cfg.units;
units = pkgs.runCommand "units" { preferLocalBuild = true; } units = pkgs.runCommand "units" { preferLocalBuild = true; }
'' ''
mkdir -p $out mkdir -p $out
@ -310,7 +211,7 @@ let
ln -s $fn $out/ ln -s $fn $out/
fi fi
done done
for i in ${toString upstreamWants}; do for i in ${toString upstreamWants}; do
fn=${systemd}/example/systemd/system/$i fn=${systemd}/example/systemd/system/$i
[ -e $fn ] [ -e $fn ]
@ -322,7 +223,7 @@ let
if ! [ -e $y ]; then rm -v $y; fi if ! [ -e $y ]; then rm -v $y; fi
done done
done done
for i in ${toString nixosUnits}; do for i in ${toString nixosUnits}; do
ln -s $i/* $out/ ln -s $i/* $out/
done done
@ -337,7 +238,7 @@ let
ln -s ../getty@tty1.service $out/multi-user.target.wants/ ln -s ../getty@tty1.service $out/multi-user.target.wants/
''; # */ ''; # */
in in
{ {
@ -350,29 +251,24 @@ in
description = "Definition of systemd units."; description = "Definition of systemd units.";
default = {}; default = {};
type = types.attrsOf types.optionSet; type = types.attrsOf types.optionSet;
options = { options = {
text = mkOption { text = mkOption {
types = types.uniq types.string; types = types.uniq types.string;
description = "Text of this systemd unit."; description = "Text of this systemd unit.";
}; };
wantedBy = mkOption { wantedBy = mkOption {
default = []; default = [];
types = types.listOf types.string; types = types.listOf types.string;
description = "Units that want (i.e. depend on) this unit."; description = "Units that want (i.e. depend on) this unit.";
}; };
}; };
}; };
boot.systemd.services = mkOption { boot.systemd.services = mkOption {
description = "Definition of systemd services."; description = "Definition of systemd services.";
default = {}; default = {};
type = types.attrsOf types.optionSet; type = types.attrsOf types.optionSet;
options = [ servicesOptions servicesConfig ]; options = [ serviceOptions serviceConfig ];
}; };
boot.systemd.defaultUnit = mkOption { boot.systemd.defaultUnit = mkOption {
@ -386,16 +282,16 @@ in
type = types.bool; type = types.bool;
description = "Whether to log kernel messages."; description = "Whether to log kernel messages.";
}; };
services.journald.console = mkOption { services.journald.console = mkOption {
default = ""; default = "";
type = types.uniq types.string; type = types.uniq types.string;
description = "If non-empty, write log messages to the specified TTY device. Defaults to /dev/console."; description = "If non-empty, write log messages to the specified TTY device. Defaults to /dev/console.";
}; };
}; };
###### implementation ###### implementation
config = { config = {
@ -405,7 +301,7 @@ in
system.build.units = units; system.build.units = units;
environment.systemPackages = [ systemd ]; environment.systemPackages = [ systemd ];
environment.etc = environment.etc =
[ { source = units; [ { source = units;
target = "systemd/system"; target = "systemd/system";

View file

@ -1,11 +1,10 @@
{ config, pkgs, ... }: { config, pkgs, ... }:
with pkgs.lib; with pkgs.lib;
with import ../boot/systemd-unit-options.nix { inherit config pkgs; };
let let
upstart = pkgs.upstart;
userExists = u: userExists = u:
(u == "") || any (uu: uu.name == u) (attrValues config.users.extraUsers); (u == "") || any (uu: uu.name == u) (attrValues config.users.extraUsers);
@ -66,6 +65,8 @@ let
serviceConfig = serviceConfig =
'' ''
${job.serviceConfig}
${optionalString (job.preStart != "" && (job.script != "" || job.exec != "")) '' ${optionalString (job.preStart != "" && (job.script != "" || job.exec != "")) ''
ExecStartPre=${preStartScript} ExecStartPre=${preStartScript}
''} ''}
@ -77,7 +78,7 @@ let
${optionalString (job.script != "" || job.exec != "") '' ${optionalString (job.script != "" || job.exec != "") ''
ExecStart=${startScript} ExecStart=${startScript}
''} ''}
${optionalString (job.postStart != "") '' ${optionalString (job.postStart != "") ''
ExecStartPost=${postStartScript} ExecStartPost=${postStartScript}
''} ''}
@ -85,7 +86,7 @@ let
${optionalString (job.preStop != "") '' ${optionalString (job.preStop != "") ''
ExecStop=${preStopScript} ExecStop=${preStopScript}
''} ''}
${optionalString (job.postStop != "") '' ${optionalString (job.postStop != "") ''
ExecStopPost=${postStopScript} ExecStopPost=${postStopScript}
''} ''}
@ -100,7 +101,7 @@ let
}; };
jobOptions = { jobOptions = serviceOptions // {
name = mkOption { name = mkOption {
# !!! The type should ensure that this could be a filename. # !!! The type should ensure that this could be a filename.
@ -111,14 +112,6 @@ let
''; '';
}; };
description = mkOption {
type = types.string;
default = "";
description = ''
A short description of this job.
'';
};
startOn = mkOption { startOn = mkOption {
# !!! Re-enable this once we're on Upstart >= 0.6. # !!! Re-enable this once we're on Upstart >= 0.6.
#type = types.string; #type = types.string;
@ -137,15 +130,6 @@ let
''; '';
}; };
preStart = mkOption {
type = types.string;
default = "";
description = ''
Shell commands executed before the job is started
(i.e. before the job's main process is started).
'';
};
postStart = mkOption { postStart = mkOption {
type = types.string; type = types.string;
default = ""; default = "";
@ -186,15 +170,6 @@ let
''; '';
}; };
script = mkOption {
type = types.string;
default = "";
description = ''
Shell commands executed as the job's main process. Can be
specified instead of the <varname>exec</varname> attribute.
'';
};
respawn = mkOption { respawn = mkOption {
type = types.bool; type = types.bool;
default = true; default = true;
@ -223,15 +198,6 @@ let
''; '';
}; };
environment = mkOption {
type = types.attrs;
default = {};
example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; };
description = ''
Environment variables passed to the job's processes.
'';
};
daemonType = mkOption { daemonType = mkOption {
type = types.string; type = types.string;
default = "none"; default = "none";
@ -264,15 +230,6 @@ let
''; '';
}; };
extraConfig = mkOption {
type = types.string;
default = "";
example = "limit nofile 4096 4096";
description = ''
Additional Upstart stanzas not otherwise supported.
'';
};
path = mkOption { path = mkOption {
default = []; default = [];
description = '' description = ''
@ -282,46 +239,25 @@ let
''; '';
}; };
console = mkOption {
default = "";
example = "console";
description = ''
If set to <literal>output</literal>, job output is written to
the console. If it's <literal>owner</literal>, additionally
the job becomes owner of the console. It it's empty (the
default), output is written to
<filename>/var/log/upstart/<replaceable>jobname</replaceable></filename>
'';
};
}; };
upstartJob = {name, config, ...}: { upstartJob = { name, config, ... }: {
options = { options = {
unit = mkOption { unit = mkOption {
default = makeUnit config; default = makeUnit config;
description = "Generated definition of the systemd unit corresponding to this job."; description = "Generated definition of the systemd unit corresponding to this job.";
}; };
}; };
config = { config = {
# The default name is the name extracted from the attribute path. # The default name is the name extracted from the attribute path.
name = mkDefaultValue name; name = mkDefaultValue name;
# Default path for Upstart jobs. Should be quite minimal.
path =
[ pkgs.coreutils
pkgs.findutils
pkgs.gnugrep
pkgs.gnused
upstart
];
}; };
}; };
@ -365,7 +301,7 @@ in
boot.systemd.services = boot.systemd.services =
flip mapAttrs' config.jobs (name: job: flip mapAttrs' config.jobs (name: job:
nameValuePair "${job.name}.service" job.unit); nameValuePair "${job.name}.service" job.unit);
}; };
} }