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

Daniel Veillard veillard at redhat.com
Thu Feb 2 13:08:06 UTC 2012


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 at veillard.com  | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library  http://libvirt.org/




More information about the libvir-list mailing list