[libvirt] [libvirt-glib] Add getter for GVirConfigDomainOS.arch
by Zeeshan Ali (Khattak)
From: "Zeeshan Ali (Khattak)" <zeeshanak(a)gnome.org>
---
libvirt-gconfig/libvirt-gconfig-domain-os.c | 7 +++++++
libvirt-gconfig/libvirt-gconfig-domain-os.h | 1 +
libvirt-gconfig/libvirt-gconfig.sym | 1 +
3 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-os.c b/libvirt-gconfig/libvirt-gconfig-domain-os.c
index 9a1648a..2e4a69a 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-os.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-os.c
@@ -275,6 +275,13 @@ GList *gvir_config_domain_os_get_boot_devices(GVirConfigDomainOs *os)
return devices;
}
+const char *gvir_config_domain_os_get_arch(GVirConfigDomainOs *os)
+{
+ return gvir_config_object_get_attribute(GVIR_CONFIG_OBJECT(os),
+ "type",
+ "arch");
+}
+
void gvir_config_domain_os_set_arch(GVirConfigDomainOs *os, const char *arch)
{
xmlNodePtr os_node;
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-os.h b/libvirt-gconfig/libvirt-gconfig-domain-os.h
index 832e275..62c1fbe 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-os.h
+++ b/libvirt-gconfig/libvirt-gconfig-domain-os.h
@@ -83,6 +83,7 @@ GVirConfigDomainOs *gvir_config_domain_os_new(void);
GVirConfigDomainOs *gvir_config_domain_os_new_from_xml(const gchar *xml, GError **error);
void gvir_config_domain_os_set_os_type(GVirConfigDomainOs *os, GVirConfigDomainOsType type);
+const char *gvir_config_domain_os_get_arch(GVirConfigDomainOs *os);
void gvir_config_domain_os_set_arch(GVirConfigDomainOs *os, const char *arch);
GList *gvir_config_domain_os_get_boot_devices(GVirConfigDomainOs *os);
void gvir_config_domain_os_set_boot_devices(GVirConfigDomainOs *os, GList *boot_devices);
diff --git a/libvirt-gconfig/libvirt-gconfig.sym b/libvirt-gconfig/libvirt-gconfig.sym
index 6fd2ef2..11c01f1 100644
--- a/libvirt-gconfig/libvirt-gconfig.sym
+++ b/libvirt-gconfig/libvirt-gconfig.sym
@@ -379,6 +379,7 @@ LIBVIRT_GCONFIG_0.0.9 {
gvir_config_domain_get_os;
gvir_config_domain_get_virt_type;
+ gvir_config_domain_os_get_arch;
gvir_config_domain_os_get_boot_devices;
gvir_config_capabilities_get_host;
--
1.7.7.6
12 years, 8 months
[libvirt] [PATCH] virBuffer: add way to trim back extra text
by Eric Blake
I'm tired of writing:
bool sep = false;
while (...) {
if (sep)
virBufferAddChar(buf, ',');
sep = true;
virBufferAdd(buf, str);
}
This makes it easier, allowing one to write:
while (...)
virBufferAsprintf(buf, "%s,", str);
virBufferTrim(buf, ",", -1);
to trim any remaining comma.
* src/util/buf.h (virBufferTrim): Declare.
* src/util/buf.c (virBufferTrim): New function.
* tests/virbuftest.c (testBufTrim): Test it.
---
I've threatened to do this enough times, so I finally carried through
with my threat :)
src/util/buf.c | 36 +++++++++++++++++++++++++++++++++
src/util/buf.h | 2 +
tests/virbuftest.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 94 insertions(+), 0 deletions(-)
diff --git a/src/util/buf.c b/src/util/buf.c
index d18f6af..630e4c9 100644
--- a/src/util/buf.c
+++ b/src/util/buf.c
@@ -612,3 +612,39 @@ virBufferStrcat(virBufferPtr buf, ...)
virBufferAdd(buf, str, -1);
va_end(ap);
}
+
+/**
+ * virBufferTrim:
+ * @buf: the buffer to trim
+ * @str: the optional string, to force an exact trim
+ * @len: the number of bytes to trim, or -1 to use @str
+ *
+ * Trim the tail of a buffer. If @str is provided, the trim only occurs
+ * if the current tail of the buffer matches @str; a non-negative @len
+ * further limits how much of the tail is trimmed. If @str is NULL, then
+ * @len must be non-negative.
+ *
+ * Returns -1 if @buf has previously encountered an error or if @len is
+ * invalid, 0 if there was nothing to trim (@buf was too short or @str
+ * didn't match), and 1 if the trim was successful.
+ */
+int
+virBufferTrim(virBufferPtr buf, const char *str, int len)
+{
+ size_t len2 = 0;
+
+ if (!buf || buf->error || (!str && len < 0))
+ return -1;
+
+ if (len > 0 && len > buf->use)
+ return 0;
+ if (str) {
+ len2 = strlen(str);
+ if (len2 > buf->use ||
+ memcmp(&buf->content[buf->use - len2], str, len2) != 0)
+ return 0;
+ }
+ buf->use -= len < 0 ? len2 : len;
+ buf->content[buf->use] = '\0';
+ return 1;
+}
diff --git a/src/util/buf.h b/src/util/buf.h
index d6bc8f3..a8e2eb5 100644
--- a/src/util/buf.h
+++ b/src/util/buf.h
@@ -64,4 +64,6 @@ void virBufferURIEncodeString(virBufferPtr buf, const char *str);
void virBufferAdjustIndent(virBufferPtr buf, int indent);
int virBufferGetIndent(const virBufferPtr buf, bool dynamic);
+int virBufferTrim(virBufferPtr buf, const char *trim, int len);
+
#endif /* __VIR_BUFFER_H__ */
diff --git a/tests/virbuftest.c b/tests/virbuftest.c
index 9058920..cd02db1 100644
--- a/tests/virbuftest.c
+++ b/tests/virbuftest.c
@@ -133,6 +133,61 @@ static int testBufAutoIndent(const void *data ATTRIBUTE_UNUSED)
return ret;
}
+static int testBufTrim(const void *data ATTRIBUTE_UNUSED)
+{
+ virBuffer bufinit = VIR_BUFFER_INITIALIZER;
+ virBufferPtr buf = NULL;
+ char *result = NULL;
+ const char *expected = "a,b";
+ int ret = -1;
+ int i = 1;
+
+#define ACT(str, len, result) \
+ do { \
+ if (virBufferTrim(buf, str, len) != result) { \
+ TEST_ERROR("trim %d failed", i); \
+ goto cleanup; \
+ } \
+ i++; \
+ } while (0);
+
+ if (virBufferTrim(buf, "", 0) != -1) {
+ TEST_ERROR("Wrong failure detection 1");
+ goto cleanup;
+ }
+ buf = &bufinit;
+ if (virBufferTrim(buf, NULL, -1) != -1) {
+ TEST_ERROR("Wrong failure detection 2");
+ goto cleanup;
+ }
+
+ virBufferAddLit(buf, "a;");
+ ACT("", 0, 1);
+ ACT("", -1, 1);
+ ACT(NULL, 1, 1);
+ ACT(NULL, 5, 0);
+ ACT("a", 2, 0);
+
+ virBufferAddLit(buf, ",b,,");
+ ACT("b", -1, 0);
+ ACT("b,,", 1, 1);
+ ACT(",", -1, 1);
+
+ result = virBufferContentAndReset(buf);
+ if (!result || STRNEQ(result, expected)) {
+ virtTestDifference(stderr, expected, result);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virBufferFreeAndReset(buf);
+ VIR_FREE(result);
+ return ret;
+}
+
+
static int
mymain(void)
{
@@ -149,6 +204,7 @@ mymain(void)
DO_TEST("EscapeString infinite loop", testBufInfiniteLoop, 1);
DO_TEST("VSprintf infinite loop", testBufInfiniteLoop, 0);
DO_TEST("Auto-indentation", testBufAutoIndent, 0);
+ DO_TEST("Trim", testBufTrim, 0);
return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
--
1.7.7.6
12 years, 8 months
[libvirt] [PATCH] Fix dep from libvirt-lock-sanlock RPM
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
The libvirt-lock-sanlock RPM requires libvirtd, so its RPM dep
should be on libvirt-daemon, not libvirt
---
libvirt.spec.in | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 8c4a2fd..0a6872e 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -731,7 +731,7 @@ Group: Development/Libraries
Requires: sanlock >= 1.8
#for virt-sanlock-cleanup require augeas
Requires: augeas
-Requires: %{name} = %{version}-%{release}
+Requires: %{name}-daemon = %{version}-%{release}
%description lock-sanlock
Includes the Sanlock lock manager plugin for the QEMU
--
1.7.7.6
12 years, 8 months
[libvirt] [PATCH] build: fix unused variable after last patch
by Eric Blake
The previous commit (2cb0899) left a dead variable behind.
* src/libxl/libxl_driver.c (libxlClose): Drop dead variable.
---
Pushing under the build-breaker rule.
src/libxl/libxl_driver.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index fc90d16..500d51b 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -1079,8 +1079,6 @@ libxlOpen(virConnectPtr conn,
static int
libxlClose(virConnectPtr conn ATTRIBUTE_UNUSED)
{
- libxlDriverPrivatePtr driver = conn->privateData;
-
conn->privateData = NULL;
return 0;
}
--
1.7.7.6
12 years, 8 months
[libvirt] [PATCH] storage backend: Add RBD (RADOS Block Device) support
by Wido den Hollander
This patch adds support for a new storage backend with RBD support.
RBD is the RADOS Block Device and is part of the Ceph distributed storage system.
It comes in two flavours: Qemu-RBD and Kernel RBD, this storage backend only supports
Qemu-RBD, thus limiting the use of this storage driver to Qemu only.
To function this backend relies on librbd and librados being present on the local system.
The backend also supports Cephx authentication for safe authentication with the Ceph cluster.
For storing credentials it uses the build-in secret mechanism of libvirt.
Signed-off-by: Wido den Hollander <wido(a)widodh.nl>
---
configure.ac | 20 ++
include/libvirt/libvirt.h.in | 1 +
src/Makefile.am | 9 +
src/conf/storage_conf.c | 197 ++++++++++---
src/conf/storage_conf.h | 16 +
src/storage/storage_backend.c | 6 +
src/storage/storage_backend_rbd.c | 465 ++++++++++++++++++++++++++++++
src/storage/storage_backend_rbd.h | 30 ++
tests/storagepoolxml2xmlin/pool-rbd.xml | 11 +
tests/storagepoolxml2xmlout/pool-rbd.xml | 15 +
tools/virsh.c | 7 +
11 files changed, 734 insertions(+), 43 deletions(-)
create mode 100644 src/storage/storage_backend_rbd.c
create mode 100644 src/storage/storage_backend_rbd.h
create mode 100644 tests/storagepoolxml2xmlin/pool-rbd.xml
create mode 100644 tests/storagepoolxml2xmlout/pool-rbd.xml
diff --git a/configure.ac b/configure.ac
index 32cc8d0..b693e5b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1743,6 +1743,8 @@ AC_ARG_WITH([storage-mpath],
AC_HELP_STRING([--with-storage-mpath], [with mpath backend for the storage driver @<:@default=check@:>@]),[],[with_storage_mpath=check])
AC_ARG_WITH([storage-disk],
AC_HELP_STRING([--with-storage-disk], [with GPartd Disk backend for the storage driver @<:@default=check@:>@]),[],[with_storage_disk=check])
+AC_ARG_WITH([storage-rbd],
+ AC_HELP_STRING([--with-storage-rbd], [with RADOS Block Device backend for the storage driver @<:@default=check@:>@]),[],[with_storage_rbd=check])
if test "$with_libvirtd" = "no"; then
with_storage_dir=no
@@ -1752,6 +1754,7 @@ if test "$with_libvirtd" = "no"; then
with_storage_scsi=no
with_storage_mpath=no
with_storage_disk=no
+ with_storage_rbd=no
fi
if test "$with_storage_dir" = "yes" ; then
AC_DEFINE_UNQUOTED([WITH_STORAGE_DIR], 1, [whether directory backend for storage driver is enabled])
@@ -1910,6 +1913,22 @@ if test "$with_storage_mpath" = "check"; then
fi
AM_CONDITIONAL([WITH_STORAGE_MPATH], [test "$with_storage_mpath" = "yes"])
+if test "$with_storage_rbd" = "yes" || test "$with_storage_rbd" = "check"; then
+ AC_CHECK_HEADER([rbd/librbd.h], [LIBRBD_FOUND=yes; break;])
+
+ LIBRBD_LIBS="-lrbd -lrados -lcrypto"
+
+ if test "$LIBRBD_FOUND" = "yes"; then
+ with_storage_rbd=yes
+ LIBS="$LIBS $LIBRBD_LIBS"
+ else
+ with_storage_rbd=no
+ fi
+
+ AC_DEFINE_UNQUOTED([WITH_STORAGE_RBD], 1, [wether RBD backend for storage driver is enabled])
+fi
+AM_CONDITIONAL([WITH_STORAGE_RBD], [test "$with_storage_rbd" = "yes"])
+
LIBPARTED_CFLAGS=
LIBPARTED_LIBS=
if test "$with_storage_disk" = "yes" ||
@@ -2673,6 +2692,7 @@ AC_MSG_NOTICE([ iSCSI: $with_storage_iscsi])
AC_MSG_NOTICE([ SCSI: $with_storage_scsi])
AC_MSG_NOTICE([ mpath: $with_storage_mpath])
AC_MSG_NOTICE([ Disk: $with_storage_disk])
+AC_MSG_NOTICE([ RBD: $with_storage_rbd])
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Security Drivers])
AC_MSG_NOTICE([])
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 499dcd4..ee1d5ec 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2324,6 +2324,7 @@ typedef enum {
VIR_STORAGE_VOL_FILE = 0, /* Regular file based volumes */
VIR_STORAGE_VOL_BLOCK = 1, /* Block based volumes */
VIR_STORAGE_VOL_DIR = 2, /* Directory-passthrough based volume */
+ VIR_STORAGE_VOL_NETWORK = 3, /* Network volumes like RBD (RADOS Block Device) */
#ifdef VIR_ENUM_SENTINELS
VIR_STORAGE_VOL_LAST
diff --git a/src/Makefile.am b/src/Makefile.am
index a2aae9d..e4457c3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -498,6 +498,9 @@ STORAGE_DRIVER_MPATH_SOURCES = \
STORAGE_DRIVER_DISK_SOURCES = \
storage/storage_backend_disk.h storage/storage_backend_disk.c
+STORAGE_DRIVER_RBD_SOURCES = \
+ storage/storage_backend_rbd.h storage/storage_backend_rbd.c
+
STORAGE_HELPER_DISK_SOURCES = \
storage/parthelper.c
@@ -1040,6 +1043,11 @@ if WITH_STORAGE_DISK
libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_DISK_SOURCES)
endif
+if WITH_STORAGE_RBD
+libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_RBD_SOURCES)
+libvirt_la_LIBADD += $(LIBRBD_LIBS)
+endif
+
if WITH_NODE_DEVICES
# Needed to keep automake quiet about conditionals
if WITH_DRIVER_MODULES
@@ -1139,6 +1147,7 @@ EXTRA_DIST += \
$(STORAGE_DRIVER_SCSI_SOURCES) \
$(STORAGE_DRIVER_MPATH_SOURCES) \
$(STORAGE_DRIVER_DISK_SOURCES) \
+ $(STORAGE_DRIVER_RBD_SOURCES) \
$(NODE_DEVICE_DRIVER_SOURCES) \
$(NODE_DEVICE_DRIVER_HAL_SOURCES) \
$(NODE_DEVICE_DRIVER_UDEV_SOURCES) \
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index bdf6218..2a0b5eb 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -52,7 +52,7 @@ VIR_ENUM_IMPL(virStoragePool,
VIR_STORAGE_POOL_LAST,
"dir", "fs", "netfs",
"logical", "disk", "iscsi",
- "scsi", "mpath")
+ "scsi", "mpath", "rbd")
VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
VIR_STORAGE_POOL_FS_LAST,
@@ -110,6 +110,7 @@ enum {
VIR_STORAGE_POOL_SOURCE_ADAPTER = (1<<3),
VIR_STORAGE_POOL_SOURCE_NAME = (1<<4),
VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN = (1<<5),
+ VIR_STORAGE_POOL_SOURCE_NETWORK = (1<<6),
};
@@ -194,6 +195,15 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
.formatToString = virStoragePoolFormatDiskTypeToString,
}
},
+ { .poolType = VIR_STORAGE_POOL_RBD,
+ .poolOptions = {
+ .flags = (VIR_STORAGE_POOL_SOURCE_NETWORK |
+ VIR_STORAGE_POOL_SOURCE_NAME),
+ },
+ .volOptions = {
+ .formatToString = virStoragePoolFormatDiskTypeToString,
+ }
+ },
{ .poolType = VIR_STORAGE_POOL_MPATH,
.volOptions = {
.formatToString = virStoragePoolFormatDiskTypeToString,
@@ -277,6 +287,11 @@ virStoragePoolSourceClear(virStoragePoolSourcePtr source)
return;
VIR_FREE(source->host.name);
+ for (i = 0 ; i < source->nhost ; i++) {
+ VIR_FREE(source->hosts[i].name);
+ }
+ VIR_FREE(source->hosts);
+
for (i = 0 ; i < source->ndevice ; i++) {
VIR_FREE(source->devices[i].freeExtents);
VIR_FREE(source->devices[i].path);
@@ -293,6 +308,12 @@ virStoragePoolSourceClear(virStoragePoolSourcePtr source)
VIR_FREE(source->auth.chap.login);
VIR_FREE(source->auth.chap.passwd);
}
+
+ if (source->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
+ VIR_FREE(source->auth.cephx.username);
+ VIR_FREE(source->auth.cephx.secret.uuid);
+ VIR_FREE(source->auth.cephx.secret.usage);
+ }
}
void
@@ -395,6 +416,27 @@ virStoragePoolDefParseAuthChap(xmlXPathContextPtr ctxt,
}
static int
+virStoragePoolDefParseAuthCephx(xmlXPathContextPtr ctxt,
+ virStoragePoolAuthCephxPtr auth) {
+ auth->username = virXPathString("string(./auth/@username)", ctxt);
+ if (auth->username == NULL) {
+ virStorageReportError(VIR_ERR_XML_ERROR,
+ "%s", _("missing auth username attribute"));
+ return -1;
+ }
+
+ auth->secret.uuid = virXPathString("string(./auth/secret/@uuid)", ctxt);
+ auth->secret.usage = virXPathString("string(./auth/secret/@usage)", ctxt);
+ if (auth->secret.uuid == NULL && auth->secret.usage == NULL) {
+ virStorageReportError(VIR_ERR_XML_ERROR,
+ "%s", _("missing auth secret uuid or usage attribute"));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
virStoragePoolSourcePtr source,
int pool_type,
@@ -414,6 +456,12 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
}
source->name = virXPathString("string(./name)", ctxt);
+ if (pool_type == VIR_STORAGE_POOL_RBD && source->name == NULL) {
+ virStorageReportError(VIR_ERR_XML_ERROR,
+ _("%s"), "missing mandatory 'name' field for RBD pool name");
+ VIR_FREE(source->name);
+ goto cleanup;
+ }
if (options->formatFromString) {
char *format = virXPathString("string(./format/@type)", ctxt);
@@ -431,17 +479,39 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
VIR_FREE(format);
}
- source->host.name = virXPathString("string(./host/@name)", ctxt);
- port = virXPathString("string(./host/@port)", ctxt);
- if (port) {
- if (virStrToLong_i(port, NULL, 10, &source->host.port) < 0) {
- virStorageReportError(VIR_ERR_XML_ERROR,
- _("Invalid port number: %s"),
- port);
+ source->nhost = virXPathNodeSet("./host", ctxt, &nodeset);
+
+ if (source->nhost) {
+ if (VIR_ALLOC_N(source->hosts, source->nhost) < 0) {
+ virReportOOMError();
goto cleanup;
}
- }
+ for (i = 0 ; i < source->nhost ; i++) {
+ char *name = virXMLPropString(nodeset[i], "name");
+ if (name == NULL) {
+ virStorageReportError(VIR_ERR_XML_ERROR,
+ "%s", _("missing storage pool host name"));
+ goto cleanup;
+ }
+ source->hosts[i].name = name;
+ if(i == 0 && source->nhost == 1)
+ source->host.name = name;
+
+ port = virXMLPropString(nodeset[i], "port");
+ if (port) {
+ if (virStrToLong_i(port, NULL, 10, &source->hosts[i].port) < 0) {
+ virStorageReportError(VIR_ERR_XML_ERROR,
+ _("Invalid port number: %s"),
+ port);
+ goto cleanup;
+ } else {
+ if (i == 0 && source->nhost == 1)
+ virStrToLong_i(port, NULL, 10, &source->host.port);
+ }
+ }
+ }
+ }
source->initiator.iqn = virXPathString("string(./initiator/iqn/@name)", ctxt);
@@ -478,6 +548,8 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
} else {
if (STREQ(authType, "chap")) {
source->authType = VIR_STORAGE_POOL_AUTH_CHAP;
+ } else if (STREQ(authType, "ceph")) {
+ source->authType = VIR_STORAGE_POOL_AUTH_CEPHX;
} else {
virStorageReportError(VIR_ERR_XML_ERROR,
_("unknown auth type '%s'"),
@@ -491,6 +563,11 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
goto cleanup;
}
+ if (source->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
+ if (virStoragePoolDefParseAuthCephx(ctxt, &source->auth.cephx) < 0)
+ goto cleanup;
+ }
+
source->vendor = virXPathString("string(./vendor/@name)", ctxt);
source->product = virXPathString("string(./product/@name)", ctxt);
@@ -682,6 +759,15 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) {
}
}
+ if (options->flags & VIR_STORAGE_POOL_SOURCE_NETWORK) {
+ if (!ret->source.host.name && ret->source.nhost < 1) {
+ virStorageReportError(VIR_ERR_XML_ERROR,
+ "%s",
+ _("missing storage pool source network host name"));
+ goto cleanup;
+ }
+ }
+
if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR) {
if (!ret->source.dir) {
virStorageReportError(VIR_ERR_XML_ERROR,
@@ -717,20 +803,22 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) {
}
}
- if ((tmppath = virXPathString("string(./target/path)", ctxt)) == NULL) {
- virStorageReportError(VIR_ERR_XML_ERROR,
- "%s", _("missing storage pool target path"));
- goto cleanup;
- }
- ret->target.path = virFileSanitizePath(tmppath);
- VIR_FREE(tmppath);
- if (!ret->target.path)
- goto cleanup;
-
+ /* When we are working with a virtual disk we can skip the target path and permissions */
+ if (!(options->flags & VIR_STORAGE_POOL_SOURCE_NETWORK)) {
+ if ((tmppath = virXPathString("string(./target/path)", ctxt)) == NULL) {
+ virStorageReportError(VIR_ERR_XML_ERROR,
+ "%s", _("missing storage pool target path"));
+ goto cleanup;
+ }
+ ret->target.path = virFileSanitizePath(tmppath);
+ VIR_FREE(tmppath);
+ if (!ret->target.path)
+ goto cleanup;
- if (virStorageDefParsePerms(ctxt, &ret->target.perms,
- "./target/permissions", 0700) < 0)
- goto cleanup;
+ if (virStorageDefParsePerms(ctxt, &ret->target.perms,
+ "./target/permissions", 0700) < 0)
+ goto cleanup;
+ }
return ret;
@@ -800,12 +888,15 @@ virStoragePoolSourceFormat(virBufferPtr buf,
int i, j;
virBufferAddLit(buf," <source>\n");
- if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) &&
- src->host.name) {
- virBufferAsprintf(buf, " <host name='%s'", src->host.name);
- if (src->host.port)
- virBufferAsprintf(buf, " port='%d'", src->host.port);
- virBufferAddLit(buf, "/>\n");
+ if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST ||
+ options->flags & VIR_STORAGE_POOL_SOURCE_NETWORK) &&
+ src->nhost) {
+ for (i = 0; i < src->nhost; i++) {
+ virBufferAsprintf(buf, " <host name='%s'", src->hosts[i].name);
+ if (src->hosts[i].port)
+ virBufferAsprintf(buf, " port='%d'", src->hosts[i].port);
+ virBufferAddLit(buf, "/>\n");
+ }
}
if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) &&
@@ -860,6 +951,23 @@ virStoragePoolSourceFormat(virBufferPtr buf,
src->auth.chap.login,
src->auth.chap.passwd);
+ if (src->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
+ virBufferAsprintf(buf," <auth username='%s' type='ceph'>\n",
+ src->auth.cephx.username);
+
+ virBufferAsprintf(buf," %s", "<secret");
+ if (src->auth.cephx.secret.uuid != NULL) {
+ virBufferAsprintf(buf," uuid='%s'", src->auth.cephx.secret.uuid);
+ }
+
+ if (src->auth.cephx.secret.usage != NULL) {
+ virBufferAsprintf(buf," usage='%s'", src->auth.cephx.secret.usage);
+ }
+ virBufferAsprintf(buf,"%s", "/>\n");
+
+ virBufferAsprintf(buf," %s", "</auth>\n");
+ }
+
if (src->vendor != NULL) {
virBufferEscapeString(buf," <vendor name='%s'/>\n", src->vendor);
}
@@ -907,25 +1015,28 @@ virStoragePoolDefFormat(virStoragePoolDefPtr def) {
if (virStoragePoolSourceFormat(&buf, options, &def->source) < 0)
goto cleanup;
- virBufferAddLit(&buf," <target>\n");
+ /* RBD devices are no local block devs nor files, so it doesn't have a target */
+ if (def->type != VIR_STORAGE_POOL_RBD) {
+ virBufferAddLit(&buf," <target>\n");
- if (def->target.path)
- virBufferAsprintf(&buf," <path>%s</path>\n", def->target.path);
+ if (def->target.path)
+ virBufferAsprintf(&buf," <path>%s</path>\n", def->target.path);
- virBufferAddLit(&buf," <permissions>\n");
- virBufferAsprintf(&buf," <mode>0%o</mode>\n",
- def->target.perms.mode);
- virBufferAsprintf(&buf," <owner>%d</owner>\n",
- def->target.perms.uid);
- virBufferAsprintf(&buf," <group>%d</group>\n",
- def->target.perms.gid);
+ virBufferAddLit(&buf," <permissions>\n");
+ virBufferAsprintf(&buf," <mode>0%o</mode>\n",
+ def->target.perms.mode);
+ virBufferAsprintf(&buf," <owner>%d</owner>\n",
+ def->target.perms.uid);
+ virBufferAsprintf(&buf," <group>%d</group>\n",
+ def->target.perms.gid);
- if (def->target.perms.label)
- virBufferAsprintf(&buf," <label>%s</label>\n",
- def->target.perms.label);
+ if (def->target.perms.label)
+ virBufferAsprintf(&buf," <label>%s</label>\n",
+ def->target.perms.label);
- virBufferAddLit(&buf," </permissions>\n");
- virBufferAddLit(&buf," </target>\n");
+ virBufferAddLit(&buf," </permissions>\n");
+ virBufferAddLit(&buf," </target>\n");
+ }
virBufferAddLit(&buf,"</pool>\n");
if (virBufferError(&buf))
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h
index 1ef9295..6b91ca5 100644
--- a/src/conf/storage_conf.h
+++ b/src/conf/storage_conf.h
@@ -120,6 +120,7 @@ enum virStoragePoolType {
VIR_STORAGE_POOL_ISCSI, /* iSCSI targets */
VIR_STORAGE_POOL_SCSI, /* SCSI HBA */
VIR_STORAGE_POOL_MPATH, /* Multipath devices */
+ VIR_STORAGE_POOL_RBD, /* RADOS Block Device */
VIR_STORAGE_POOL_LAST,
};
@@ -137,6 +138,7 @@ enum virStoragePoolDeviceType {
enum virStoragePoolAuthType {
VIR_STORAGE_POOL_AUTH_NONE,
VIR_STORAGE_POOL_AUTH_CHAP,
+ VIR_STORAGE_POOL_AUTH_CEPHX,
};
typedef struct _virStoragePoolAuthChap virStoragePoolAuthChap;
@@ -146,6 +148,15 @@ struct _virStoragePoolAuthChap {
char *passwd;
};
+typedef struct _virStoragePoolAuthCephx virStoragePoolAuthCephx;
+typedef virStoragePoolAuthCephx *virStoragePoolAuthCephxPtr;
+struct _virStoragePoolAuthCephx {
+ char *username;
+ struct {
+ char *uuid;
+ char *usage;
+ } secret;
+};
/*
* For remote pools, info on how to reach the host
@@ -215,6 +226,10 @@ struct _virStoragePoolSource {
/* An optional host */
virStoragePoolSourceHost host;
+ /* Or multiple hosts */
+ int nhost;
+ virStoragePoolSourceHostPtr hosts;
+
/* And either one or more devices ... */
int ndevice;
virStoragePoolSourceDevicePtr devices;
@@ -234,6 +249,7 @@ struct _virStoragePoolSource {
int authType; /* virStoragePoolAuthType */
union {
virStoragePoolAuthChap chap;
+ virStoragePoolAuthCephx cephx;
} auth;
/* Vendor of the source */
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index caac2f8..e2e9b51 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -77,6 +77,9 @@
#if WITH_STORAGE_DIR
# include "storage_backend_fs.h"
#endif
+#if WITH_STORAGE_RBD
+# include "storage_backend_rbd.h"
+#endif
#define VIR_FROM_THIS VIR_FROM_STORAGE
@@ -103,6 +106,9 @@ static virStorageBackendPtr backends[] = {
#if WITH_STORAGE_DISK
&virStorageBackendDisk,
#endif
+#if WITH_STORAGE_RBD
+ &virStorageBackendRBD,
+#endif
NULL
};
diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c
new file mode 100644
index 0000000..056059a
--- /dev/null
+++ b/src/storage/storage_backend_rbd.c
@@ -0,0 +1,465 @@
+/*
+ * storage_backend_rbd.c: storage backend for RBD (RADOS Block Device) handling
+ *
+ * Copyright (C) 2012 Wido den Hollander
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Wido den Hollander <wido(a)widodh.nl>
+ */
+
+#include <config.h>
+
+#include "virterror_internal.h"
+#include "storage_backend_rbd.h"
+#include "storage_conf.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "base64.h"
+#include "rados/librados.h"
+#include "rbd/librbd.h"
+
+#define VIR_FROM_THIS VIR_FROM_STORAGE
+
+struct _virStorageBackendRBDState {
+ rados_t cluster;
+ rados_ioctx_t ioctx;
+ time_t starttime;
+};
+
+typedef struct _virStorageBackendRBDState virStorageBackendRBDState;
+typedef virStorageBackendRBDState virStorageBackendRBDStatePtr;
+
+static int virStorageBackendRBDOpenRADOSConn(virStorageBackendRBDStatePtr *ptr,
+ virConnectPtr conn,
+ virStoragePoolObjPtr pool)
+{
+ int ret = -1;
+ unsigned char *secret_value;
+ size_t secret_value_size;
+ char *rados_key;
+ virBuffer mon_host = VIR_BUFFER_INITIALIZER;
+ virSecretPtr secret = NULL;
+
+ VIR_DEBUG("Found Cephx username: %s",
+ pool->def->source.auth.cephx.username);
+
+ if (pool->def->source.auth.cephx.username != NULL) {
+ VIR_DEBUG("Using cephx authorization");
+ if (rados_create(&ptr->cluster,
+ pool->def->source.auth.cephx.username) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to initialize RADOS"));
+ goto cleanup;
+ }
+
+ if (pool->def->source.auth.cephx.secret.uuid != NULL) {
+ VIR_DEBUG("Looking up secret by UUID: %s",
+ pool->def->source.auth.cephx.secret.uuid);
+ secret = virSecretLookupByUUIDString(conn,
+ pool->def->source.auth.cephx.secret.uuid);
+ }
+
+ if (pool->def->source.auth.cephx.secret.usage != NULL) {
+ VIR_DEBUG("Looking up secret by usage: %s",
+ pool->def->source.auth.cephx.secret.usage);
+ secret = virSecretLookupByUsage(conn, VIR_SECRET_USAGE_TYPE_CEPH,
+ pool->def->source.auth.cephx.secret.usage);
+ }
+
+ if (secret == NULL) {
+ virStorageReportError(VIR_ERR_NO_SECRET,
+ _("failed to find the secret"));
+ goto cleanup;
+ }
+
+ secret_value = virSecretGetValue(secret, &secret_value_size, 0);
+ base64_encode_alloc((char *)secret_value,
+ secret_value_size, &rados_key);
+ memset(secret_value, 0, secret_value_size);
+
+ if (rados_key == NULL) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to decode the RADOS key"));
+ goto cleanup;
+ }
+
+ VIR_DEBUG("Found cephx key: %s", rados_key);
+ if (rados_conf_set(ptr->cluster, "key", rados_key) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to set RADOS option: %s"),
+ "rados_key");
+ goto cleanup;
+ }
+
+ memset(rados_key, 0, strlen(rados_key));
+
+ if (rados_conf_set(ptr->cluster, "auth_supported", "cephx") < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to set RADOS option: %s"),
+ "auth_supported");
+ goto cleanup;
+ }
+ } else {
+ VIR_DEBUG("Not using cephx authorization");
+ if (rados_conf_set(ptr->cluster, "auth_supported", "none") < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to set RADOS option: %s"),
+ "auth_supported");
+ goto cleanup;
+ }
+ if (rados_create(&ptr->cluster, NULL) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to create the RADOS cluster"));
+ goto cleanup;
+ }
+ }
+
+ VIR_DEBUG("Found %d RADOS cluster monitors in the pool configuration",
+ pool->def->source.nhost);
+
+ int i;
+ for (i = 0; i < pool->def->source.nhost; i++) {
+ if (pool->def->source.hosts[i].name != NULL &&
+ !pool->def->source.hosts[i].port) {
+ virBufferAsprintf(&mon_host, "%s:6789,",
+ pool->def->source.hosts[i].name);
+ } else if (pool->def->source.hosts[i].name != NULL &&
+ pool->def->source.hosts[i].port) {
+ virBufferAsprintf(&mon_host, "%s:%d,",
+ pool->def->source.hosts[i].name,
+ pool->def->source.hosts[i].port);
+ } else {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("received malformed monitor, check the XML definition"));
+ }
+ }
+
+ char *mon_buff = virBufferContentAndReset(&mon_host);
+ VIR_DEBUG("RADOS mon_host has been set to: %s", mon_buff);
+ if (rados_conf_set(ptr->cluster, "mon_host", mon_buff) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to set RADOS option: %s"),
+ "mon_host");
+ goto cleanup;
+ }
+
+ ptr->starttime = time(0);
+ if (rados_connect(ptr->cluster) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to connect to the RADOS monitor on: %s"),
+ virBufferContentAndReset(&mon_host));
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(secret_value);
+ VIR_FREE(rados_key);
+ virSecretFree(secret);
+ virBufferFreeAndReset(&mon_host);
+ return ret;
+}
+
+static int virStorageBackendRBDCloseRADOSConn(virStorageBackendRBDStatePtr ptr)
+{
+ int ret = 0;
+
+ if (ptr.ioctx != NULL) {
+ VIR_DEBUG("Closing RADOS IoCTX");
+ rados_ioctx_destroy(ptr.ioctx);
+ ret = -1;
+ }
+
+ if (ptr.cluster != NULL) {
+ VIR_DEBUG("Closing RADOS connection");
+ rados_shutdown(ptr.cluster);
+ ret = -2;
+ }
+
+ time_t runtime = time(0) - ptr.starttime;
+ VIR_DEBUG("RADOS connection existed for %ld seconds", runtime);
+
+ return ret;
+}
+
+static int volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol,
+ virStoragePoolObjPtr pool,
+ virStorageBackendRBDStatePtr ptr)
+{
+ int ret = -1;
+ rbd_image_t image;
+ if (rbd_open(ptr.ioctx, vol->name, &image, NULL) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to open the RBD image '%s'"),
+ vol->name);
+ goto cleanup;
+ }
+
+ rbd_image_info_t info;
+ if (rbd_stat(image, &info, sizeof(info)) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to stat the RBD image"));
+ goto cleanup;
+ }
+
+ VIR_DEBUG("Refreshed RBD image %s/%s (size: %llu obj_size: %llu num_objs: %llu)",
+ pool->def->source.name, vol->name, (unsigned long long)info.size,
+ (unsigned long long)info.obj_size,
+ (unsigned long long)info.num_objs);
+
+ vol->capacity = info.size;
+ vol->allocation = info.obj_size * info.num_objs;
+ vol->type = VIR_STORAGE_VOL_NETWORK;
+
+ VIR_FREE(vol->target.path);
+ if (virAsprintf(&vol->target.path, "rbd:%s/%s",
+ pool->def->source.name,
+ vol->name) == -1) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ VIR_FREE(vol->key);
+ if (virAsprintf(&vol->key, "%s/%s",
+ pool->def->source.name,
+ vol->name) == -1) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ rbd_close(image);
+ return ret;
+}
+
+static int virStorageBackendRBDRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virStoragePoolObjPtr pool)
+{
+ size_t max_size = 1024;
+ int ret = -1;
+ virStorageBackendRBDStatePtr ptr;
+ ptr.cluster = NULL;
+ ptr.ioctx = NULL;
+
+ if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
+ goto cleanup;
+ }
+
+ if (rados_ioctx_create(ptr.cluster,
+ pool->def->source.name, &ptr.ioctx) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to create the RBD IoCTX. Does the pool '%s' exist?"),
+ pool->def->source.name);
+ goto cleanup;
+ }
+
+ struct rados_cluster_stat_t stat;
+ if (rados_cluster_stat(ptr.cluster, &stat) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to stat the RADOS cluster"));
+ goto cleanup;
+ }
+
+ struct rados_pool_stat_t poolstat;
+ if (rados_ioctx_pool_stat(ptr.ioctx, &poolstat) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to stat the RADOS pool '%s'"),
+ pool->def->source.name);
+ goto cleanup;
+ }
+
+ pool->def->capacity = stat.kb * 1024;
+ pool->def->available = stat.kb_avail * 1024;
+ pool->def->allocation = poolstat.num_bytes;
+
+ int num_images, i;
+ char *names, *name = NULL;
+
+ if (VIR_ALLOC_N(names, 1024) < 0)
+ goto cleanup;
+
+ int len = rbd_list(ptr.ioctx, names, &max_size);
+
+ for (i = 0, num_images = 0, name = names; name < names + len; i++) {
+
+ if (VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count + 1) < 0) {
+ virStoragePoolObjClearVols(pool);
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ virStorageVolDefPtr vol;
+ if (VIR_ALLOC(vol) < 0)
+ goto cleanup;
+
+ vol->name = strdup(name);
+ if (vol->name == NULL)
+ goto cleanup;
+ name += strlen(name) + 1;
+
+ if (volStorageBackendRBDRefreshVolInfo(vol, pool, ptr) < 0)
+ goto cleanup;
+
+ pool->volumes.objs[pool->volumes.count++] = vol;
+ }
+
+ VIR_DEBUG("Refreshed RBD pool %s (kb: %llu kb_avail: %llu num_bytes: %llu num_images: %d)",
+ pool->def->source.name, (unsigned long long)stat.kb,
+ (unsigned long long)stat.kb_avail,
+ (unsigned long long)poolstat.num_bytes, pool->volumes.count);
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(names);
+ virStorageBackendRBDCloseRADOSConn(ptr);
+ return ret;
+}
+
+static int virStorageBackendRBDDeleteVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol,
+ unsigned int flags)
+{
+ int ret = -1;
+ virStorageBackendRBDStatePtr ptr;
+ ptr.cluster = NULL;
+ ptr.ioctx = NULL;
+
+ VIR_DEBUG("Removing RBD image %s/%s", pool->def->source.name, vol->name);
+
+ if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
+ goto cleanup;
+ }
+
+ if (rados_ioctx_create(ptr.cluster,
+ pool->def->source.name, &ptr.ioctx) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to create the RBD IoCTX. Does the pool '%s' exist?"),
+ pool->def->source.name);
+ goto cleanup;
+ }
+
+ if (rbd_remove(ptr.ioctx, vol->name) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to remove volume '%s/%s'"),
+ pool->def->source.name,
+ vol->name);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virStorageBackendRBDCloseRADOSConn(ptr);
+ return ret;
+}
+
+static int virStorageBackendRBDCreateVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol)
+{
+ virStorageBackendRBDStatePtr ptr;
+ ptr.cluster = NULL;
+ ptr.ioctx = NULL;
+ int order = 0;
+ int ret = -1;
+
+ VIR_DEBUG("Creating RBD image %s/%s with size %llu",
+ pool->def->source.name,
+ vol->name, vol->capacity);
+
+ if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
+ goto cleanup;
+ }
+
+ if (rados_ioctx_create(ptr.cluster,
+ pool->def->source.name,&ptr.ioctx) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to create the RBD IoCTX. Does the pool '%s' exist?"),
+ pool->def->source.name);
+ goto cleanup;
+ }
+
+ if (vol->target.encryption != NULL) {
+ virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("storage pool does not support encrypted volumes"));
+ goto cleanup;
+ }
+
+ if (rbd_create(ptr.ioctx, vol->name, vol->capacity, &order) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to create volume '%s/%s'"),
+ pool->def->source.name,
+ vol->name);
+ goto cleanup;
+ }
+
+ if (volStorageBackendRBDRefreshVolInfo(vol, pool, ptr) < 0) {
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virStorageBackendRBDCloseRADOSConn(ptr);
+ return ret;
+}
+
+static int virStorageBackendRBDRefreshVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
+ virStorageVolDefPtr vol)
+{
+ virStorageBackendRBDStatePtr ptr;
+ ptr.cluster = NULL;
+ ptr.ioctx = NULL;
+ int ret = -1;
+
+ if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
+ goto cleanup;
+ }
+
+ if (rados_ioctx_create(ptr.cluster,
+ pool->def->source.name, &ptr.ioctx) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to create the RBD IoCTX. Does the pool '%s' exist?"),
+ pool->def->source.name);
+ goto cleanup;
+ }
+
+ if (volStorageBackendRBDRefreshVolInfo(vol, pool, ptr) < 0) {
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virStorageBackendRBDCloseRADOSConn(ptr);
+ return ret;
+}
+
+virStorageBackend virStorageBackendRBD = {
+ .type = VIR_STORAGE_POOL_RBD,
+
+ .refreshPool = virStorageBackendRBDRefreshPool,
+ .createVol = virStorageBackendRBDCreateVol,
+ .refreshVol = virStorageBackendRBDRefreshVol,
+ .deleteVol = virStorageBackendRBDDeleteVol,
+};
diff --git a/src/storage/storage_backend_rbd.h b/src/storage/storage_backend_rbd.h
new file mode 100644
index 0000000..2ae2513
--- /dev/null
+++ b/src/storage/storage_backend_rbd.h
@@ -0,0 +1,30 @@
+/*
+ * storage_backend_rbd.h: storage backend for RBD (RADOS Block Device) handling
+ *
+ * Copyright (C) 2012 Wido den Hollander
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Wido den Hollander <wido(a)widodh.nl>
+ */
+
+#ifndef __VIR_STORAGE_BACKEND_RBD_H__
+# define __VIR_STORAGE_BACKEND_RBD_H__
+
+# include "storage_backend.h"
+
+extern virStorageBackend virStorageBackendRBD;
+
+#endif /* __VIR_STORAGE_BACKEND_RBD_H__ */
diff --git a/tests/storagepoolxml2xmlin/pool-rbd.xml b/tests/storagepoolxml2xmlin/pool-rbd.xml
new file mode 100644
index 0000000..c9d4790
--- /dev/null
+++ b/tests/storagepoolxml2xmlin/pool-rbd.xml
@@ -0,0 +1,11 @@
+<pool type='rbd'>
+ <name>ceph</name>
+ <source>
+ <name>rbd</name>
+ <host name='localhost' port='6789'/>
+ <host name='localhost' port='6790'/>
+ <auth username='admin' type='ceph'>
+ <secret uuid='2ec115d7-3a88-3ceb-bc12-0ac909a6fd87' usage='admin'/>
+ </auth>
+ </source>
+</pool>
diff --git a/tests/storagepoolxml2xmlout/pool-rbd.xml b/tests/storagepoolxml2xmlout/pool-rbd.xml
new file mode 100644
index 0000000..fa7fb34
--- /dev/null
+++ b/tests/storagepoolxml2xmlout/pool-rbd.xml
@@ -0,0 +1,15 @@
+<pool type='rbd'>
+ <name>ceph</name>
+ <uuid>47c1faee-0207-e741-f5ae-d9b019b98fe2</uuid>
+ <capacity unit='bytes'>0</capacity>
+ <allocation unit='bytes'>0</allocation>
+ <available unit='bytes'>0</available>
+ <source>
+ <host name='localhost' port='6789'/>
+ <host name='localhost' port='6790'/>
+ <name>rbd</name>
+ <auth username='admin' type='ceph'>
+ <secret uuid='2ec115d7-3a88-3ceb-bc12-0ac909a6fd87' usage='admin'/>
+ </auth>
+ </source>
+</pool>
diff --git a/tools/virsh.c b/tools/virsh.c
index 8ee25c3..632c75e 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -11894,6 +11894,10 @@ cmdVolInfo(vshControl *ctl, const vshCmd *cmd)
vshPrint(ctl, "%-15s %s\n", _("Type:"), _("dir"));
break;
+ case VIR_STORAGE_VOL_NETWORK:
+ vshPrint(ctl, "%-15s %s\n", _("Type:"), _("network"));
+ break;
+
default:
vshPrint(ctl, "%-15s %s\n", _("Type:"), _("unknown"));
}
@@ -19852,6 +19856,9 @@ vshShowVersion(vshControl *ctl ATTRIBUTE_UNUSED)
#ifdef WITH_STORAGE_LVM
vshPrint(ctl, " LVM");
#endif
+#ifdef WITH_STORAGE_RBD
+ vshPrint(ctl, " RBD");
+#endif
vshPrint(ctl, "\n");
vshPrint(ctl, "%s", _(" Miscellaneous:"));
--
1.7.0.4
12 years, 8 months
[libvirt] RFE: virConnectListAllDomains()
by Eric Blake
Use of virConnectListDomains() and virConnectListDefinedDomains() is:
1. inherently racy. A domain can change between active and inactive
between two back-to-back calls, and thus be entirely skipped or
enumerated twice when concatenating lists.
2. painful to use. ListDomains gives ids, ListDefinedDomains gives
names, and the user must then call virDomainLookupByID() and
virDomainLookupByName() to convert into UUIDs.
3. requires pre-allocation. The user must call virConnectNumOfDomains()
then over-allocate before calling virConnectListDomains(), in order to
guarantee that the list size didn't change between the two calls.
This is a proposal for a new API that addresses all three points - by
returning virDomainPtr rather than id or strings, the UUID of each
domain can be grabbed in one shot. By consolidating things into a
single API call, there is no race in trying to piece together the
complete list. By having libvirt allocate the resulting array, rather
than making the caller pre-allocate, the user doesn't have to worry
about a race between getting a count and using that count. It also
provides the convenience of returning smaller lists based on various
filtering groups.
Thoughts before I expand this API and add the actual implementation?
diff --git i/include/libvirt/libvirt.h.in w/include/libvirt/libvirt.h.in
index a817db8..ea63d9f 100644
--- i/include/libvirt/libvirt.h.in
+++ w/include/libvirt/libvirt.h.in
@@ -1192,6 +1192,38 @@ int virConnectListDomains
(virConnectPtr conn,
*/
int virConnectNumOfDomains (virConnectPtr conn);
+/**
+ * virConnectListAllDomainsFlags:
+ *
+ * Flags used to tune which domains are listed by
virConnectListAllDomains().
+ * Note that these flags come in groups; if all bits from a group are 0,
+ * then that group is not used to filter results.
+ */
+typedef enum {
+ VIR_CONNECT_LIST_DOMAINS_ACTIVE = 1 << 0,
+ VIR_CONNECT_LIST_DOMAINS_INACTIVE = 1 << 1,
+
+ VIR_CONNECT_LIST_DOMAINS_PERSISTENT = 1 << 2,
+ VIR_CONNECT_LIST_DOMAINS_TRANSIENT = 1 << 3,
+
+ VIR_CONNECT_LIST_DOMAINS_RUNNING = 1 << 4,
+ VIR_CONNECT_LIST_DOMAINS_PAUSED = 1 << 5,
+ VIR_CONNECT_LIST_DOMAINS_SHUTOFF = 1 << 6,
+ VIR_CONNECT_LIST_DOMAINS_OTHER = 1 << 7,
+
+ VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE = 1 << 8,
+ VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE = 1 << 9,
+
+ VIR_CONNECT_LIST_DOMAINS_AUTOSTART = 1 << 10,
+ VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART = 1 << 11,
+
+ VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT = 1 << 12,
+ VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT = 1 << 13,
+} virConnectListAllDomainsFlags;
+
+int virConnectListAllDomains(virConnectPtr conn,
+ virDomainPtr *doms,
+ unsigned int flags);
/*
* Get connection from domain.
diff --git i/src/libvirt.c w/src/libvirt.c
index 22fc863..9d7d96f 100644
--- i/src/libvirt.c
+++ w/src/libvirt.c
@@ -1859,7 +1859,14 @@ error:
*
* Collect the list of active domains, and store their IDs in array @ids
*
- * Returns the number of domains found or -1 in case of error
+ * For inactive domains, see virConnectListDefinedDomains(). For more
+ * control over the results, see virConnectListAllDomains().
+ *
+ * Returns the number of domains found or -1 in case of error. Note that
+ * this command is inherently racy; a domain can be started between a
+ * call to virConnectNumOfDomains() and this call; you are only guaranteed
+ * that all currently active domains were listed if the return is less
+ * than @maxids.
*/
int
virConnectListDomains(virConnectPtr conn, int *ids, int maxids)
@@ -1927,6 +1934,88 @@ error:
}
/**
+ * virConnectListAllDomains:
+ * @conn: pointer to the hypervisor connection
+ * @doms: pointer to the location to store allocated output array
+ * @flags: bitwise-OR of virConnectListAllDomainsFlags
+ *
+ * Collect a possibly-filtered list of all domains, and return an allocated
+ * array of information for each. This API solves the race inherent in
+ * virConnectListDomains() and virConnectListDefinedDomains().
+ *
+ * Normally, all domains are returned; however, @flags can be used to
+ * filter the results for a smaller list of targetted domains. The valid
+ * flags are divided into groups, where each group contains bits that
+ * describe mutually exclusive attributes of a domain, and where all bits
+ * within a group describe all possible domains. Some hypervisors might
+ * reject explicit bits from a group where the hypervisor cannot make a
+ * distinction (for example, not all hypervisors can tell whether domains
+ * have snapshots). For a group supported by a given hypervisor, the
+ * behavior when no bits of a group are set is identical to the behavior
+ * when all bits in that group are set. When setting bits from more than
+ * one group, it is possible to select an impossible combination (such
+ * as an inactive transient domain), in that case a hypervisor may return
+ * either 0 or an error.
+ *
+ * The first group of @flags is VIR_CONNECT_LIST_DOMAINS_ACTIVE (online
+ * domains) and VIR_CONNECT_LIST_DOMAINS_INACTIVE (offline domains).
+ *
+ * The next group of @flags is VIR_CONNECT_LIST_DOMAINS_PERSISTENT (defined
+ * domains) and VIR_CONNECT_LIST_DOMAINS_TRANSIENT (running but not
defined).
+ *
+ * The next group of @flags covers various domain states:
+ * VIR_CONNECT_LIST_DOMAINS_RUNNING, VIR_CONNECT_LIST_DOMAINS_PAUSED,
+ * VIR_CONNECT_LIST_DOMAINS_SHUTOFF, and a catch-all for all other states
+ * (such as crashed, this catch-all covers the possibility of adding new
+ * states).
+ *
+ * The remaining groups cover boolean attributes commonly asked about
+ * domains; they include VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE and
+ * VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE, for filtering based on whether
+ * a managed save image exists; VIR_CONNECT_LIST_DOMAINS_AUTOSTART and
+ * VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART, for filtering based on autostart;
+ * VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT and
+ * VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT, for filtering based on whether
+ * a domain has snapshots.
+ *
+ * Returns the number of domains found or -1 in case of error. On success,
+ * the array stored into @doms is guaranteed to have an extra allocated
+ * element set to NULL, to make iteration easier. The caller is
+ * responsible for calling virDomainFree() on each array element, then
+ * calling free() on @doms.
+ */
+int
+virConnectListDomains(virConnectPtr conn, int *ids, int maxids)
+{
+ VIR_DEBUG("conn=%p, ids=%p, maxids=%d", conn, ids, maxids);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+
+ if ((ids == NULL) || (maxids < 0)) {
+ virLibConnError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ if (conn->driver->listDomains) {
+ int ret = conn->driver->listDomains (conn, ids, maxids);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+ virDispatchError(conn);
+ return -1;
+}
+
+/**
* virDomainGetConnect:
* @dom: pointer to a domain
*
@@ -8092,7 +8181,14 @@ error:
* list the defined but inactive domains, stores the pointers to the names
* in @names
*
- * Returns the number of names provided in the array or -1 in case of error
+ * For active domains, see virConnectListDomains(). For more control over
+ * the results, see virConnectListAllDomains().
+ *
+ * Returns the number of names provided in the array or -1 in case of
error.
+ * Note that this command is inherently racy; a domain can be defined
between
+ * a call to virConnectNumOfDefinedDomains() and this call; you are only
+ * guaranteed that all currently defined domains were listed if the return
+ * is less than @maxids. The client must call free() on each returned
name.
*/
int
virConnectListDefinedDomains(virConnectPtr conn, char **const names,
--
Eric Blake eblake(a)redhat.com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
12 years, 8 months
[libvirt] Problem with pty
by Daniele Milani
Dear all
I have the following problem:
-I'm running libvirt 0.9.11 on ubuntu 12.04;
-when I try to create a VM with the following configuration:
...
<serial type='pty'>
<source path='/dev/pts/2'/>
<target port='0'/>
<alias name='serial0'/>
</serial>
<console type='pty' tty='/dev/pts/2'>
<source path='/dev/pts/2'/>
<target type='serial' port='0'/>
<alias name='serial0'/>
</console>
...
I obtain this output:
errore: Impossibile creare il dominio da domain_alpha_1.xml
(error, impossible to create a domain from domain_alpha_1.xml)
errore: errore interno Process exited while reading console log output:
chardev: opening backend "pty" failed: Permission denied
Does anyone know what's going wrong and ho to fix it?
Thanks,
Daniele Milani
12 years, 8 months
[libvirt] [PATCH] Fix build when configuring with polkit0
by Jim Fehlig
Commit 2223ea98 removed the only use of 'server' param in
remoteDispatchAuthPolkit(). Mark the parameter with ATTRIBUTE_UNUSED
to fix the build when configuring with polkit0.
---
Pushing under the build breaker rule.
daemon/remote.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index 16a8a05..a02c09b 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -2653,7 +2653,7 @@ authdeny:
}
#elif HAVE_POLKIT0
static int
-remoteDispatchAuthPolkit(virNetServerPtr server,
+remoteDispatchAuthPolkit(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
virNetMessageErrorPtr rerr,
--
1.7.9.2
12 years, 8 months
[libvirt] [PATCH] Fix potential events deadlock when unref'ing virConnectPtr
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
When the last reference to a virConnectPtr is released by
libvirtd, it was possible for a deadlock to occur in the
virDomainEventState functions. The virDomainEventStatePtr
holds a reference on virConnectPtr for each registered
callback. When removing a callback, the virUnrefConnect
function is run. If this causes the last reference on the
virConnectPtr to be released, then virReleaseConnect can
be run, which in turns calls qemudClose. This function has
a call to virDomainEventStateDeregisterConn which is intended
to remove all callbacks associated with the virConnectPtr
instance.
Since each callback associated with a virConnectPtr holds a
reference on virConnectPtr, it is impossible for the qemudClose
method to be invoked while any callbacks are still registered.
Thus the call to virDomainEventStateDeregisterConn must in fact
be a no-op. Thus it is possible to just remove all trace of
virDomainEventStateDeregisterConn and avoid the deadlock.
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Delete virDomainEventStateDeregisterConn
* src/libxl/libxl_driver.c, src/lxc/lxc_driver.c,
src/qemu/qemu_driver.c, src/uml/uml_driver.c: Remove
calls to virDomainEventStateDeregisterConn
---
src/conf/domain_event.c | 61 ----------------------------------------------
src/conf/domain_event.h | 4 ---
src/libvirt_private.syms | 1 -
src/libxl/libxl_driver.c | 4 ---
src/lxc/lxc_driver.c | 2 --
src/qemu/qemu_driver.c | 2 --
src/uml/uml_driver.c | 2 --
7 files changed, 76 deletions(-)
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index 923c58d..4ecc413 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -248,45 +248,6 @@ virDomainEventCallbackListRemoveID(virConnectPtr conn,
}
-/**
- * virDomainEventCallbackListRemoveConn:
- * @conn: pointer to the connection
- * @cbList: the list
- *
- * Internal function to remove all of a given connection's callback
- * from a virDomainEventCallbackListPtr
- */
-static int
-virDomainEventCallbackListRemoveConn(virConnectPtr conn,
- virDomainEventCallbackListPtr cbList)
-{
- int old_count = cbList->count;
- int i;
- for (i = 0 ; i < cbList->count ; i++) {
- if (cbList->callbacks[i]->conn == conn) {
- virFreeCallback freecb = cbList->callbacks[i]->freecb;
- if (freecb)
- (*freecb)(cbList->callbacks[i]->opaque);
- virUnrefConnect(cbList->callbacks[i]->conn);
- VIR_FREE(cbList->callbacks[i]);
-
- if (i < (cbList->count - 1))
- memmove(cbList->callbacks + i,
- cbList->callbacks + i + 1,
- sizeof(*(cbList->callbacks)) *
- (cbList->count - (i + 1)));
- cbList->count--;
- i--;
- }
- }
- if (cbList->count < old_count &&
- VIR_REALLOC_N(cbList->callbacks, cbList->count) < 0) {
- ; /* Failure to reduce memory allocation isn't fatal */
- }
- return 0;
-}
-
-
static int
virDomainEventCallbackListMarkDelete(virConnectPtr conn,
virDomainEventCallbackListPtr cbList,
@@ -1608,28 +1569,6 @@ virDomainEventStateDeregisterID(virConnectPtr conn,
/**
- * virDomainEventStateDeregisterConn:
- * @conn: connection to associate with callbacks
- * @state: domain event state
- *
- * Remove all callbacks from @state associated with the
- * connection @conn
- *
- * Returns 0 on success, -1 on error
- */
-int
-virDomainEventStateDeregisterConn(virConnectPtr conn,
- virDomainEventStatePtr state)
-{
- int ret;
- virDomainEventStateLock(state);
- ret = virDomainEventCallbackListRemoveConn(conn, state->callbacks);
- virDomainEventStateUnlock(state);
- return ret;
-}
-
-
-/**
* virDomainEventStateEventID:
* @conn: connection associated with the callback
* @state: domain event state
diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
index f7776c7..d381aec 100644
--- a/src/conf/domain_event.h
+++ b/src/conf/domain_event.h
@@ -161,10 +161,6 @@ virDomainEventStateDeregisterID(virConnectPtr conn,
int callbackID)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
int
-virDomainEventStateDeregisterConn(virConnectPtr conn,
- virDomainEventStatePtr state)
- ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
-int
virDomainEventStateEventID(virConnectPtr conn,
virDomainEventStatePtr state,
int callbackID)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index f5c2184..6c907c4 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -522,7 +522,6 @@ virDomainEventRebootNewFromDom;
virDomainEventRebootNewFromObj;
virDomainEventStateDeregister;
virDomainEventStateDeregisterID;
-virDomainEventStateDeregisterConn;
virDomainEventStateEventID;
virDomainEventStateRegister;
virDomainEventStateRegisterID;
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index 45bf1f8..fc90d16 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -1081,10 +1081,6 @@ libxlClose(virConnectPtr conn ATTRIBUTE_UNUSED)
{
libxlDriverPrivatePtr driver = conn->privateData;
- libxlDriverLock(driver);
- virDomainEventStateDeregisterConn(conn,
- driver->domainEventState);
- libxlDriverUnlock(driver);
conn->privateData = NULL;
return 0;
}
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 4cccd53..9aea556 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -178,8 +178,6 @@ static int lxcClose(virConnectPtr conn)
lxc_driver_t *driver = conn->privateData;
lxcDriverLock(driver);
- virDomainEventStateDeregisterConn(conn,
- driver->domainEventState);
lxcProcessAutoDestroyRun(driver, conn);
lxcDriverUnlock(driver);
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index efbc421..39b27b1 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -962,8 +962,6 @@ static int qemudClose(virConnectPtr conn) {
/* Get rid of callbacks registered for this conn */
qemuDriverLock(driver);
- virDomainEventStateDeregisterConn(conn,
- driver->domainEventState);
qemuDriverCloseCallbackRunAll(driver, conn);
qemuDriverUnlock(driver);
diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
index 8a39d73..65f9cbc 100644
--- a/src/uml/uml_driver.c
+++ b/src/uml/uml_driver.c
@@ -1188,8 +1188,6 @@ static int umlClose(virConnectPtr conn) {
struct uml_driver *driver = conn->privateData;
umlDriverLock(driver);
- virDomainEventStateDeregisterConn(conn,
- driver->domainEventState);
umlProcessAutoDestroyRun(driver, conn);
umlDriverUnlock(driver);
--
1.7.10.1
12 years, 8 months