unit: add new ConditionHost= condition type

This commit is contained in:
Lennart Poettering 2012-08-22 01:51:53 +02:00
parent ddfa5101a2
commit c0d6e764d1
6 changed files with 120 additions and 40 deletions

4
TODO
View file

@ -49,6 +49,8 @@ Bugfixes:
Features: Features:
* There's something wrong with escaping unit names: http://lists.freedesktop.org/archives/systemd-devel/2012-August/006292.html
* cleanup ellipsation for log output in journalctl and systemctl status: have a sane way to disable ellipsation, and disable it by default when invoked in less/more * cleanup ellipsation for log output in journalctl and systemctl status: have a sane way to disable ellipsation, and disable it by default when invoked in less/more
* enforce limits on fds openened by socket units * enforce limits on fds openened by socket units
@ -59,8 +61,6 @@ Features:
* testing tool for socket activation: some binary that listens on a socket and passes it on using the usual socket activation protocol to some server. * testing tool for socket activation: some binary that listens on a socket and passes it on using the usual socket activation protocol to some server.
* ConditionHost= for filtering services for clusters
* journald: add symlinks and device names to kernel messages * journald: add symlinks and device names to kernel messages
* maybe make systemd-detect-virt suid? or use fscaps? * maybe make systemd-detect-virt suid? or use fscaps?

View file

