From: "Daniel P. Berrange" <berrange(a)redhat.com>
This wires up the LXC driver to support the domain device attach/
detach/update APIs, following the same code design as used in
the QEMU driver. No actual changes are possible with this commit,
it is only providing the framework
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/lxc/lxc_driver.c | 290 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 290 insertions(+)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 1c6ec8c..38d5d87 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -2768,6 +2768,291 @@ lxcListAllDomains(virConnectPtr conn,
return ret;
}
+
+static int
+lxcDomainAttachDeviceConfig(virDomainDefPtr vmdef ATTRIBUTE_UNUSED,
+ virDomainDeviceDefPtr dev)
+{
+ int ret = -1;
+
+ switch (dev->type) {
+ default:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("persistent attach of device is not supported"));
+ break;
+ }
+
+ return ret;
+}
+
+
+static int
+lxcDomainUpdateDeviceConfig(virDomainDefPtr vmdef ATTRIBUTE_UNUSED,
+ virDomainDeviceDefPtr dev)
+{
+ int ret = -1;
+
+ switch (dev->type) {
+ default:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("persistent update of device is not supported"));
+ break;
+ }
+
+ return ret;
+}
+
+
+static int
+lxcDomainDetachDeviceConfig(virDomainDefPtr vmDef ATTRIBUTE_UNUSED,
+ virDomainDeviceDefPtr dev)
+{
+ int ret = -1;
+
+ switch (dev->type) {
+ default:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("persistent detach of device is not supported"));
+ break;
+ }
+
+ return ret;
+}
+
+
+static int
+lxcDomainAttachDeviceLive(virLXCDriverPtr driver ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm ATTRIBUTE_UNUSED,
+ virDomainDeviceDefPtr dev)
+{
+ int ret = -1;
+
+ switch (dev->type) {
+ default:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("device type '%s' cannot be attached"),
+ virDomainDeviceTypeToString(dev->type));
+ break;
+ }
+
+ return ret;
+}
+
+
+static int
+lxcDomainDetachDeviceLive(virLXCDriverPtr driver ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm ATTRIBUTE_UNUSED,
+ virDomainDeviceDefPtr dev)
+{
+ int ret = -1;
+
+ switch (dev->type) {
+ default:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("device type '%s' cannot be detached"),
+ virDomainDeviceTypeToString(dev->type));
+ break;
+ }
+
+ return ret;
+}
+
+
+/* Actions for lxcDomainModifyDeviceFlags */
+enum {
+ LXC_DEVICE_ATTACH,
+ LXC_DEVICE_UPDATE,
+ LXC_DEVICE_DETACH,
+};
+
+
+static int
+lxcDomainModifyDeviceFlags(virDomainPtr dom, const char *xml,
+ unsigned int flags, int action)
+{
+ virLXCDriverPtr driver = dom->conn->privateData;
+ virDomainObjPtr vm = NULL;
+ virDomainDefPtr vmdef = NULL;
+ virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
+ int ret = -1;
+ unsigned int affect;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG |
+ (action == LXC_DEVICE_UPDATE ?
+ VIR_DOMAIN_DEVICE_MODIFY_FORCE : 0), -1);
+
+ affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);
+
+ lxcDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ virReportError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"),
uuidstr);
+ goto cleanup;
+ }
+
+ if (virDomainObjIsActive(vm)) {
+ if (affect == VIR_DOMAIN_AFFECT_CURRENT)
+ flags |= VIR_DOMAIN_AFFECT_LIVE;
+ } else {
+ if (affect == VIR_DOMAIN_AFFECT_CURRENT)
+ flags |= VIR_DOMAIN_AFFECT_CONFIG;
+ /* check consistency between flags and the vm state */
+ if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("cannot do live update a device on "
+ "inactive domain"));
+ goto cleanup;
+ }
+ }
+
+ if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("cannot modify device on transient domain"));
+ goto cleanup;
+ }
+
+ dev = dev_copy = virDomainDeviceDefParse(driver->caps, vm->def, xml,
+ VIR_DOMAIN_XML_INACTIVE);
+ if (dev == NULL)
+ goto cleanup;
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
+ flags & VIR_DOMAIN_AFFECT_LIVE) {
+ /* If we are affecting both CONFIG and LIVE
+ * create a deep copy of device as adding
+ * to CONFIG takes one instance.
+ */
+ dev_copy = virDomainDeviceDefCopy(driver->caps, vm->def, dev);
+ if (!dev_copy)
+ goto cleanup;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ if (virDomainDefCompatibleDevice(vm->def, dev) < 0)
+ goto cleanup;
+
+ /* Make a copy for updated domain. */
+ vmdef = virDomainObjCopyPersistentDef(driver->caps, vm);
+ if (!vmdef)
+ goto cleanup;
+ switch (action) {
+ case LXC_DEVICE_ATTACH:
+ ret = lxcDomainAttachDeviceConfig(vmdef, dev);
+ break;
+ case LXC_DEVICE_DETACH:
+ ret = lxcDomainDetachDeviceConfig(vmdef, dev);
+ break;
+ case LXC_DEVICE_UPDATE:
+ ret = lxcDomainUpdateDeviceConfig(vmdef, dev);
+ break;
+ default:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown domain modify action %d"), action);
+ break;
+ }
+
+ if (ret == -1)
+ goto cleanup;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ if (virDomainDefCompatibleDevice(vm->def, dev_copy) < 0)
+ goto cleanup;
+
+ switch (action) {
+ case LXC_DEVICE_ATTACH:
+ ret = lxcDomainAttachDeviceLive(driver, vm, dev_copy);
+ break;
+ case LXC_DEVICE_DETACH:
+ ret = lxcDomainDetachDeviceLive(driver, vm, dev_copy);
+ break;
+ default:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown domain modify action %d"), action);
+ ret = -1;
+ break;
+ }
+
+ if (ret == -1)
+ goto cleanup;
+ /*
+ * update domain status forcibly because the domain status may be
+ * changed even if we failed to attach the device. For example,
+ * a new controller may be created.
+ */
+ if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
+ ret = -1;
+ goto cleanup;
+ }
+ }
+
+ /* Finally, if no error until here, we can save config. */
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ ret = virDomainSaveConfig(driver->configDir, vmdef);
+ if (!ret) {
+ virDomainObjAssignDef(vm, vmdef, false);
+ vmdef = NULL;
+ }
+ }
+
+cleanup:
+ virDomainDefFree(vmdef);
+ if (dev != dev_copy)
+ virDomainDeviceDefFree(dev_copy);
+ virDomainDeviceDefFree(dev);
+ if (vm)
+ virDomainObjUnlock(vm);
+ lxcDriverUnlock(driver);
+ return ret;
+}
+
+
+static int lxcDomainAttachDeviceFlags(virDomainPtr dom,
+ const char *xml,
+ unsigned int flags)
+{
+ return lxcDomainModifyDeviceFlags(dom, xml, flags,
+ LXC_DEVICE_ATTACH);
+}
+
+
+static int lxcDomainAttachDevice(virDomainPtr dom,
+ const char *xml)
+{
+ return lxcDomainAttachDeviceFlags(dom, xml,
+ VIR_DOMAIN_AFFECT_LIVE);
+}
+
+
+static int lxcDomainUpdateDeviceFlags(virDomainPtr dom,
+ const char *xml,
+ unsigned int flags)
+{
+ return lxcDomainModifyDeviceFlags(dom, xml, flags,
+ LXC_DEVICE_UPDATE);
+}
+
+
+static int lxcDomainDetachDeviceFlags(virDomainPtr dom,
+ const char *xml,
+ unsigned int flags)
+{
+ return lxcDomainModifyDeviceFlags(dom, xml, flags,
+ LXC_DEVICE_DETACH);
+}
+
+
+static int lxcDomainDetachDevice(virDomainPtr dom,
+ const char *xml)
+{
+ return lxcDomainDetachDeviceFlags(dom, xml,
+ VIR_DOMAIN_AFFECT_LIVE);
+}
+
/* Function Tables */
static virDriver lxcDriver = {
.no = VIR_DRV_LXC,
@@ -2809,6 +3094,11 @@ static virDriver lxcDriver = {
.domainDefineXML = lxcDomainDefine, /* 0.4.2 */
.domainUndefine = lxcDomainUndefine, /* 0.4.2 */
.domainUndefineFlags = lxcDomainUndefineFlags, /* 0.9.4 */
+ .domainAttachDevice = lxcDomainAttachDevice, /* 1.0.1 */
+ .domainAttachDeviceFlags = lxcDomainAttachDeviceFlags, /* 1.0.1 */
+ .domainDetachDevice = lxcDomainDetachDevice, /* 1.0.1 */
+ .domainDetachDeviceFlags = lxcDomainDetachDeviceFlags, /* 1.0.1 */
+ .domainUpdateDeviceFlags = lxcDomainUpdateDeviceFlags, /* 1.0.1 */
.domainGetAutostart = lxcDomainGetAutostart, /* 0.7.0 */
.domainSetAutostart = lxcDomainSetAutostart, /* 0.7.0 */
.domainGetSchedulerType = lxcGetSchedulerType, /* 0.5.0 */
--
1.8.0.1