[libvirt] [RFC] Introduce API for retrieving bulk domain stats

Peter Krempa pkrempa at redhat.com
Tue Aug 19 13:14:19 UTC 2014


I'd like to propose a (hopefully) fairly future-proof API to retrieve
various statistics for domains.

The motivation is that management layers that use libvirt usually poll
libvirt for statistics using various split up APIs we currently provide.
To get all the necessary stuff, the mgmt app need to issue Ndomains *
Napis calls and cope with the various returned formats. The APIs I'm
wanting to introduce here will:

1) Return data in a format that we can expand in the future and is
hierarchical. For starters I'll use XML, with possible expansion to
something like JSON if it will be favourable for a consumer (switchable
by a flag)

2) Stats for multiple (all) domains can be queried at once and are
returned in one call. This will allow to decrease the overhead necessary
to issue multiple calls per domain multiplied by the count of domains.

3) Selectable (bit mask) fields in the returned format. This will allow
to retrieve only specific stats according to the APPs need.

The returned XML will have the following format:

<domainstats>
  <domain name='vm1'>
    <state>running</state>
    <cpus>
      <cpu id='1'>
        <state>running</state>
        <time>10001231231</time>
      </cpu>
      <cpu id='2'>
        <state>offline</state>
        <time>10001231231</time>
      <cpu>
      </cpus>
      ...
  </domain>
  <domain name='vm2'>
    <state>paused</state>
    ...
  </domain>
  <domain name='vm3'>
    <state>running</state>
    ...
  </domain>
</domainstats>

Initially the implementation will introduce the option to retrieve
block, interface  and cpu stats with the possibility to add more in the
future.

The stats groups will be enabled using a bit field @stats passed as the
function argument. A few groups for inspiration:

VIR_DOMAIN_STATS_CPU
VIR_DOMAIN_STATS_BLOCK
VIR_DOMAIN_STATS_INTERFACE

As this is a first draft and dump of my mind on this subject it may be
a bit rough, so suggestions are welcome.

Thanks for looking.

Peter
---
 include/libvirt/libvirt.h.in |  12 ++++
 src/driver.h                 |   8 +++
 src/libvirt.c                | 127 +++++++++++++++++++++++++++++++++++++++++++
 src/libvirt_public.syms      |   7 +++
 4 files changed, 154 insertions(+)

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 47ea695..72ab617 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2501,6 +2501,18 @@ int virDomainDetachDeviceFlags(virDomainPtr domain,
 int virDomainUpdateDeviceFlags(virDomainPtr domain,
                                const char *xml, unsigned int flags);

+char *virConnectGetAllDomainStats(virConnectPtr conn,
+                                  unsigned int stats,
+                                  unsigned int flags);
+
+char *virDomainListGetStats(virDomainPtr *doms,
+                            unsigned int stats,
+                            unsigned int flags);
+
+char *virDomainGetStats(virDomainPtr dom,
+                        unsigned int stats,
+                        unsigned int flags);
+
 /*
  * BlockJob API
  */
diff --git a/src/driver.h b/src/driver.h
index 158df79..2650e90 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -1191,6 +1191,13 @@ typedef int
                           unsigned int flags);


+typedef char *
+(*virDrvDomainListGetStats)(virConnectPtr conn,
+                            virDomainPtr *doms,
+                            unsigned int ndoms,
+                            unsigned int stats,
+                            unsigned int flags);
+
 typedef struct _virDriver virDriver;
 typedef virDriver *virDriverPtr;

@@ -1411,6 +1418,7 @@ struct _virDriver {
     virDrvDomainSetTime domainSetTime;
     virDrvNodeGetFreePages nodeGetFreePages;
     virDrvConnectGetDomainCapabilities connectGetDomainCapabilities;
+    virDrvDomainListGetStats domainListGetStats;
 };


diff --git a/src/libvirt.c b/src/libvirt.c
index 992e4f2..10e0b70 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -21341,3 +21341,130 @@ virConnectGetDomainCapabilities(virConnectPtr conn,
     virDispatchError(conn);
     return NULL;
 }
