#include "viralloc.h"
#include "vircgroup.h"
#include "virstring.h"
+#include "virsystemd.h"
#define VIR_FROM_THIS VIR_FROM_LXC
int *nicindexes)
{
virCgroupPtr cgroup = NULL;
+ char *machineName = virSystemdMakeMachineName("lxc",
+ def->id,
+ def->name,
+ true);
+
+ if (!machineName)
+ goto cleanup;
if (def->resource->partition[0] != '/') {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
goto cleanup;
}
- if (virCgroupNewMachine(def->name,
+ if (virCgroupNewMachine(machineName,
"lxc",
- true,
def->uuid,
NULL,
initpid,
}
cleanup:
+ VIR_FREE(machineName);
+
return cgroup;
}
pid_t initpid;
virCgroupPtr cgroup;
+ char *machineName;
};
extern virDomainXMLNamespace virLXCDriverDomainXMLNamespace;
* properly. See https://bugs.freedesktop.org/show_bug.cgi?id=68370 for
* the bug we are working around here.
*/
- virSystemdTerminateMachine(vm->def->name, "lxc", true);
-
+ virCgroupTerminateMachine(priv->machineName);
/* The "release" hook cleans up additional resources */
if (virHookPresent(VIR_HOOK_DRIVER_LXC)) {
* point so lets detect that first, since it gives us a
* more reliable way to kill everything off if something
* goes wrong from here onwards ... */
- if (virCgroupNewDetectMachine(vm->def->name, "lxc", vm->pid,
- -1, &priv->cgroup) < 0)
+ if (virCgroupNewDetectMachine(vm->def->name, "lxc",
+ vm->def->id, true,
+ vm->pid, -1, &priv->cgroup) < 0)
goto cleanup;
if (!priv->cgroup) {
goto cleanup;
}
+ /* Get the machine name so we can properly delete it through
+ * systemd later */
+ if (!(priv->machineName = virSystemdGetMachineNameByPID(vm->pid)))
+ virResetLastError();
+
/* And we can get the first monitor connection now too */
if (!(priv->monitor = virLXCProcessConnectMonitor(driver, vm))) {
/* Intentionally overwrite the real monitor error message,
if (!(priv->monitor = virLXCProcessConnectMonitor(driver, vm)))
goto error;
- if (virCgroupNewDetectMachine(vm->def->name, "lxc", vm->pid,
- -1, &priv->cgroup) < 0)
+ if (virCgroupNewDetectMachine(vm->def->name, "lxc", vm->def->id, true,
+ vm->pid, -1, &priv->cgroup) < 0)
goto error;
if (!priv->cgroup) {
goto error;
}
+ if (!(priv->machineName = virSystemdGetMachineNameByPID(vm->pid)))
+ virResetLastError();
+
if (virLXCUpdateActiveUSBHostdevs(driver, vm->def) < 0)
goto error;
#include "virfile.h"
#include "virtypedparam.h"
#include "virnuma.h"
+#include "virsystemd.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
goto cleanup;
}
- if (virCgroupNewMachine(vm->def->name,
+ /*
+ * We need to do this because of systemd-machined, because
+ * CreateMachine requires the name to be a valid hostname.
+ */
+ priv->machineName = virSystemdMakeMachineName("qemu",
+ vm->def->id,
+ vm->def->name,
+ virQEMUDriverIsPrivileged(driver));
+ if (!priv->machineName)
+ goto cleanup;
+
+ if (virCgroupNewMachine(priv->machineName,
"qemu",
- true,
vm->def->uuid,
NULL,
vm->pid,
if (virCgroupNewDetectMachine(vm->def->name,
"qemu",
+ vm->def->id,
+ virQEMUDriverIsPrivileged(driver),
vm->pid,
cfg->cgroupControllers,
&priv->cgroup) < 0)
goto cleanup;
+ priv->machineName = virSystemdGetMachineNameByPID(vm->pid);
+ if (!priv->machineName)
+ virResetLastError();
+
qemuRestoreCgroupState(vm);
done:
}
int
-qemuRemoveCgroup(virQEMUDriverPtr driver,
- virDomainObjPtr vm)
+qemuRemoveCgroup(virDomainObjPtr vm)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
if (priv->cgroup == NULL)
return 0; /* Not supported, so claim success */
- if (virCgroupTerminateMachine(vm->def->name,
- "qemu",
- virQEMUDriverIsPrivileged(driver)) < 0) {
+ if (virCgroupTerminateMachine(priv->machineName) < 0) {
if (!virCgroupNewIgnoreError())
VIR_DEBUG("Failed to terminate cgroup for %s", vm->def->name);
}
int qemuSetupCgroupForVcpu(virDomainObjPtr vm);
int qemuSetupCgroupForIOThreads(virDomainObjPtr vm);
int qemuSetupCgroupForEmulator(virDomainObjPtr vm);
-int qemuRemoveCgroup(virQEMUDriverPtr driver, virDomainObjPtr vm);
+int qemuRemoveCgroup(virDomainObjPtr vm);
int qemuAddToCgroup(virDomainObjPtr vm);
#endif /* __QEMU_CGROUP_H__ */
bool signalIOError; /* true if the domain condition should be signalled on
I/O error */
+ char *machineName;
};
# define QEMU_DOMAIN_DISK_PRIVATE(disk) \
/* Ensure no historical cgroup for this VM is lying around bogus
* settings */
VIR_DEBUG("Ensuring no historical cgroup is lying around");
- qemuRemoveCgroup(driver, vm);
+ qemuRemoveCgroup(vm);
VIR_DEBUG("Setting up ports for graphics");
if (qemuProcessSetupGraphics(driver, vm) < 0)
}
retry:
- if ((ret = qemuRemoveCgroup(driver, vm)) < 0) {
+ if ((ret = qemuRemoveCgroup(vm)) < 0) {
if (ret == -EBUSY && (retries++ < 5)) {
usleep(200*1000);
goto retry;
virCgroupValidateMachineGroup(virCgroupPtr group,
const char *name,
const char *drivername,
+ int id,
+ bool privileged,
bool stripEmulatorSuffix)
{
size_t i;
bool valid = false;
- char *partname;
- char *scopename;
+ char *partname = NULL;
+ char *scopename_old = NULL;
+ char *scopename_new = NULL;
+ char *machinename = virSystemdMakeMachineName(drivername, id,
+ name, privileged);
if (virAsprintf(&partname, "%s.libvirt-%s",
name, drivername) < 0)
if (virCgroupPartitionEscape(&partname) < 0)
goto cleanup;
- if (!(scopename = virSystemdMakeScopeName(name, drivername)))
+ if (!(scopename_old = virSystemdMakeScopeName(name, drivername, true)))
goto cleanup;
- if (virCgroupPartitionEscape(&scopename) < 0)
+ /* We should keep trying even if this failed */
+ if (!machinename)
+ virResetLastError();
+ else if (!(scopename_new = virSystemdMakeScopeName(machinename,
+ drivername, false)))
+ goto cleanup;
+
+ if (virCgroupPartitionEscape(&scopename_old) < 0)
+ goto cleanup;
+
+ if (scopename_new &&
+ virCgroupPartitionEscape(&scopename_new) < 0)
goto cleanup;
for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
tmp++;
if (STRNEQ(tmp, name) &&
+ STRNEQ_NULLABLE(tmp, machinename) &&
STRNEQ(tmp, partname) &&
- STRNEQ(tmp, scopename)) {
+ STRNEQ(tmp, scopename_old) &&
+ STRNEQ_NULLABLE(tmp, scopename_new)) {
VIR_DEBUG("Name '%s' for controller '%s' does not match "
- "'%s', '%s' or '%s'",
+ "'%s', '%s', '%s', '%s' or '%s'",
tmp, virCgroupControllerTypeToString(i),
- name, partname, scopename);
+ name, NULLSTR(machinename), partname,
+ scopename_old, NULLSTR(scopename_new));
goto cleanup;
}
}
cleanup:
VIR_FREE(partname);
- VIR_FREE(scopename);
+ VIR_FREE(scopename_old);
+ VIR_FREE(scopename_new);
+ VIR_FREE(machinename);
return valid;
}
int
virCgroupNewDetectMachine(const char *name,
const char *drivername,
+ int id,
+ bool privileged,
pid_t pid,
int controllers,
virCgroupPtr *group)
return -1;
}
- if (!virCgroupValidateMachineGroup(*group, name, drivername, true)) {
+ if (!virCgroupValidateMachineGroup(*group, name, drivername,
+ id, privileged, true)) {
VIR_DEBUG("Failed to validate machine name for '%s' driver '%s'",
name, drivername);
virCgroupFree(group);
static int
virCgroupNewMachineSystemd(const char *name,
const char *drivername,
- bool privileged,
const unsigned char *uuid,
const char *rootdir,
pid_t pidleader,
VIR_DEBUG("Trying to setup machine '%s' via systemd", name);
if ((rv = virSystemdCreateMachine(name,
drivername,
- privileged,
uuid,
rootdir,
pidleader,
/*
* Returns 0 on success, -1 on fatal error
*/
-int virCgroupTerminateMachine(const char *name,
- const char *drivername,
- bool privileged)
+int virCgroupTerminateMachine(const char *name)
{
- return virSystemdTerminateMachine(name, drivername, privileged);
+ return virSystemdTerminateMachine(name);
}
int
virCgroupNewMachine(const char *name,
const char *drivername,
- bool privileged,
const unsigned char *uuid,
const char *rootdir,
pid_t pidleader,
if ((rv = virCgroupNewMachineSystemd(name,
drivername,
- privileged,
uuid,
rootdir,
pidleader,
int
virCgroupNewDetectMachine(const char *name ATTRIBUTE_UNUSED,
const char *drivername ATTRIBUTE_UNUSED,
+ int id ATTRIBUTE_UNUSED,
+ bool privileged ATTRIBUTE_UNUSED,
pid_t pid ATTRIBUTE_UNUSED,
int controllers ATTRIBUTE_UNUSED,
virCgroupPtr *group ATTRIBUTE_UNUSED)
}
-int virCgroupTerminateMachine(const char *name ATTRIBUTE_UNUSED,
- const char *drivername ATTRIBUTE_UNUSED,
- bool privileged ATTRIBUTE_UNUSED)
+int virCgroupTerminateMachine(const char *name ATTRIBUTE_UNUSED)
{
virReportSystemError(ENXIO, "%s",
_("Control groups not supported on this platform"));
int
virCgroupNewMachine(const char *name ATTRIBUTE_UNUSED,
const char *drivername ATTRIBUTE_UNUSED,
- bool privileged ATTRIBUTE_UNUSED,
const unsigned char *uuid ATTRIBUTE_UNUSED,
const char *rootdir ATTRIBUTE_UNUSED,
pid_t pidleader ATTRIBUTE_UNUSED,
int virCgroupNewDetectMachine(const char *name,
const char *drivername,
+ int id,
+ bool privileged,
pid_t pid,
int controllers,
- virCgroupPtr *group);
+ virCgroupPtr *group)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
int virCgroupNewMachine(const char *name,
const char *drivername,
- bool privileged,
const unsigned char *uuid,
const char *rootdir,
pid_t pidleader,
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
ATTRIBUTE_NONNULL(4);
-int virCgroupTerminateMachine(const char *name,
- const char *drivername,
- bool privileged)
- ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int virCgroupTerminateMachine(const char *name)
+ ATTRIBUTE_NONNULL(1);
bool virCgroupNewIgnoreError(void);
#include "virsystemd.h"
#include "viratomic.h"
+#include "virbuffer.h"
#include "virdbus.h"
#include "virstring.h"
#include "viralloc.h"
#undef VALID_CHARS
}
-
char *virSystemdMakeScopeName(const char *name,
- const char *drivername)
+ const char *drivername,
+ bool legacy_behaviour)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "machine-");
- virSystemdEscapeName(&buf, drivername);
- virBufferAddLit(&buf, "\\x2d");
+ if (legacy_behaviour) {
+ virSystemdEscapeName(&buf, drivername);
+ virBufferAddLit(&buf, "\\x2d");
+ }
virSystemdEscapeName(&buf, name);
virBufferAddLit(&buf, ".scope");
return virBufferContentAndReset(&buf);
}
+#define HOSTNAME_CHARS \
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-"
+
+static void
+virSystemdAppendValidMachineName(virBufferPtr buf,
+ const char *name)
+{
+ bool skip_dot = false;
+
+ for (; *name; name++) {
+ if (strlen(virBufferCurrentContent(buf)) >= 64)
+ break;
+
+ if (*name == '.') {
+ if (!skip_dot)
+ virBufferAddChar(buf, *name);
+ skip_dot = true;
+ continue;
+ }
+
+ skip_dot = false;
+
+ if (!strchr(HOSTNAME_CHARS, *name))
+ continue;
+
+ virBufferAddChar(buf, *name);
+ }
+}
+
+#undef HOSTNAME_CHARS
-char *virSystemdMakeMachineName(const char *name,
- const char *drivername,
- bool privileged)
+char *
+virSystemdMakeMachineName(const char *drivername,
+ int id,
+ const char *name,
+ bool privileged)
{
char *machinename = NULL;
char *username = NULL;
virBufferAsprintf(&buf, "%s-%s-", username, drivername);
}
- virSystemdEscapeName(&buf, name);
+ virBufferAsprintf(&buf, "%d-", id);
+ virSystemdAppendValidMachineName(&buf, name);
machinename = virBufferContentAndReset(&buf);
cleanup:
*/
int virSystemdCreateMachine(const char *name,
const char *drivername,
- bool privileged,
const unsigned char *uuid,
const char *rootdir,
pid_t pidleader,
{
int ret;
DBusConnection *conn;
- char *machinename = NULL;
char *creatorname = NULL;
char *slicename = NULL;
static int hasCreateWithNetwork = 1;
return -1;
ret = -1;
- if (!(machinename = virSystemdMakeMachineName(name, drivername, privileged)))
- goto cleanup;
if (virAsprintf(&creatorname, "libvirt-%s", drivername) < 0)
goto cleanup;
"org.freedesktop.machine1.Manager",
"CreateMachineWithNetwork",
"sayssusa&ia(sv)",
- machinename,
+ name,
16,
uuid[0], uuid[1], uuid[2], uuid[3],
uuid[4], uuid[5], uuid[6], uuid[7],
"org.freedesktop.machine1.Manager",
"CreateMachine",
"sayssusa(sv)",
- machinename,
+ name,
16,
uuid[0], uuid[1], uuid[2], uuid[3],
uuid[4], uuid[5], uuid[6], uuid[7],
cleanup:
VIR_FREE(creatorname);
- VIR_FREE(machinename);
VIR_FREE(slicename);
return ret;
}
-int virSystemdTerminateMachine(const char *name,
- const char *drivername,
- bool privileged)
+int virSystemdTerminateMachine(const char *name)
{
int ret;
DBusConnection *conn;
- char *machinename = NULL;
virError error;
+ if (!name)
+ return 0;
+
memset(&error, 0, sizeof(error));
ret = virDBusIsServiceEnabled("org.freedesktop.machine1");
if (!(conn = virDBusGetSystemBus()))
goto cleanup;
- if (!(machinename = virSystemdMakeMachineName(name, drivername, privileged)))
- goto cleanup;
-
/*
* The systemd DBus API we're invoking has the
* following signature
"org.freedesktop.machine1.Manager",
"TerminateMachine",
"s",
- machinename) < 0)
+ name) < 0)
goto cleanup;
if (error.code == VIR_ERR_ERROR &&
cleanup:
virResetError(&error);
- VIR_FREE(machinename);
return ret;
}
# include "internal.h"
char *virSystemdMakeScopeName(const char *name,
- const char *drivername);
+ const char *drivername,
+ bool legacy_behaviour);
char *virSystemdMakeSliceName(const char *partition);
-char *virSystemdMakeMachineName(const char *name,
- const char *drivername,
+char *virSystemdMakeMachineName(const char *drivername,
+ int id,
+ const char *name,
bool privileged);
int virSystemdCreateMachine(const char *name,
const char *drivername,
- bool privileged,
const unsigned char *uuid,
const char *rootdir,
pid_t pidleader,
int *nicindexes,
const char *partition);
-int virSystemdTerminateMachine(const char *name,
- const char *drivername,
- bool privileged);
+int virSystemdTerminateMachine(const char *name);
void virSystemdNotifyStartup(void);
};
if (virSystemdCreateMachine("demo",
"lxc",
- true,
uuid,
"/proc/123/root",
123,
static int testTerminateContainer(const void *opaque ATTRIBUTE_UNUSED)
{
- if (virSystemdTerminateMachine("demo",
- "lxc",
- true) < 0) {
+ if (virSystemdTerminateMachine("lxc-demo") < 0) {
fprintf(stderr, "%s", "Failed to terminate LXC machine\n");
return -1;
}
};
if (virSystemdCreateMachine("demo",
"qemu",
- false,
uuid,
NULL,
123,
static int testTerminateMachine(const void *opaque ATTRIBUTE_UNUSED)
{
- if (virSystemdTerminateMachine("demo",
- "qemu",
- false) < 0) {
+ if (virSystemdTerminateMachine("test-qemu-demo") < 0) {
fprintf(stderr, "%s", "Failed to terminate KVM machine\n");
return -1;
}
if ((rv = virSystemdCreateMachine("demo",
"qemu",
- true,
uuid,
NULL,
123,
if ((rv = virSystemdCreateMachine("demo",
"qemu",
- true,
uuid,
NULL,
123,
if ((rv = virSystemdCreateMachine("demo",
"qemu",
- true,
uuid,
NULL,
123,
size_t nnicindexes = ARRAY_CARDINALITY(nicindexes);
if (virSystemdCreateMachine("demo",
"lxc",
- true,
uuid,
"/proc/123/root",
123,
struct testNameData {
const char *name;
const char *expected;
+ int id;
+ bool legacy;
};
static int
int ret = -1;
char *actual = NULL;
- if (!(actual = virSystemdMakeScopeName(data->name, "lxc")))
+ if (!(actual = virSystemdMakeScopeName(data->name, "lxc", data->legacy)))
goto cleanup;
if (STRNEQ(actual, data->expected)) {
int ret = -1;
char *actual = NULL;
- if (!(actual = virSystemdMakeMachineName(data->name, "qemu", true)))
+ if (!(actual = virSystemdMakeMachineName("qemu", data->id,
+ data->name, true)))
goto cleanup;
if (STRNEQ(actual, data->expected)) {
{
int ret = 0;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+
+ /* The one we use in tests quite often */
+ if (virUUIDParse("c7a5fdbd-edaf-9455-926a-d65c16db1809", uuid) < 0)
+ return EXIT_FAILURE;
+
if (virtTestRun("Test create container ", testCreateContainer, NULL) < 0)
ret = -1;
if (virtTestRun("Test terminate container ", testTerminateContainer, NULL) < 0)
if (virtTestRun("Test getting machine name ", testGetMachineName, NULL) < 0)
ret = -1;
-# define TEST_SCOPE(name, unitname) \
+# define TEST_SCOPE(_name, unitname, _legacy) \
do { \
struct testNameData data = { \
- name, unitname \
+ .name = _name, .expected = unitname, .legacy = _legacy, \
}; \
if (virtTestRun("Test scopename", testScopeName, &data) < 0) \
ret = -1; \
} while (0)
- TEST_SCOPE("demo", "machine-lxc\\x2ddemo.scope");
- TEST_SCOPE("demo-name", "machine-lxc\\x2ddemo\\x2dname.scope");
- TEST_SCOPE("demo!name", "machine-lxc\\x2ddemo\\x21name.scope");
- TEST_SCOPE(".demo", "machine-lxc\\x2d\\x2edemo.scope");
- TEST_SCOPE("bull💩", "machine-lxc\\x2dbull\\xf0\\x9f\\x92\\xa9.scope");
+# define TEST_SCOPE_OLD(name, unitname) \
+ TEST_SCOPE(name, unitname, true)
+# define TEST_SCOPE_NEW(name, unitname) \
+ TEST_SCOPE(name, unitname, false)
+
+ TEST_SCOPE_OLD("demo", "machine-lxc\\x2ddemo.scope");
+ TEST_SCOPE_OLD("demo-name", "machine-lxc\\x2ddemo\\x2dname.scope");
+ TEST_SCOPE_OLD("demo!name", "machine-lxc\\x2ddemo\\x21name.scope");
+ TEST_SCOPE_OLD(".demo", "machine-lxc\\x2d\\x2edemo.scope");
+ TEST_SCOPE_OLD("bull💩", "machine-lxc\\x2dbull\\xf0\\x9f\\x92\\xa9.scope");
+
+ TEST_SCOPE_NEW("qemu-3-demo", "machine-qemu\\x2d3\\x2ddemo.scope");
-# define TEST_MACHINE(name, machinename) \
+# define TEST_MACHINE(_name, _id, machinename) \
do { \
struct testNameData data = { \
- name, machinename \
+ .name = _name, .expected = machinename, .id = _id, \
}; \
if (virtTestRun("Test scopename", testMachineName, &data) < 0) \
ret = -1; \
} while (0)
- TEST_MACHINE("demo", "qemu-demo");
- TEST_MACHINE("demo-name", "qemu-demo\\x2dname");
- TEST_MACHINE("demo!name", "qemu-demo\\x21name");
- TEST_MACHINE(".demo", "qemu-\\x2edemo");
- TEST_MACHINE("bull\U0001f4a9", "qemu-bull\\xf0\\x9f\\x92\\xa9");
+ TEST_MACHINE("demo", 1, "qemu-1-demo");
+ TEST_MACHINE("demo-name", 2, "qemu-2-demo-name");
+ TEST_MACHINE("demo!name", 3, "qemu-3-demoname");
+ TEST_MACHINE(".demo", 4, "qemu-4-.demo");
+ TEST_MACHINE("bull\U0001f4a9", 5, "qemu-5-bull");
+ TEST_MACHINE("demo..name", 6, "qemu-6-demo.name");
+ TEST_MACHINE("12345678901234567890123456789012345678901234567890123456789", 7,
+ "qemu-7-123456789012345678901234567890123456789012345678901234567");
+ TEST_MACHINE("123456789012345678901234567890123456789012345678901234567890", 8,
+ "qemu-8-123456789012345678901234567890123456789012345678901234567");
# define TESTS_PM_SUPPORT_HELPER(name, function) \
do { \