diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index cf53cf260d3d8b6b843724f63b002fdbd9e21ff1..07d03fa160a86867cba47720e60a7292efff4ad9 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 */ + VIR_DOMAIN_METADATA_TITLE = 1, /* Operate on */ + 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 9844cbe23f1f076888294b3f8ad00fc73239e82a..9dbadfe63f47a078dd35de404fe8bc7d09226acc 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 9ff5edf18fc076b962bec61fb94d5e9118f1df4f..d6ee60f4982fe33668c1e4e069fe9f1688aed030 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 fc41a3fad2ac103acfbae9066d54db0ef09b6f29..659e5db4e4968876e3ffb872e7ff70972ec192b4 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -8886,6 +8886,184 @@ error: return -1; } +/** + * 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 diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index ced9fb3969ffac7e302522e39a94a3fd3b70c361..9bbd3082f60f09020a5ca4fbd7a528e691f3b99a 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 09b5ace66675e294c66751abc8680cd621b14211..34816ad44002bf460c39f6bade704fb6e72c08c8 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 10fd2940a885961f12beeb4441dea519448f18bb..efb209a23ebdfde3971252e3b48b7cb6dac90a9b 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 ee2207ca5261a4247610c44ec08f70532b39bf44..8b66a5fbea96a5175acd664c2c8bed1320356415 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 31ddd9d2d3c8be11c9ceabae111b6241e03c3a57..edd5198640b35bf9aab9174a7a25f235b30da048 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -1,7 +1,7 @@ /* * virterror.c: implements error handling and reporting code for libvirt * - * Copy: Copyright (C) 2006, 2008-2011 Red Hat, Inc. + * Copy: Copyright (C) 2006, 2008-2012 Red Hat, Inc. * * See COPYING.LIB for the License of this software * @@ -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: %s"); + break; } return (errmsg); }