@ -586,7 +586,7 @@
<term><varname>RequiresMountsFor=</varname></term> <term><varname>RequiresMountsFor=</varname></term>
<listitem><para>Takes a space <listitem><para>Takes a space
separated list of paths. Automatically separated list of absolute paths. Automatically
adds dependencies of type adds dependencies of type
<varname>Requires=</varname> and <varname>Requires=</varname> and
<varname>After=</varname> for all <varname>After=</varname> for all
@ -760,65 +760,86 @@
<term><varname>ConditionVirtualization=</varname></term> <term><varname>ConditionVirtualization=</varname></term>
<term><varname>ConditionSecurity=</varname></term> <term><varname>ConditionSecurity=</varname></term>
<term><varname>ConditionCapability=</varname></term> <term><varname>ConditionCapability=</varname></term>
<term><varname>ConditionHost=</varname></term>
<term><varname>ConditionNull=</varname></term> <term><varname>ConditionNull=</varname></term>
<listitem><para>Before starting a unit <listitem><para>Before starting a unit
verify that the specified condition is verify that the specified condition is
true. With true. If it is not true the starting
of the unit will be skipped, however
all ordering dependencies of it are
still respected. A failing condition
will not result in the unit being
moved into a failure state. The
condition is checked at the time the
queued start job is to be
executed.</para>
<para>With
<varname>ConditionPathExists=</varname> <varname>ConditionPathExists=</varname>
a file existence condition can be a file existence condition is
checked before a unit is started. If checked before a unit is started. If
the specified absolute path name does the specified absolute path name does
not exist, startup of a unit will not not exist the condition will
actually happen, however the unit is fail. If the absolute path name passed
still useful for ordering purposes in to
this case. The condition is checked at
the time the queued start job is to be
executed. If the absolute path name
passed to
<varname>ConditionPathExists=</varname> <varname>ConditionPathExists=</varname>
is prefixed with an exclamation mark is prefixed with an exclamation mark
(!), the test is negated, and the unit ('!'), the test is negated, and the unit
is only started if the path does not is only started if the path does not
exist. exist.</para>
<varname>ConditionPathExistsGlob=</varname>
works in a similar way, but checks for <para><varname>ConditionPathExistsGlob=</varname>
the existence of at least one file or is similar to
directory matching the specified <varname>ConditionPathExists=</varname>,
globbing but checks for the existence of at
pattern. <varname>ConditionPathIsDirectory=</varname> least one file or directory matching
the specified globbing pattern.</para>
<para><varname>ConditionPathIsDirectory=</varname>
is similar to is similar to
<varname>ConditionPathExists=</varname> <varname>ConditionPathExists=</varname>
but verifies whether a certain path but verifies whether a certain path
exists and is a exists and is a
directory. <varname>ConditionPathIsSymbolicLink=</varname> directory.</para>
<para><varname>ConditionPathIsSymbolicLink=</varname>
is similar to is similar to
<varname>ConditionPathExists=</varname> <varname>ConditionPathExists=</varname>
but verifies whether a certain path but verifies whether a certain path
exists and is a symbolic exists and is a symbolic
link. <varname>ConditionPathIsMountPoint=</varname> link.</para>
<para><varname>ConditionPathIsMountPoint=</varname>
is similar to is similar to
<varname>ConditionPathExists=</varname> <varname>ConditionPathExists=</varname>
but verifies whether a certain path but verifies whether a certain path
exists and is a mount exists and is a mount
point. <varname>ConditionPathIsReadWrite=</varname> point.</para>
<para><varname>ConditionPathIsReadWrite=</varname>
is similar to is similar to
<varname>ConditionPathExists=</varname> <varname>ConditionPathExists=</varname>
but verifies whether the underlying but verifies whether the underlying
file system is read and writable file system is readable and writable
(i.e. not mounted (i.e. not mounted
read-only). <varname>ConditionFileIsExecutable=</varname> read-only).</para>
<para><varname>ConditionFileIsExecutable=</varname>
is similar to is similar to
<varname>ConditionPathExists=</varname> <varname>ConditionPathExists=</varname>
but verifies whether a certain path but verifies whether a certain path
exists, is a regular file and marked exists, is a regular file and marked
executable. executable.</para>
<varname>ConditionDirectoryNotEmpty=</varname>
<para><varname>ConditionDirectoryNotEmpty=</varname>
is similar to is similar to
<varname>ConditionPathExists=</varname> <varname>ConditionPathExists=</varname>
but verifies whether a certain path but verifies whether a certain path
exists and is a non-empty exists and is a non-empty
directory. Similarly directory.</para>
<para>Similarly,
<varname>ConditionKernelCommandLine=</varname> <varname>ConditionKernelCommandLine=</varname>
may be used to check whether a may be used to check whether a
specific kernel command line option is specific kernel command line option is
@ -826,14 +847,16 @@
exclamation mark unset). The argument exclamation mark unset). The argument
must either be a single word, or an must either be a single word, or an
assignment (i.e. two words, separated assignment (i.e. two words, separated
by the equality sign). In the former '='). In the former
case the kernel command line is case the kernel command line is
searched for the word appearing as is, searched for the word appearing as is,
or as left hand side of an or as left hand side of an
assignment. In the latter case the assignment. In the latter case the
exact assignment is looked for with exact assignment is looked for with
right and left hand side right and left hand side
matching. <varname>ConditionVirtualization=</varname> matching.</para>
<para><varname>ConditionVirtualization=</varname>
may be used to check whether the may be used to check whether the
system is executed in a virtualized system is executed in a virtualized
environment and optionally test environment and optionally test
@ -843,7 +866,7 @@
any virtualized environment, or one of any virtualized environment, or one of
<varname>vm</varname> and <varname>vm</varname> and
<varname>container</varname> to test <varname>container</varname> to test
against a specific type of against a generic type of
virtualization solution, or one of virtualization solution, or one of
<varname>qemu</varname>, <varname>qemu</varname>,
<varname>kvm</varname>, <varname>kvm</varname>,
@ -862,15 +885,18 @@
virtualization technologies are nested virtualization technologies are nested
only the innermost is considered. The only the innermost is considered. The
test may be negated by prepending an test may be negated by prepending an
exclamation mark. exclamation mark.</para>
<varname>ConditionSecurity=</varname>
<para><varname>ConditionSecurity=</varname>
may be used to check whether the given may be used to check whether the given
security module is enabled on the security module is enabled on the
system. Currently the only recognized system. Currently the only recognized
value is <varname>selinux</varname>. value is <varname>selinux</varname>.
The test may be negated by prepending The test may be negated by prepending
an exclamation an exclamation
mark. <varname>ConditionCapability=</varname> mark.</para>
<para><varname>ConditionCapability=</varname>
may be used to check whether the given may be used to check whether the given
capability exists in the capability capability exists in the capability
bounding set of the service manager bounding set of the service manager
@ -881,14 +907,32 @@
for details). Pass a capability name for details). Pass a capability name
such as <literal>CAP_MKNOD</literal>, such as <literal>CAP_MKNOD</literal>,
possibly prefixed with an exclamation possibly prefixed with an exclamation
mark to negate the check. Finally, mark to negate the check.</para>
<para><varname>ConditionHost=</varname>
may be used to match against the
host name or machine ID of the
host. This either takes a host name
string (optionally with shell style
globs) which is tested against the
locally set host name as returned by
<citerefentry><refentrytitle>gethostname</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
or a machine ID formatted as string
(see
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
The test may be negated by prepending
an exclamation mark.</para>
<para>Finally,
<varname>ConditionNull=</varname> may <varname>ConditionNull=</varname> may
be used to add a constant condition be used to add a constant condition
check value to the unit. It takes a check value to the unit. It takes a
boolean argument. If set to boolean argument. If set to
<varname>false</varname> the condition <varname>false</varname> the condition
will always fail, otherwise will always fail, otherwise
succeed. If multiple conditions are succeed.</para>
<para>If multiple conditions are
specified the unit will be executed if specified the unit will be executed if
all of them apply (i.e. a logical AND all of them apply (i.e. a logical AND
is applied). Condition checks can be is applied). Condition checks can be

View file

@ -25,11 +25,13 @@
#include <unistd.h> #include <unistd.h>
#include <sys/capability.h> #include <sys/capability.h>
#include <sys/statvfs.h> #include <sys/statvfs.h>
#include <fnmatch.h>
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
#include <selinux/selinux.h> #include <selinux/selinux.h>
#endif #endif
#include <systemd/sd-id128.h>
#include "util.h" #include "util.h"
#include "condition.h" #include "condition.h"
#include "virt.h" #include "virt.h"
@ -194,6 +196,31 @@ static bool test_capability(const char *parameter) {
return !!(capabilities & (1ULL << value)); return !!(capabilities & (1ULL << value));
} }
static bool test_host(const char *parameter) {
sd_id128_t x, y;
char *h;
int r;
bool b;
if (sd_id128_from_string(parameter, &x) >= 0) {
r = sd_id128_get_machine(&y);
if (r < 0)
return false;
return sd_id128_equal(x, y);
}
h = gethostname_malloc();
if (!h)
return false;
b = fnmatch(parameter, h, FNM_CASEFOLD) == 0;
free(h);
return b;
}
bool condition_test(Condition *c) { bool condition_test(Condition *c) {
assert(c); assert(c);
@ -255,6 +282,9 @@ bool condition_test(Condition *c) {
case CONDITION_CAPABILITY: case CONDITION_CAPABILITY:
return test_capability(c->parameter) == !c->negate; return test_capability(c->parameter) == !c->negate;
case CONDITION_HOST:
return test_host(c->parameter) == !c->negate;
case CONDITION_NULL: case CONDITION_NULL:
return !c->negate; return !c->negate;
@ -323,6 +353,7 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
[CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine", [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
[CONDITION_VIRTUALIZATION] = "ConditionVirtualization", [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
[CONDITION_SECURITY] = "ConditionSecurity", [CONDITION_SECURITY] = "ConditionSecurity",
[CONDITION_HOST] = "ConditionHost",
[CONDITION_NULL] = "ConditionNull" [CONDITION_NULL] = "ConditionNull"
}; };

View file

@ -38,6 +38,7 @@ typedef enum ConditionType {
CONDITION_VIRTUALIZATION, CONDITION_VIRTUALIZATION,
CONDITION_SECURITY, CONDITION_SECURITY,
CONDITION_CAPABILITY, CONDITION_CAPABILITY,
CONDITION_HOST,
CONDITION_NULL, CONDITION_NULL,
_CONDITION_TYPE_MAX, _CONDITION_TYPE_MAX,
_CONDITION_TYPE_INVALID = -1 _CONDITION_TYPE_INVALID = -1

View file

@ -135,6 +135,7 @@ Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_K
Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, 0 Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, 0
Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, 0 Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, 0
Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, 0 Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, 0
Unit.ConditionHost, config_parse_unit_condition_string, CONDITION_HOST, 0
Unit.ConditionNull, config_parse_unit_condition_null, 0, 0 Unit.ConditionNull, config_parse_unit_condition_null, 0, 0
m4_dnl m4_dnl
Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file) Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file)

View file

@ -1516,14 +1516,17 @@ int config_parse_unit_condition_string(
assert(rvalue); assert(rvalue);
assert(data); assert(data);
if ((trigger = rvalue[0] == '|')) trigger = rvalue[0] == '|';
if (trigger)
rvalue++; rvalue++;
if ((negate = rvalue[0] == '!')) negate = rvalue[0] == '!';
if (negate)
rvalue++; rvalue++;
if (!(c = condition_new(cond, rvalue, trigger, negate))) c = condition_new(cond, rvalue, trigger, negate);
return -ENOMEM; if (!c)
return log_oom();
LIST_PREPEND(Condition, conditions, u->conditions, c); LIST_PREPEND(Condition, conditions, u->conditions, c);
return 0; return 0;