diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 7128bfa115..cf7820af13 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -4362,6 +4362,34 @@ testConnectFindStoragePoolSources(virConnectPtr conn ATTRIBUTE_UNUSED, } +static virNodeDeviceObjPtr +testNodeDeviceMockCreateVport(testDriverPtr driver, + const char *wwnn, + const char *wwpn); +static int +testCreateVport(testDriverPtr driver, + const char *wwnn, + const char *wwpn) +{ + virNodeDeviceObjPtr obj = NULL; + /* The storage_backend_scsi createVport() will use the input adapter + * fields parent name, parent_wwnn/parent_wwpn, or parent_fabric_wwn + * in order to determine whether the provided parent can be used to + * create a vHBA or will find "an available vport capable" to create + * a vHBA. In order to do this, it uses the virVHBA* API's which traverse + * the sysfs looking at various fields (rather than going via nodedev). + * + * Since the test environ doesn't have the sysfs for the storage pool + * test, at least for now use the node device test infrastructure to + * create the vHBA. In the long run the result is the same. */ + if (!(obj = testNodeDeviceMockCreateVport(driver, wwnn, wwpn))) + return -1; + virNodeDeviceObjUnlock(obj); + + return 0; +} + + static virStoragePoolPtr testStoragePoolCreateXML(virConnectPtr conn, const char *xml, @@ -4392,6 +4420,21 @@ testStoragePoolCreateXML(virConnectPtr conn, goto cleanup; def = NULL; + if (pool->def->source.adapter.type == + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) { + /* In the real code, we'd call virVHBAManageVport followed by + * find_new_device, but we cannot do that here since we're not + * mocking udev. The mock routine will copy an existing vHBA and + * rename a few fields to mock that. */ + if (testCreateVport(privconn, + pool->def->source.adapter.data.fchost.wwnn, + pool->def->source.adapter.data.fchost.wwpn) < 0) { + virStoragePoolObjRemove(&privconn->pools, pool); + pool = NULL; + goto cleanup; + } + } + if (testStoragePoolObjSetDefaults(pool) == -1) { virStoragePoolObjRemove(&privconn->pools, pool); pool = NULL; @@ -4522,6 +4565,44 @@ testStoragePoolBuild(virStoragePoolPtr pool, } +static int +testDestroyVport(testDriverPtr privconn, + const char *wwnn ATTRIBUTE_UNUSED, + const char *wwpn ATTRIBUTE_UNUSED) +{ + int ret = -1; + virNodeDeviceObjPtr obj = NULL; + virObjectEventPtr event = NULL; + + /* NB: Cannot use virVHBAGetHostByWWN (yet) like the storage_backend_scsi + * deleteVport() helper since that traverses the file system looking for + * the wwnn/wwpn. So our choice short term is to cheat and use the name + * (scsi_host12) we know was created. + * + * Reaching across the boundaries of space and time into the + * Node Device in order to remove */ + if (!(obj = virNodeDeviceObjFindByName(&privconn->devs, "scsi_host12"))) { + virReportError(VIR_ERR_NO_NODE_DEVICE, "%s", + _("no node device with matching name 'scsi_host12'")); + goto cleanup; + } + + event = virNodeDeviceEventLifecycleNew("scsi_host12", + VIR_NODE_DEVICE_EVENT_DELETED, + 0); + + virNodeDeviceObjRemove(&privconn->devs, &obj); + + ret = 0; + + cleanup: + if (obj) + virNodeDeviceObjUnlock(obj); + testObjectEventQueue(privconn, event); + return ret; +} + + static int testStoragePoolDestroy(virStoragePoolPtr pool) { @@ -4540,7 +4621,17 @@ testStoragePoolDestroy(virStoragePoolPtr pool) } privpool->active = 0; - event = virStoragePoolEventLifecycleNew(privpool->def->name, privpool->def->uuid, + + if (privpool->def->source.adapter.type == + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) { + if (testDestroyVport(privconn, + privpool->def->source.adapter.data.fchost.wwnn, + privpool->def->source.adapter.data.fchost.wwpn) < 0) + goto cleanup; + } + + event = virStoragePoolEventLifecycleNew(privpool->def->name, + privpool->def->uuid, VIR_STORAGE_POOL_EVENT_STOPPED, 0); diff --git a/tests/fchosttest.c b/tests/fchosttest.c index 51fdcbd478..dc6b9af988 100644 --- a/tests/fchosttest.c +++ b/tests/fchosttest.c @@ -75,6 +75,19 @@ static const char test10_xml[] = " " ""; +/* virStoragePoolCreateXML using parent='%s' to find the vport capable HBA */ +static const char test11_xml[] = +"" +" vhba_pool" +" " +" " +" " +" " +" /dev/disk/by-path" +" " +""; + + /* Test virIsVHBACapable */ static int test1(const void *data ATTRIBUTE_UNUSED) @@ -275,6 +288,54 @@ manageVHBAByNodeDevice(const void *data) } +/* Test manageVHBAByStoragePool + * - Test both virStoragePoolCreateXML and virStoragePoolDestroy + * - Create a storage pool vHBA allowing usage of various different + * methods based on the input data/xml argument. + * - Be sure that it's possible to destroy the storage pool as well. + */ +static int +manageVHBAByStoragePool(const void *data) +{ + const char *expect_hostname = "scsi_host12"; + virConnectPtr conn = NULL; + virStoragePoolPtr pool = NULL; + virNodeDevicePtr dev = NULL; + int ret = -1; + const char *vhba = data; + + if (!(conn = virConnectOpen("test:///default"))) + return -1; + + if (!(pool = virStoragePoolCreateXML(conn, vhba, 0))) + goto cleanup; + + if (!(dev = virNodeDeviceLookupByName(conn, expect_hostname))) { + VIR_DEBUG("Failed to find expected_hostname '%s'", expect_hostname); + ignore_value(virStoragePoolDestroy(pool)); + goto cleanup; + } + + if (virStoragePoolDestroy(pool) < 0) + goto cleanup; + + if ((dev = virNodeDeviceLookupByName(conn, expect_hostname))) { + VIR_DEBUG("Found expected_hostname '%s' after destroy", + expect_hostname); + goto cleanup; + } + + ret = 0; + + cleanup: + if (pool) + virStoragePoolFree(pool); + if (conn) + virConnectClose(conn); + return ret; +} + + static int mymain(void) { @@ -310,6 +371,9 @@ mymain(void) if (virTestRun("manageVHBAByNodeDevice-parent-fabric-wwn", manageVHBAByNodeDevice, test10_xml) < 0) ret = -1; + if (virTestRun("manageVHBAByStoragePool-by-parent", manageVHBAByStoragePool, + test11_xml) < 0) + ret = -1; cleanup: VIR_FREE(fchost_prefix);