[libvirt] [PATCHv2 2/4] API: Add api to set and get domain metadata

Eric Blake eblake at redhat.com
Tue Jan 31 00:20:01 UTC 2012


On 01/30/2012 08:09 AM, 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
> ---
> Diff to v1:
> - lifted the length restriction and tweaked commands according to that
> - moved argument checks from driver to main library implementation
> - sorted entries in symbol list
> 
>  include/libvirt/libvirt.h.in |   24 ++++++
>  include/libvirt/virterror.h  |    1 +
>  src/driver.h                 |   16 ++++
>  src/libvirt.c                |  181 ++++++++++++++++++++++++++++++++++++++++++
>  src/libvirt_public.syms      |    2 +
>  src/remote/remote_driver.c   |    2 +
>  src/remote/remote_protocol.x |   24 ++++++-

'yum install dwarves' then 'make check' fails, because you didn't update
src/remote_protocol-structs.

>  /**
> + * 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
> + * can be set to NULL.

s/can be/must be/ (since you error out if they are non-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)

I think we've settled on a good API.

> +
> +    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;

These are okay,

> +    default:
> +         virLibDomainError(VIR_ERR_INVALID_ARG, "%s",
> +                           _("Invalid metadata type"));
> +         goto error;
> +         break;

but I don't like this one.  If you have an older client trying to talk
to a newer server, where the newer server understands a fourth type of
metadata, then we should not be getting in the way of the client passing
that data over RPC.

> +/**
> + * 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.

Also mention:

Otherwise, uri 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=%p, flags=%x",
> +                     type, uri, flags);

Here (and in the setter), I'd use "uri=%s"/NULLSTR(uri), rather
"uri=%p"/uri, as that makes debugging a bit nicer when we know we have a
validly-null string.

> +
> +    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, "%s",
> +                          _("Can't specify both LIVE and CONFIG flags"));
> +        goto error;

Elsewhere, we just used the terser:

    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;

Again, fine with these, (we have a defined semantic for these flags)

> +    default:
> +         virLibDomainError(VIR_ERR_INVALID_ARG, "%s",
> +                           _("Invalid metadata type"));
> +         goto error;
> +         break;

but not this (this prevents expansion).

> --- a/src/remote/remote_protocol.x
> +++ b/src/remote/remote_protocol.x
> @@ -1114,6 +1114,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_string metadata;

This should be remote_nonnull_string (errors are returned automatically;
the _ret struct is only used on success, which means it will never be
used for NULL).

> @@ -2708,7 +2728,9 @@ enum remote_procedure {
>      REMOTE_PROC_STORAGE_VOL_RESIZE = 260, /* autogen autogen */
> 
>      REMOTE_PROC_DOMAIN_PM_SUSPEND_FOR_DURATION = 261, /* autogen autogen */
> -    REMOTE_PROC_DOMAIN_GET_CPU_STATS = 262 /* skipgen skipgen */
> +    REMOTE_PROC_DOMAIN_GET_CPU_STATS = 262, /* skipgen skipgen */
> +    REMOTE_PROC_DOMAIN_SET_METADATA = 263, /* autogen autogen */
> +    REMOTE_PROC_DOMAIN_GET_METADATA = 264 /* autogen autogen */

I'm surprised our generator didn't complain about things - it should be
requiring nonnull_string in *_ret (but that can be a patch for a
different day).

I'm interested in this API making it into 0.9.10, and I think you're
close enough that you could push this after fixing the issues I pointed
out above.  ACK with above issues fixed.

-- 
Eric Blake   eblake at redhat.com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 620 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20120130/deb1f029/attachment-0001.sig>


More information about the libvir-list mailing list