+
+
+/**
+ * virConnectGetAllDomainStats:
+ * @conn: pointer to the hypervisor connection
+ * @stats: stats to return, binary OR of virDomainStats
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Report statistics of various parameters for a running VM.
+ *
+ * Returns an XML containing the requested stats or NULL on error. The
+ * returned string shall be freed by the caller.
+ */
+char *
+virConnectGetAllDomainStats(virConnectPtr conn,
+                            unsigned int stats,
+                            unsigned int flags)
+{
+    char *ret = NULL;
+
+    VIR_DEBUG("conn=%p, stats=0x%x, flags=0x%x",
+              conn, stats, flags);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, NULL);
+
+    if (!conn->driver->domainListGetStats) {
+        virReportUnsupportedError();
+        goto cleanup;
+    }
+
+    ret = conn->driver->domainListGetStats(conn, NULL, 0, stats, flags);
+
+ cleanup:
+    if (!ret)
+        virDispatchError(conn);
+
+    return ret;
+}
+
+
+/**
+ * virDomainListGetStats:
+ * @doms: NULL terminated array of domains
+ * @stats: stats to return, binary OR of virDomainStats
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Report statistics of various parameters for a running VM.
+ *
+ * Returns an XML containing the requested stats or NULL on error. The
+ * returned string shall be freed by the caller.
+ */
+char *
+virDomainListGetStats(virDomainPtr *doms,
+                      unsigned int stats,
+                      unsigned int flags)
+{
+    virConnectPtr conn = NULL;
+    virDomainPtr *nextdom = doms;
+    unsigned int ndoms = 0;
+    char *ret = NULL;
+
+    VIR_DEBUG("doms=%p, stats=0x%x, flags=0x%x",
+              doms, stats, flags);
+
+    virResetLastError();
+
+    if (!*doms) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("doms array in %s must contain at leas one domain"),
+                       __FUNCTION__);
+        goto cleanup;
+    }
+
+    conn = doms[0]->conn;
+
+    if (!conn->driver->domainListGetStats) {
+        virReportUnsupportedError();
+        goto cleanup;
+    }
+
+    while (*(++nextdom)) {
+        virDomainPtr dom = *nextdom;
+
+        virCheckDomainGoto(dom, cleanup);
+
+        if (dom->conn != conn) {
+            virReportError(VIR_ERR_INVALID_ARG,
+                           _("domains in 'doms' array must belong to a "
+                             "single connection in %s"), __FUNCTION__);
+            goto cleanup;
+        }
+
+        ndoms++;
+    }
+
+    ret = conn->driver->domainListGetStats(conn, doms, ndoms, stats, flags);
+
+ cleanup:
+    if (!ret)
+        virDispatchError(conn);
+    return ret;
+}
+
+
+/**
+ * virDomainGetStats:
+ * @dom: a domain object
+ * @stats: stats to return, binary OR of virDomainStats
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Convenience wrapper to get stats for a single domain.
+ * See virDomainListGetStats for more info.
+ *
+ * Returns an XML containing the requested stats or NULL on error. The
+ * returned string shall be freed by the caller.
+ */
+char *
+virDomainGetStats(virDomainPtr dom,
+                  unsigned int stats,
+                  unsigned int flags)
+{
+    virDomainPtr doms[2] = {dom, NULL};
+
+    return virDomainListGetStats(doms, stats, flags);
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 9f4016a..5bb25ab 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -670,4 +670,11 @@ LIBVIRT_1.2.7 {
         virConnectGetDomainCapabilities;
 } LIBVIRT_1.2.6;

+LIBVIRT_1.2.8 {
+    global:
+        virDomainListGetStats;
+        virDomainGetStats;
+        virConnectGetAllDomainStats;
+} LIBVIRT_1.2.7;
+
 # .... define new API here using predicted next version number ....
-- 
2.0.2




More information about the libvir-list mailing list