/* * 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 * Copyright (C) 2012 Ata E Husain Bohra * * 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 * . * */ #include #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.: * [] * 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 */ };