libvirt/src/esx/esx_storage_driver.c
Daniel P. Berrange 55ea7be7d9 Removing probing of secondary drivers
For stateless, client side drivers, it is never correct to
probe for secondary drivers. It is only ever appropriate to
use the secondary driver that is associated with the
hypervisor in question. As a result the ESX & HyperV drivers
have both been forced to do hacks where they register no-op
drivers for the ones they don't implement.

For stateful, server side drivers, we always just want to
use the same built-in shared driver. The exception is
virtualbox which is really a stateless driver and so wants
to use its own server side secondary drivers. To deal with
this virtualbox has to be built as 3 separate loadable
modules to allow registration to work in the right order.

This can all be simplified by introducing a new struct
recording the precise set of secondary drivers each
hypervisor driver wants

struct _virConnectDriver {
    virHypervisorDriverPtr hypervisorDriver;
    virInterfaceDriverPtr interfaceDriver;
    virNetworkDriverPtr networkDriver;
    virNodeDeviceDriverPtr nodeDeviceDriver;
    virNWFilterDriverPtr nwfilterDriver;
    virSecretDriverPtr secretDriver;
    virStorageDriverPtr storageDriver;
};

Instead of registering the hypervisor driver, we now
just register a virConnectDriver instead. This allows
us to remove all probing of secondary drivers. Once we
have chosen the primary driver, we immediately know the
correct secondary drivers to use.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2015-01-27 12:02:04 +00:00

548 lines
14 KiB
C

