From: Daniel P. Berrange Date: Thu, 18 Jul 2013 09:54:21 +0000 (+0100) Subject: Add API for calling systemd-machined's DBus API X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=dff93f8cabc146fe39517af3628e485da5a9bc6d;p=people%2Fliuw%2Flibxenctrl-split%2Flibvirt.git Add API for calling systemd-machined's DBus API To register virtual machines and containers with systemd-machined, and thus have cgroups auto-created, we need to talk over DBus. This is somewhat tedious code, so introduce a dedicated function to isolate the DBus call in one place. Signed-off-by: Daniel P. Berrange --- diff --git a/.gitignore b/.gitignore index 851c6e400..4c79de39a 100644 --- a/.gitignore +++ b/.gitignore @@ -204,6 +204,7 @@ /tests/virshtest /tests/virstoragetest /tests/virstringtest +/tests/virsystemdtest /tests/virtimetest /tests/viruritest /tests/vmx2xmltest diff --git a/build-aux/bracket-spacing.pl b/build-aux/bracket-spacing.pl index fbb323e51..4c199689e 100755 --- a/build-aux/bracket-spacing.pl +++ b/build-aux/bracket-spacing.pl @@ -92,8 +92,8 @@ foreach my $file (@ARGV) { # Require whitespace immediately after keywords, # but none after the opening bracket - while ($data =~ /(if|for|while|switch|return)\(/ || - $data =~ /(if|for|while|switch|return)\s+\(\s/) { + while ($data =~ /\b(if|for|while|switch|return)\(/ || + $data =~ /\b(if|for|while|switch|return)\s+\(\s/) { print "$file:$.: $line"; $ret = 1; last; diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 3ef73a1f4..c1960c86d 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -119,6 +119,7 @@ typedef enum { VIR_FROM_CGROUP = 54, /* Error from cgroups */ VIR_FROM_ACCESS = 55, /* Error from access control manager */ + VIR_FROM_SYSTEMD = 56, /* Error from systemd code */ # ifdef VIR_ENUM_SENTINELS VIR_ERR_DOMAIN_LAST diff --git a/src/Makefile.am b/src/Makefile.am index b397be74a..0eb3cb555 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -132,6 +132,7 @@ UTIL_SOURCES = \ util/virstoragefile.c util/virstoragefile.h \ util/virstring.h util/virstring.c \ util/virsysinfo.c util/virsysinfo.h \ + util/virsystemd.c util/virsystemd.h \ util/virthread.c util/virthread.h \ util/virthreadpthread.h \ util/virthreadwin32.h \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b83074f4b..5d39d50ef 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1923,6 +1923,10 @@ virSysinfoRead; virSysinfoSetup; +# util/virsystemd.h +virSystemdCreateMachine; + + # util/virthread.h virCondBroadcast; virCondDestroy; diff --git a/src/util/virerror.c b/src/util/virerror.c index b8572daf6..36d256bbf 100644 --- a/src/util/virerror.c +++ b/src/util/virerror.c @@ -123,6 +123,7 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST, "Cgroup", "Access Manager", /* 55 */ + "Systemd", ) diff --git a/src/util/virsystemd.c b/src/util/virsystemd.c new file mode 100644 index 000000000..8477cd330 --- /dev/null +++ b/src/util/virsystemd.c @@ -0,0 +1,148 @@ +/* + * virsystemd.c: helpers for using systemd APIs + * + * Copyright (C) 2013 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + */ + +#include + +#include "virsystemd.h" +#include "virdbus.h" +#include "virstring.h" +#include "viralloc.h" +#include "virutil.h" + +#define VIR_FROM_THIS VIR_FROM_SYSTEMD + +/** + * virSystemdCreateMachine: + * @name: driver unique name of the machine + * @drivername: name of the virt driver + * @privileged: whether driver is running privileged or per user + * @uuid: globally unique UUID of the machine + * @rootdir: root directory of machine filesystem + * @pidleader: PID of the leader process + * @slice: name of the slice to place the machine in + */ +int virSystemdCreateMachine(const char *name, + const char *drivername, + bool privileged, + const unsigned char *uuid, + const char *rootdir, + pid_t pidleader, + bool iscontainer, + const char *partition) +{ + int ret = -1; + DBusConnection *conn; + char *machinename = NULL; + char *creatorname = NULL; + char *username = NULL; + char *slicename = NULL; + + if (!(conn = virDBusGetSystemBus())) + return -1; + + if (privileged) { + if (virAsprintf(&machinename, "%s-%s", drivername, name) < 0) + goto cleanup; + } else { + if (!(username = virGetUserName(geteuid()))) + goto cleanup; + if (virAsprintf(&machinename, "%s-%s-%s", username, drivername, name) < 0) + goto cleanup; + } + + if (virAsprintf(&creatorname, "libvirt-%s", drivername) < 0) + goto cleanup; + + if (partition) { + if (virAsprintf(&slicename, "%s.slice", partition) < 0) + goto cleanup; + } else { + if (VIR_STRDUP(slicename, "") < 0) + goto cleanup; + } + + /* + * The systemd DBus API we're invoking has the + * following signature + * + * CreateMachine(in s name, + * in ay id, + * in s service, + * in s class, + * in u leader, + * in s root_directory, + * in a(sv) scope_properties, + * out o path); + * + * @name a host unique name for the machine. shows up + * in 'ps' listing & similar + * + * @id: a UUID of the machine, ideally matching /etc/machine-id + * for containers + * + * @service: identifier of the client ie "libvirt-lxc" + * + * @class: either the string "container" or "vm" depending + * on the type of machine + * + * @leader: main PID of the machine, either the host emulator + * process, or the 'init' PID of the container + * + * @root_directory: the root directory of the container, if + * this is known & visible in the host filesystem, or empty string + * + * @scope_properties:an array (not a dict!) of properties that are + * passed on to PID 1 when creating a scope unit for your machine. + * Will allow initial settings for the cgroup & similar. + * + * @path: a bus path returned for the machine object created, to + * allow further API calls to be made against the object. + */ + + if (virDBusCallMethod(conn, + NULL, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "CreateMachine", + "sayssusa(sv)", + machinename, + 16, + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15], + creatorname, + iscontainer ? "container" : "vm", + (unsigned int)pidleader, + rootdir ? rootdir : "", + 1, "Slice", "s", + slicename) < 0) + goto cleanup; + + ret = 0; + +cleanup: + VIR_FREE(username); + VIR_FREE(creatorname); + VIR_FREE(machinename); + return ret; +} diff --git a/src/util/virsystemd.h b/src/util/virsystemd.h new file mode 100644 index 000000000..9ca4e0b20 --- /dev/null +++ b/src/util/virsystemd.h @@ -0,0 +1,36 @@ +/* + * virsystemd.h: helpers for using systemd APIs + * + * Copyright (C) 2013 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + */ + +#ifndef __VIR_SYSTEMD_H__ +# define __VIR_SYSTEMD_H__ + +# include "internal.h" + +int virSystemdCreateMachine(const char *name, + const char *drivername, + bool privileged, + const unsigned char *uuid, + const char *rootdir, + pid_t pidleader, + bool iscontainer, + const char *partition); + +#endif /* __VIR_SYSTEMD_H__ */ diff --git a/tests/Makefile.am b/tests/Makefile.am index f04aec6d4..5ea806e8d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -129,10 +129,10 @@ test_programs = virshtest sockettest \ $(NULL) if WITH_DBUS -test_programs += virdbustest +test_programs += virdbustest \ + virsystemdtest endif - if WITH_GNUTLS test_programs += virnettlscontexttest endif @@ -281,6 +281,10 @@ if WITH_QEMU test_libraries += libqemumonitortestutils.la endif +if WITH_DBUS +test_libraries += virsystemdmock.la +endif + if WITH_TESTS noinst_PROGRAMS = $(test_programs) $(test_helpers) noinst_LTLIBRARIES = $(test_libraries) @@ -650,8 +654,20 @@ virdbustest_SOURCES = \ virdbustest.c testutils.h testutils.c virdbustest_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) virdbustest_LDADD = $(LDADDS) + +virsystemdtest_SOURCES = \ + virsystemdtest.c testutils.h testutils.c +virsystemdtest_CFLAGS = $(AM_CFLAGS) +virsystemdtest_LDADD = $(LDADDS) + +virsystemdmock_la_SOURCES = \ + virsystemdmock.c +virsystemdmock_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) +virsystemdmock_la_LDFLAGS = -module -avoid-version \ + -rpath /evil/libtool/hack/to/force/shared/lib/creation + else -EXTRA_DIST += virdbustest.c +EXTRA_DIST += virdbustest.c virsystemdtest.c virsystemdmock.c endif viruritest_SOURCES = \ diff --git a/tests/testutils.h b/tests/testutils.h index 3647487c9..bf5c70174 100644 --- a/tests/testutils.h +++ b/tests/testutils.h @@ -25,6 +25,8 @@ # include # include "viralloc.h" +# include "virfile.h" +# include "virstring.h" # define EXIT_AM_SKIP 77 /* tell Automake we're skipping a test */ # define EXIT_AM_HARDFAIL 99 /* tell Automake that the framework is broken */ diff --git a/tests/virsystemdmock.c b/tests/virsystemdmock.c new file mode 100644 index 000000000..5f9cce6a9 --- /dev/null +++ b/tests/virsystemdmock.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Author: Daniel P. Berrange + */ + +#include + +#include "internal.h" + +#include + +#include + +void dbus_connection_set_change_sigpipe(dbus_bool_t will_modify_sigpipe ATTRIBUTE_UNUSED) +{ +} + +dbus_bool_t dbus_threads_init_default(void) +{ + return 1; +} + +DBusConnection *dbus_bus_get(DBusBusType type ATTRIBUTE_UNUSED, + DBusError *error ATTRIBUTE_UNUSED) +{ + return (DBusConnection *)0x1; +} + +void dbus_connection_set_exit_on_disconnect(DBusConnection *connection ATTRIBUTE_UNUSED, + dbus_bool_t exit_on_disconnect ATTRIBUTE_UNUSED) +{ +} + + +dbus_bool_t dbus_connection_set_watch_functions(DBusConnection *connection ATTRIBUTE_UNUSED, + DBusAddWatchFunction add_function ATTRIBUTE_UNUSED, + DBusRemoveWatchFunction remove_function ATTRIBUTE_UNUSED, + DBusWatchToggledFunction toggled_function ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED, + DBusFreeFunction free_data_function ATTRIBUTE_UNUSED) +{ + return 1; +} + +DBusMessage *dbus_connection_send_with_reply_and_block(DBusConnection *connection ATTRIBUTE_UNUSED, + DBusMessage *message, + int timeout_milliseconds ATTRIBUTE_UNUSED, + DBusError *error ATTRIBUTE_UNUSED) +{ + DBusMessage *reply; + + dbus_message_set_serial(message, 7); + + if (getenv("FAIL_NO_SERVICE")) + reply = dbus_message_new_error(message, + "org.freedesktop.DBus.Error.ServiceUnknown", + "The name org.freedesktop.machine1 was not provided by any .service files"); + else + reply = dbus_message_new_method_return(message); + + return reply; +} diff --git a/tests/virsystemdtest.c b/tests/virsystemdtest.c new file mode 100644 index 000000000..3992722e9 --- /dev/null +++ b/tests/virsystemdtest.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Author: Daniel P. Berrange + */ + +#include + +#include + +#include "virsystemd.h" +#include "virlog.h" +#include "testutils.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +static int testCreateContainer(const void *opaque ATTRIBUTE_UNUSED) +{ + unsigned char uuid[VIR_UUID_BUFLEN] = { + 1, 1, 1, 1, + 2, 2, 2, 2, + 3, 3, 3, 3, + 4, 4, 4, 4 + }; + if (virSystemdCreateMachine("demo", + "lxc", + true, + uuid, + "/proc/123/root", + 123, + true, + "highpriority.slice") < 0) { + fprintf(stderr, "%s", "Failed to create LXC machine\n"); + return -1; + } + + return 0; +} + +static int testCreateMachine(const void *opaque ATTRIBUTE_UNUSED) +{ + unsigned char uuid[VIR_UUID_BUFLEN] = { + 1, 1, 1, 1, + 2, 2, 2, 2, + 3, 3, 3, 3, + 4, 4, 4, 4 + }; + if (virSystemdCreateMachine("demo", + "qemu", + false, + uuid, + NULL, + 123, + false, + NULL) < 0) { + fprintf(stderr, "%s", "Failed to create KVM machine\n"); + return -1; + } + + return 0; +} + +static int testCreateNoSystemd(const void *opaque ATTRIBUTE_UNUSED) +{ + unsigned char uuid[VIR_UUID_BUFLEN] = { + 1, 1, 1, 1, + 2, 2, 2, 2, + 3, 3, 3, 3, + 4, 4, 4, 4 + }; + + setenv("FAIL_NO_SERVICE", "1", 1); + + if (virSystemdCreateMachine("demo", + "qemu", + true, + uuid, + NULL, + 123, + false, + NULL) == 0) { + fprintf(stderr, "%s", "Unexpected create machine success\n"); + return -1; + } + + virErrorPtr err = virGetLastError(); + + if (!err) { + fprintf(stderr, "No error raised"); + return -1; + } + + if (err->code == VIR_ERR_DBUS_SERVICE && + STREQ(err->str2, "org.freedesktop.DBus.Error.ServiceUnknown")) + return 0; + + fprintf(stderr, "Unexpected error code %d / message %s\n", + err->code, err->str2); + return -1; +} + +static int +mymain(void) +{ + int ret = 0; + + if (virtTestRun("Test create container ", 1, testCreateContainer, NULL) < 0) + ret = -1; + if (virtTestRun("Test create machine ", 1, testCreateMachine, NULL) < 0) + ret = -1; + if (virtTestRun("Test create nosystemd ", 1, testCreateNoSystemd, NULL) < 0) + ret = -1; + + return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIRT_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/virsystemdmock.so")