On Wed, Feb 01, 2012 at 02:03:50PM +0100, Peter Krempa wrote: > 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; Okay we let the driver error directly on unsupported metadata type > + } > + > + 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"); %s missing as Eric pointed out, > + else > + errmsg = _("metadata not found"); > + break; > } > return (errmsg); > } ACK, better than what I had in mind :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@xxxxxxxxxxxx | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/ -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list