/*
* esx_storage_driver.c: storage driver functions for managing VMware ESX
* host storage
*
* Copyright (C) 2010-2011 Red Hat, Inc.
* Copyright (C) 2010-2012 Matthias Bolte <matthias.bolte@googlemail.com>
* Copyright (C) 2012 Ata E Husain Bohra <ata.husain@hotmail.com>
*
* 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
* <http://www.gnu.org/licenses/>.
*
*/
#include <config.h>
#include "viruuid.h"
#include "viralloc.h"
#include "storage_conf.h"
#include "esx_private.h"
#include "esx_storage_driver.h"
#include "esx_storage_backend_vmfs.h"
#include "esx_storage_backend_iscsi.h"
#define VIR_FROM_THIS VIR_FROM_ESX
/*
* ESX storage driver implements a facade pattern;
* the driver exposes the routines supported by libvirt
* public interface to manage ESX storage devices. Internally
* it uses backend drivers to perform the required task.
*/
enum {
VMFS = 0,
ISCSI,
LAST_BACKEND
};
static virStorageDriverPtr backends[] = {
&esxStorageBackendVMFS,
&esxStorageBackendISCSI
};
static int
esxConnectNumOfStoragePools(virConnectPtr conn)
{
int count = 0;
esxPrivate *priv = conn->privateData;
size_t i;
int tmp;
if (esxVI_EnsureSession(priv->primary) < 0)
return -1;
for (i = 0; i < LAST_BACKEND; ++i) {
tmp = backends[i]->connectNumOfStoragePools(conn);
if (tmp < 0)
return -1;
count += tmp;
}
return count;
}
static int
esxConnectListStoragePools(virConnectPtr conn, char **const names, int maxnames)
{
bool success = false;
esxPrivate *priv = conn->privateData;
int count = 0;
size_t i;
int tmp;
if (maxnames == 0)
return 0;
if (esxVI_EnsureSession(priv->primary) < 0)
return -1;
for (i = 0; i < LAST_BACKEND; ++i) {
tmp = backends[i]->connectListStoragePools(conn, &names[count], maxnames - count);
if (tmp < 0)
goto cleanup;
count += tmp;
}
success = true;
cleanup:
if (! success) {
for (i = 0; i < count; ++i)
VIR_FREE(names[i]);
count = -1;
}
return count;
}
static int
esxConnectNumOfDefinedStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED)
{
/* ESX storage pools are always active */
return 0;
}
static int
esxConnectListDefinedStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED,
char **const names ATTRIBUTE_UNUSED,
int maxnames ATTRIBUTE_UNUSED)
{
/* ESX storage pools are always active */
return 0;
}
static virStoragePoolPtr
esxStoragePoolLookupByName(virConnectPtr conn, const char *name)
{
esxPrivate *priv = conn->privateData;
size_t i;
virStoragePoolPtr pool;
virCheckNonNullArgReturn(name, NULL);
if (esxVI_EnsureSession(priv->primary) < 0)
return NULL;
for (i = 0; i < LAST_BACKEND; ++i) {
pool = backends[i]->storagePoolLookupByName(conn, name);
if (pool)
return pool;
}
virReportError(VIR_ERR_NO_STORAGE_POOL,
_("Could not find storage pool with name '%s'"), name);
return NULL;
}
static virStoragePoolPtr
esxStoragePoolLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
esxPrivate *priv = conn->privateData;
size_t i;
virStoragePoolPtr pool;
char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
if (esxVI_EnsureSession(priv->primary) < 0)
return NULL;
/* invoke backend drive method to search all known pools */
for (i = 0; i < LAST_BACKEND; ++i) {
pool = backends[i]->storagePoolLookupByUUID(conn, uuid);
if (pool)
return pool;
}
virUUIDFormat(uuid, uuid_string);
virReportError(VIR_ERR_NO_STORAGE_POOL,
_("Could not find storage pool with uuid '%s'"),
uuid_string);
return NULL;
}
static virStoragePoolPtr
esxStoragePoolLookupByVolume(virStorageVolPtr volume)
{
return esxStoragePoolLookupByName(volume->conn, volume->pool);
}
static int
esxStoragePoolRefresh(virStoragePoolPtr pool, unsigned int flags)
{
esxPrivate *priv = pool->conn->privateData;
virStorageDriverPtr backend = pool->privateData;
virCheckNonNullArgReturn(pool->privateData, -1);
if (esxVI_EnsureSession(priv->primary) < 0)
return -1;
return backend->storagePoolRefresh(pool, flags);
}
static int
esxStoragePoolGetInfo(virStoragePoolPtr pool, virStoragePoolInfoPtr info)
{
esxPrivate *priv = pool->conn->privateData;
virStorageDriverPtr backend = pool->privateData;
virCheckNonNullArgReturn(pool->privateData, -1);
memset(info, 0, sizeof(*info));
if (esxVI_EnsureSession(priv->primary) < 0)
return -1;
return backend->storagePoolGetInfo(pool, info);
}
static char *
esxStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
{
esxPrivate *priv = pool->conn->privateData;
virStorageDriverPtr backend = pool->privateData;
virCheckNonNullArgReturn(pool->privateData, NULL);
if (esxVI_EnsureSession(priv->primary) < 0)
return NULL;
return backend->storagePoolGetXMLDesc(pool, flags);
}
static int
esxStoragePoolGetAutostart(virStoragePoolPtr pool ATTRIBUTE_UNUSED,
int *autostart)
{
/* ESX storage pools are always active */
*autostart = 1;
return 0;
}
static int
esxStoragePoolSetAutostart(virStoragePoolPtr pool ATTRIBUTE_UNUSED,
int autostart)
{
/* Just accept autostart activation, but fail on autostart deactivation */
autostart = (autostart != 0);
if (! autostart) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot deactivate storage pool autostart"));
return -1;
}
return 0;
}
static int
esxStoragePoolNumOfVolumes(virStoragePoolPtr pool)
{
esxPrivate *priv = pool->conn->privateData;
virStorageDriverPtr backend = pool->privateData;
virCheckNonNullArgReturn(pool->privateData, -1);
if (esxVI_EnsureSession(priv->primary) < 0)
return -1;
return backend->storagePoolNumOfVolumes(pool);
}
static int
esxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names,
int maxnames)
{
esxPrivate *priv = pool->conn->privateData;
virStorageDriverPtr backend = pool->privateData;
virCheckNonNullArgReturn(pool->privateData, -1);
if (esxVI_EnsureSession(priv->primary) < 0)
return -1;
return backend->storagePoolListVolumes(pool, names, maxnames);
}
static virStorageVolPtr
esxStorageVolLookupByName(virStoragePoolPtr pool, const char *name)
{
esxPrivate *priv = pool->conn->privateData;
virStorageDriverPtr backend = pool->privateData;
virCheckNonNullArgReturn(pool->privateData, NULL);
if (esxVI_EnsureSession(priv->primary) < 0)
return NULL;
return backend->storageVolLookupByName(pool, name);
}
static virStorageVolPtr
esxStorageVolLookupByPath(virConnectPtr conn, const char *path)
{
esxPrivate *priv = conn->privateData;
if (esxVI_EnsureSession(priv->primary) < 0)
return NULL;
/*
* FIXME: calling backends blindly may set unwanted error codes
*
* VMFS Datastore path follows canonical format i.e.:
* [<datastore_name>] <file_path>
* WHEREAS
* iSCSI LUNs device path follows normal linux path convention
*/
if (STRPREFIX(path, "[")) {
return backends[VMFS]->storageVolLookupByPath(conn, path);
} else if (STRPREFIX(path, "/")) {
return backends[ISCSI]->storageVolLookupByPath(conn, path);
} else {
virReportError(VIR_ERR_INVALID_ARG,
_("Unexpected volume path format: %s"), path);
return NULL;
}
}
static virStorageVolPtr
esxStorageVolLookupByKey(virConnectPtr conn, const char *key)
{
virStorageVolPtr volume;
esxPrivate *priv = conn->privateData;
size_t i;
if (esxVI_EnsureSession(priv->primary) < 0)
return NULL;
for (i = 0; i < LAST_BACKEND; ++i) {
volume = backends[i]->storageVolLookupByKey(conn, key);
if (volume)
return volume;
}
virReportError(VIR_ERR_NO_STORAGE_VOL,
_("Could not find storage volume with key '%s'"),
key);
return NULL;
}
static virStorageVolPtr
esxStorageVolCreateXML(virStoragePoolPtr pool, const char *xmldesc,
unsigned int flags)
{
esxPrivate *priv = pool->conn->privateData;
virStorageDriverPtr backend = pool->privateData;
virCheckNonNullArgReturn(pool->privateData, NULL);
if (esxVI_EnsureSession(priv->primary) < 0)
return NULL;
return backend->storageVolCreateXML(pool, xmldesc, flags);
}
static virStorageVolPtr
esxStorageVolCreateXMLFrom(virStoragePoolPtr pool, const char *xmldesc,
virStorageVolPtr sourceVolume, unsigned int flags)
{
esxPrivate *priv = pool->conn->privateData;
virStorageDriverPtr backend = pool->privateData;
virCheckNonNullArgReturn(pool->privateData, NULL);
if (esxVI_EnsureSession(priv->primary) < 0)
return NULL;
return backend->storageVolCreateXMLFrom(pool, xmldesc, sourceVolume, flags);
}
static int
esxStorageVolDelete(virStorageVolPtr volume, unsigned int flags)
{
esxPrivate *priv = volume->conn->privateData;
virStorageDriverPtr backend = volume->privateData;
virCheckNonNullArgReturn(volume->privateData, -1);
if (esxVI_EnsureSession(priv->primary) < 0)
return -1;
return backend->storageVolDelete(volume, flags);
}
static int
esxStorageVolWipe(virStorageVolPtr volume, unsigned int flags)
{
esxPrivate *priv = volume->conn->privateData;
virStorageDriverPtr backend = volume->privateData;
virCheckNonNullArgReturn(volume->privateData, -1);
if (esxVI_EnsureSession(priv->primary) < 0)
return -1;
return backend->storageVolWipe(volume, flags);
}
static int
esxStorageVolGetInfo(virStorageVolPtr volume, virStorageVolInfoPtr info)
{
esxPrivate *priv = volume->conn->privateData;
virStorageDriverPtr backend = volume->privateData;
virCheckNonNullArgReturn(volume->privateData, -1);
if (esxVI_EnsureSession(priv->primary) < 0)
return -1;
return backend->storageVolGetInfo(volume, info);
}
static char *
esxStorageVolGetXMLDesc(virStorageVolPtr volume, unsigned int flags)
{
esxPrivate *priv = volume->conn->privateData;
virStorageDriverPtr backend = volume->privateData;
virCheckNonNullArgReturn(volume->privateData, NULL);
if (esxVI_EnsureSession(priv->primary) < 0)
return NULL;
return backend->storageVolGetXMLDesc(volume, flags);
}
static char *
esxStorageVolGetPath(virStorageVolPtr volume)
{
esxPrivate *priv = volume->conn->privateData;
virStorageDriverPtr backend = volume->privateData;
virCheckNonNullArgReturn(volume->privateData, NULL);
if (esxVI_EnsureSession(priv->primary) < 0)
return NULL;
return backend->storageVolGetPath(volume);
}
static int
esxStoragePoolIsActive(virStoragePoolPtr pool ATTRIBUTE_UNUSED)
{
/* ESX storage pools are always active */
return 1;
}
static int
esxStoragePoolIsPersistent(virStoragePoolPtr pool ATTRIBUTE_UNUSED)
{
/* ESX has no concept of transient pools, so all of them are persistent */
return 1;
}
virStorageDriver esxStorageDriver = {
.connectNumOfStoragePools = esxConnectNumOfStoragePools, /* 0.8.2 */
.connectListStoragePools = esxConnectListStoragePools, /* 0.8.2 */
.connectNumOfDefinedStoragePools = esxConnectNumOfDefinedStoragePools, /* 0.8.2 */
.connectListDefinedStoragePools = esxConnectListDefinedStoragePools, /* 0.8.2 */
.storagePoolLookupByName = esxStoragePoolLookupByName, /* 0.8.2 */
.storagePoolLookupByUUID = esxStoragePoolLookupByUUID, /* 0.8.2 */
.storagePoolLookupByVolume = esxStoragePoolLookupByVolume, /* 0.8.4 */
.storagePoolRefresh = esxStoragePoolRefresh, /* 0.8.2 */
.storagePoolGetInfo = esxStoragePoolGetInfo, /* 0.8.2 */
.storagePoolGetXMLDesc = esxStoragePoolGetXMLDesc, /* 0.8.2 */
.storagePoolGetAutostart = esxStoragePoolGetAutostart, /* 0.8.2 */
.storagePoolSetAutostart = esxStoragePoolSetAutostart, /* 0.8.2 */
.storagePoolNumOfVolumes = esxStoragePoolNumOfVolumes, /* 0.8.4 */
.storagePoolListVolumes = esxStoragePoolListVolumes, /* 0.8.4 */
.storageVolLookupByName = esxStorageVolLookupByName, /* 0.8.4 */
.storageVolLookupByPath = esxStorageVolLookupByPath, /* 0.8.4 */
.storageVolLookupByKey = esxStorageVolLookupByKey, /* 0.8.4 */
.storageVolCreateXML = esxStorageVolCreateXML, /* 0.8.4 */
.storageVolCreateXMLFrom = esxStorageVolCreateXMLFrom, /* 0.8.7 */
.storageVolDelete = esxStorageVolDelete, /* 0.8.7 */
.storageVolWipe = esxStorageVolWipe, /* 0.8.7 */
.storageVolGetInfo = esxStorageVolGetInfo, /* 0.8.4 */
.storageVolGetXMLDesc = esxStorageVolGetXMLDesc, /* 0.8.4 */
.storageVolGetPath = esxStorageVolGetPath, /* 0.8.4 */
.storagePoolIsActive = esxStoragePoolIsActive, /* 0.8.2 */
.storagePoolIsPersistent = esxStoragePoolIsPersistent, /* 0.8.2 */
};