From: Michal Privoznik <mprivozn(a)redhat.com>
Changes from previous version:
1) don't print extra/incorrect error on format failure.
2) use cleanup: instead of no_memory: and end:
3) always clear out the destination list at the start.
4) remove bogus "conn->ref++"
---
src/conf/interface_conf.c | 38 ++++++++++++++++++++
src/conf/interface_conf.h | 3 ++
src/libvirt_private.syms | 1 +
src/test/test_driver.c | 83 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 125 insertions(+), 0 deletions(-)
diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c
index f3848bd..10377e7 100644
--- a/src/conf/interface_conf.c
+++ b/src/conf/interface_conf.c
@@ -1227,6 +1227,44 @@ void virInterfaceObjListFree(virInterfaceObjListPtr interfaces)
interfaces->count = 0;
}
+int virInterfaceObjListClone(virInterfaceObjListPtr src,
+ virInterfaceObjListPtr dest)
+{
+ int ret = -1;
+ unsigned int i, cnt;
+
+ if (!src || !dest)
+ goto cleanup;
+
+ virInterfaceObjListFree(dest); /* start with an empty list */
+ cnt = src->count;
+ for (i = 0; i < cnt; i++) {
+ virInterfaceDefPtr def = src->objs[i]->def;
+ virInterfaceDefPtr backup;
+ virInterfaceObjPtr iface;
+ char *xml = virInterfaceDefFormat(def);
+
+ if (!xml)
+ goto cleanup;
+
+ if ((backup = virInterfaceDefParseString(xml)) == NULL) {
+ VIR_FREE(xml);
+ goto cleanup;
+ }
+
+ VIR_FREE(xml);
+ if ((iface = virInterfaceAssignDef(dest, backup)) == NULL)
+ goto cleanup;
+ virInterfaceObjUnlock(iface); /* was locked by virInterfaceAssignDef */
+ }
+
+ ret = cnt;
+cleanup:
+ if ((ret < 0) && dest)
+ virInterfaceObjListFree(dest);
+ return ret;
+}
+
virInterfaceObjPtr virInterfaceAssignDef(virInterfaceObjListPtr interfaces,
const virInterfaceDefPtr def)
{
diff --git a/src/conf/interface_conf.h b/src/conf/interface_conf.h
index 6073b49..c5630d4 100644
--- a/src/conf/interface_conf.h
+++ b/src/conf/interface_conf.h
@@ -192,6 +192,9 @@ virInterfaceObjPtr virInterfaceFindByName(const
virInterfaceObjListPtr
void virInterfaceDefFree(virInterfaceDefPtr def);
void virInterfaceObjFree(virInterfaceObjPtr iface);
void virInterfaceObjListFree(virInterfaceObjListPtr vms);
+int virInterfaceObjListClone(virInterfaceObjListPtr src,
+ virInterfaceObjListPtr dest);
+
virInterfaceObjPtr virInterfaceAssignDef(virInterfaceObjListPtr interfaces,
const virInterfaceDefPtr def);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 4cb8dda..5f7fdb2 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -485,6 +485,7 @@ virInterfaceDefParseNode;
virInterfaceDefParseString;
virInterfaceFindByMACString;
virInterfaceFindByName;
+virInterfaceObjListClone;
virInterfaceObjListFree;
virInterfaceObjLock;
virInterfaceObjUnlock;
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index e86bc4e..b703e9b 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -85,6 +85,8 @@ struct _testConn {
virDomainObjList domains;
virNetworkObjList networks;
virInterfaceObjList ifaces;
+ bool transaction_running;
+ virInterfaceObjList backupIfaces;
virStoragePoolObjList pools;
virNodeDeviceObjList devs;
int numCells;
@@ -3455,6 +3457,84 @@ cleanup:
return ret;
}
+static int testInterfaceChangeBegin(virConnectPtr conn,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ testConnPtr privconn = conn->privateData;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ if (privconn->transaction_running) {
+ testError(VIR_ERR_OPERATION_INVALID,
+ _("there is another transaction running."));
+ goto cleanup;
+ }
+
+ privconn->transaction_running = true;
+
+ if (virInterfaceObjListClone(&privconn->ifaces,
+ &privconn->backupIfaces) < 0)
+ goto cleanup;
+
+ ret = 0;
+cleanup:
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int testInterfaceChangeCommit(virConnectPtr conn,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ testConnPtr privconn = conn->privateData;
+ int ret = -1;
+
+ testDriverLock(privconn);
+
+ if (!privconn->transaction_running) {
+ testError(VIR_ERR_OPERATION_INVALID, _("no transaction running, "
+ "nothing to be commited."));
+ goto cleanup;
+ }
+
+ virInterfaceObjListFree(&privconn->backupIfaces);
+ privconn->transaction_running = false;
+
+ ret = 0;
+
+cleanup:
+ testDriverUnlock(privconn);
+
+ return ret;
+}
+
+static int testInterfaceChangeRollback(virConnectPtr conn,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ testConnPtr privconn = conn->privateData;
+ int ret = -1;
+
+ testDriverLock(privconn);
+
+ if (!privconn->transaction_running) {
+ testError(VIR_ERR_OPERATION_INVALID, _("no transaction running, "
+ "nothing to rollback."));
+ goto cleanup;
+ }
+
+ virInterfaceObjListFree(&privconn->ifaces);
+ privconn->ifaces.count = privconn->backupIfaces.count;
+ privconn->ifaces.objs = privconn->backupIfaces.objs;
+ privconn->backupIfaces.count = 0;
+ privconn->backupIfaces.objs = NULL;
+
+ privconn->transaction_running = false;
+
+ ret = 0;
+
+cleanup:
+ testDriverUnlock(privconn);
+ return ret;
+}
static char *testInterfaceGetXMLDesc(virInterfacePtr iface,
unsigned int flags ATTRIBUTE_UNUSED)
@@ -5428,6 +5508,9 @@ static virInterfaceDriver testInterfaceDriver = {
.interfaceCreate = testInterfaceCreate, /* 0.7.0 */
.interfaceDestroy = testInterfaceDestroy, /* 0.7.0 */
.interfaceIsActive = testInterfaceIsActive, /* 0.7.3 */
+ .interfaceChangeBegin = testInterfaceChangeBegin, /* 0.9.2 */
+ .interfaceChangeCommit = testInterfaceChangeCommit, /* 0.9.2 */
+ .interfaceChangeRollback = testInterfaceChangeRollback, /* 0.9.2 */
};
--
1.7.3.4