This patch adds API to modify domain metadata for running and stopped
domains. The api supports changing description, title as well as the
newly added <metadata> element. The API has support for storing data in
the metadata element using xml namespaces.
* include/libvirt/libvirt.h.in
* src/libvirt_public.syms
- add function headers
- add enum to select metadata to operate on
- export functions
* src/libvirt.c
- add public api implementation
* src/driver.h
- add driver support
* src/remote/remote_driver.c
* src/remote/remote_protocol.x
- wire up the remote protocol
* include/libvirt/virterror.h
* src/util/virterror.c
- add a new error message note that metadata for domain are
missing
---
include/libvirt/libvirt.h.in | 24 ++++++
include/libvirt/virterror.h | 1 +
src/driver.h | 16 ++++
src/libvirt.c | 178 ++++++++++++++++++++++++++++++++++++++++++
src/libvirt_public.syms | 2 +
src/remote/remote_driver.c | 2 +
src/remote/remote_protocol.x | 24 ++++++-
src/remote_protocol-structs | 19 +++++
src/util/virterror.c | 6 ++
9 files changed, 271 insertions(+), 1 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index cf53cf2..07d03fa 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1496,6 +1496,30 @@ int virDomainGetMaxVcpus (virDomainPtr
domain);
int virDomainGetSecurityLabel (virDomainPtr domain,
virSecurityLabelPtr seclabel);
+typedef enum {
+ VIR_DOMAIN_METADATA_DESCRIPTION = 0, /* Operate on <description> */
+ VIR_DOMAIN_METADATA_TITLE = 1, /* Operate on <title> */
+ VIR_DOMAIN_METADATA_ELEMENT = 2, /* Operate on <metadata> */
+
+#ifdef VIR_ENUM_SENTINELS
+ VIR_DOMAIN_METADATA_LAST
+#endif
+} virDomainMetadataType;
+
+int
+virDomainSetMetadata(virDomainPtr domain,
+ int type,
+ const char *metadata,
+ const char *key,
+ const char *uri,
+ unsigned int flags);
+
+char *
+virDomainGetMetadata(virDomainPtr domain,
+ int type,
+ const char *uri,
+ unsigned int flags);
+
/*
* XML domain description
*/
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 9844cbe..9dbadfe 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -244,6 +244,7 @@ typedef enum {
VIR_ERR_OPERATION_ABORTED = 78, /* operation on a domain was
canceled/aborted by user */
VIR_ERR_AUTH_CANCELLED = 79, /* authentication cancelled */
+ VIR_ERR_NO_DOMAIN_METADATA = 80, /* The metadata is not present */
} virErrorNumber;
/**
diff --git a/src/driver.h b/src/driver.h
index 9ff5edf..d6ee60f 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -816,6 +816,20 @@ typedef int
unsigned int maxerrors,
unsigned int flags);
+typedef int
+ (*virDrvDomainSetMetadata)(virDomainPtr dom,
+ int type,
+ const char *metadata,
+ const char *key,
+ const char *uri,
+ unsigned int flags);
+
+typedef char *
+ (*virDrvDomainGetMetadata)(virDomainPtr dom,
+ int type,
+ const char *uri,
+ unsigned int flags);
+
/**
* _virDriver:
*
@@ -988,6 +1002,8 @@ struct _virDriver {
virDrvDomainGetBlockIoTune domainGetBlockIoTune;
virDrvDomainGetCPUStats domainGetCPUStats;
virDrvDomainGetDiskErrors domainGetDiskErrors;
+ virDrvDomainSetMetadata domainSetMetadata;
+ virDrvDomainGetMetadata domainGetMetadata;
};
typedef int
diff --git a/src/libvirt.c b/src/libvirt.c
index fc41a3f..659e5db 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -8887,6 +8887,184 @@ error:
}
/**
+ * virDomainSetMetadata:
+ * @domain: a domain object
+ * @type: type of description, from virDomainMetadataType
+ * @metadata: new metadata text
+ * @key: XML namespace key, or NULL
+ * @uri: XML namespace URI, or NULL
+ * @flags: bitwise-OR of virDomainModificationImpact
+ *
+ * Sets the appropriate domain element given by @type to the
+ * value of @description. A @type of VIR_DOMAIN_METADATA_DESCRIPTION
+ * is free-form text; VIR_DOMAIN_METADATA_TITLE is free-form, but no
+ * newlines are permitted, and should be short (although the length is
+ * not enforced). For these two options @key and @uri are irrelevant and
+ * must be set to NULL.
+ *
+ * For type VIR_DOMAIN_METADATA_ELEMENT @metadata must be well-formed
+ * XML belonging to namespace defined by @uri with local name @key.
+ *
+ * Passing NULL for @metadata says to remove that element from the
+ * domain XML (passing the empty string leaves the element present).
+ *
+ * The resulting metadata will be present in virDomainGetXMLDesc(),
+ * as well as quick access through virDomainGetMetadata().
+ *
+ * @flags controls whether the live domain, persistent configuration,
+ * or both will be modified.
+ *
+ * Returns 0 on success, -1 in case of failure.
+ */
+int
+virDomainSetMetadata(virDomainPtr domain,
+ int type,
+ const char *metadata,
+ const char *key,
+ const char *uri,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(domain,
+ "type=%d, metadata='%s', key='%s',
uri='%s', flags=%x",
+ type, NULLSTR(metadata), NULLSTR(key), NULLSTR(uri),
+ flags);
+
+ if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+ virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ goto error;
+ }
+
+ conn = domain->conn;
+
+ if (conn->flags & VIR_CONNECT_RO) {
+ virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+ goto error;
+ }
+
+ switch (type) {
+ case VIR_DOMAIN_METADATA_TITLE:
+ if (metadata && strchr(metadata, '\n')) {
+ virLibDomainError(VIR_ERR_INVALID_ARG, "%s",
+ _("Domain title can't contain
newlines"));
+ goto error;
+ }
+ /* fallthrough */
+ case VIR_DOMAIN_METADATA_DESCRIPTION:
+ if (uri || key) {
+ virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+ break;
+ case VIR_DOMAIN_METADATA_ELEMENT:
+ if (!uri || !key) {
+ virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+ break;
+ default:
+ /* For future expansion */
+ break;
+ }
+
+ if (conn->driver->domainSetMetadata) {
+ int ret;
+ ret = conn->driver->domainSetMetadata(domain, type, metadata, key, uri,
+ flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(domain->conn);
+ return -1;
+}
+
+/**
+ * virDomainGetMetadata:
+ * @domain: a domain object
+ * @type: type of description, from virDomainMetadataType
+ * @uri: XML namespace identifier
+ * @flags: bitwise-OR of virDomainModificationImpact
+ *
+ * Retrieves the appropriate domain element given by @type.
+ * If VIR_DOMAIN_METADATA_ELEMENT is requested parameter @uri
+ * must be set to the name of the namespace the requested elements
+ * belong to, otherwise must be NULL.
+ *
+ * If an element of the domain XML is not present, the resulting
+ * error will be VIR_ERR_NO_DOMAIN_METADATA. This method forms
+ * a shortcut for seeing information from virDomainSetMetadata()
+ * without having to go through virDomainGetXMLDesc().
+ *
+ * @flags controls whether the live domain or persistent
+ * configuration will be queried.
+ *
+ * Returns the metadata string on success (caller must free),
+ * or NULL in case of failure.
+ */
+char *
+virDomainGetMetadata(virDomainPtr domain,
+ int type,
+ const char *uri,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(domain, "type=%d, uri='%s', flags=%x",
+ type, NULLSTR(uri), flags);
+
+ if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+ virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ goto error;
+ }
+
+ if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
+ (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
+ virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ switch (type) {
+ case VIR_DOMAIN_METADATA_TITLE:
+ case VIR_DOMAIN_METADATA_DESCRIPTION:
+ if (uri) {
+ virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+ break;
+ case VIR_DOMAIN_METADATA_ELEMENT:
+ if (!uri) {
+ virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+ break;
+ default:
+ /* For future expansion */
+ break;
+ }
+
+ conn = domain->conn;
+
+ if (conn->driver->domainGetMetadata) {
+ char *ret;
+ if (!(ret = conn->driver->domainGetMetadata(domain, type, uri, flags)))
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(domain->conn);
+ return NULL;
+}
+
+/**
* virNodeGetSecurityModel:
* @conn: a connection object
* @secmodel: pointer to a virSecurityModel structure
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index ced9fb3..9bbd308 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -520,7 +520,9 @@ LIBVIRT_0.9.10 {
global:
virDomainGetCPUStats;
virDomainGetDiskErrors;
+ virDomainGetMetadata;
virDomainPMSuspendForDuration;
+ virDomainSetMetadata;
virDomainShutdownFlags;
virStorageVolResize;
virStorageVolWipePattern;
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 09b5ace..34816ad 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -4917,6 +4917,8 @@ static virDriver remote_driver = {
.domainGetNumaParameters = remoteDomainGetNumaParameters, /* 0.9.9 */
.domainGetCPUStats = remoteDomainGetCPUStats, /* 0.9.10 */
.domainGetDiskErrors = remoteDomainGetDiskErrors, /* 0.9.10 */
+ .domainSetMetadata = remoteDomainSetMetadata, /* 0.9.10 */
+ .domainGetMetadata = remoteDomainGetMetadata, /* 0.9.10 */
};
static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 10fd294..efb209a 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -1123,6 +1123,26 @@ struct remote_domain_set_autostart_args {
int autostart;
};
+struct remote_domain_set_metadata_args {
+ remote_nonnull_domain dom;
+ int type;
+ remote_string metadata;
+ remote_string key;
+ remote_string uri;
+ unsigned int flags;
+};
+
+struct remote_domain_get_metadata_args {
+ remote_nonnull_domain dom;
+ int type;
+ remote_string uri;
+ unsigned int flags;
+};
+
+struct remote_domain_get_metadata_ret {
+ remote_nonnull_string metadata;
+};
+
struct remote_domain_block_job_abort_args {
remote_nonnull_domain dom;
remote_nonnull_string path;
@@ -2729,7 +2749,9 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_PM_SUSPEND_FOR_DURATION = 261, /* autogen autogen */
REMOTE_PROC_DOMAIN_GET_CPU_STATS = 262, /* skipgen skipgen */
- REMOTE_PROC_DOMAIN_GET_DISK_ERRORS = 263 /* skipgen skipgen */
+ REMOTE_PROC_DOMAIN_GET_DISK_ERRORS = 263, /* skipgen skipgen */
+ REMOTE_PROC_DOMAIN_SET_METADATA = 264, /* autogen autogen */
+ REMOTE_PROC_DOMAIN_GET_METADATA = 265 /* autogen autogen */
/*
* Notice how the entries are grouped in sets of 10 ?
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index ee2207c..8b66a5f 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -788,6 +788,23 @@ struct remote_domain_set_autostart_args {
remote_nonnull_domain dom;
int autostart;
};
+struct remote_domain_set_metadata_args {
+ remote_nonnull_domain dom;
+ int type;
+ remote_string metadata;
+ remote_string key;
+ remote_string uri;
+ u_int flags;
+};
+struct remote_domain_get_metadata_args {
+ remote_nonnull_domain dom;
+ int type;
+ remote_string uri;
+ u_int flags;
+};
+struct remote_domain_get_metadata_ret {
+ remote_nonnull_string metadata;
+};
struct remote_domain_block_job_abort_args {
remote_nonnull_domain dom;
remote_nonnull_string path;
@@ -2146,4 +2163,6 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_PM_SUSPEND_FOR_DURATION = 261,
REMOTE_PROC_DOMAIN_GET_CPU_STATS = 262,
REMOTE_PROC_DOMAIN_GET_DISK_ERRORS = 263,
+ REMOTE_PROC_DOMAIN_SET_METADATA = 264,
+ REMOTE_PROC_DOMAIN_GET_METADATA = 265,
};
diff --git a/src/util/virterror.c b/src/util/virterror.c
index 31ddd9d..640f5d8 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -1226,6 +1226,12 @@ virErrorMsg(virErrorNumber error, const char *info)
else
errmsg = _("operation aborted: %s");
break;
+ case VIR_ERR_NO_DOMAIN_METADATA:
+ if (info == NULL)
+ errmsg = _("metadata not found");
+ else
+ errmsg = _("metadata not found");
+ break;
}
return (errmsg);
}
--
1.7.3.4