From 1a2be7098cf5acfd893153abb52b65e69631dcec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= <cbosdonnat@suse.com>
Date: Tue, 2 Jan 2018 14:44:39 +0100
Subject: [PATCH 2/3] lxc: implement connectGetAllDomainStats

LXC containers can also provide some statistics. Allow users to fetch
them using the existing API.
---
 src/lxc/lxc_driver.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 138 insertions(+)

Index: libvirt-4.0.0/src/lxc/lxc_driver.c
===================================================================
--- libvirt-4.0.0.orig/src/lxc/lxc_driver.c
+++ libvirt-4.0.0/src/lxc/lxc_driver.c
@@ -81,6 +81,7 @@
 #include "viraccessapichecklxc.h"
 #include "virhostdev.h"
 #include "netdev_bandwidth_conf.h"
+#include "domain_stats.h"
 
 #define VIR_FROM_THIS VIR_FROM_LXC
 
@@ -5485,6 +5486,142 @@ lxcDomainHasManagedSaveImage(virDomainPt
     return ret;
 }
 
+static int
+lxcDomainGetStatsCpu(virDomainObjPtr dom,
+                     virDomainStatsRecordPtr record,
+                     int *maxparams)
+{
+    virLXCDomainObjPrivatePtr priv = dom->privateData;
+    return virCgroupGetStatsCpu(priv->cgroup, record, maxparams);
+}
+
+typedef int
+(*lxcDomainGetStatsFunc)(virDomainObjPtr dom,
+                         virDomainStatsRecordPtr record,
+                         int *maxparams);
+
+struct lxcDomainGetStatsWorker {
+    lxcDomainGetStatsFunc func;
+    unsigned int stats;
+};
+
+static struct lxcDomainGetStatsWorker lxcDomainGetStatsWorkers[] = {
+    { virDomainStatsGetState, VIR_DOMAIN_STATS_STATE },
+    { lxcDomainGetStatsCpu, VIR_DOMAIN_STATS_CPU_TOTAL },
+    { virDomainStatsGetInterface, VIR_DOMAIN_STATS_INTERFACE },
+    { NULL, 0 }
+};
+
+static int
+lxcDomainGetStats(virConnectPtr conn,
+                  virDomainObjPtr dom,
+                  unsigned int stats,
+                  virDomainStatsRecordPtr *record)
+{
+    int maxparams = 0;
+    virDomainStatsRecordPtr tmp;
+    size_t i;
+    int ret = -1;
+
+    if (VIR_ALLOC(tmp) < 0)
+        goto cleanup;
+
+    for (i = 0; lxcDomainGetStatsWorkers[i].func; i++) {
+        if (stats & lxcDomainGetStatsWorkers[i].stats) {
+            if (lxcDomainGetStatsWorkers[i].func(dom, tmp, &maxparams) < 0)
+                goto cleanup;
+        }
+    }
+
+    if (!(tmp->dom = virGetDomain(conn, dom->def->name,
+                                  dom->def->uuid, dom->def->id)))
+        goto cleanup;
+
+    *record = tmp;
+    tmp = NULL;
+    ret = 0;
+
+ cleanup:
+    if (tmp) {
+        virTypedParamsFree(tmp->params, tmp->nparams);
+        VIR_FREE(tmp);
+    }
+
+    return ret;
+}
+
+static int
+lxcConnectGetAllDomainStats(virConnectPtr conn,
+                            virDomainPtr *doms,
+                            unsigned int ndoms,
+                            unsigned int stats,
+                            virDomainStatsRecordPtr **retStats,
+                            unsigned int flags)
+{
+    virLXCDriverPtr driver = conn->privateData;
+    virDomainObjPtr *vms = NULL;
+    virDomainObjPtr vm;
+    size_t nvms;
+    virDomainStatsRecordPtr *tmpstats = NULL;
+    int nstats = 0;
+    size_t i;
+    int ret = -1;
+    unsigned int lflags = flags & (VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE |
+                                   VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT |
+                                   VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE);
+
+    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE |
+                  VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT |
+                  VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE, -1);
+
+    if (virConnectGetAllDomainStatsEnsureACL(conn) < 0)
+        return -1;
+
+    /* TODO Check stats support */
+
+    if (ndoms) {
+        if (virDomainObjListConvert(driver->domains, conn, doms, ndoms, &vms,
+                                    &nvms, virConnectGetAllDomainStatsCheckACL,
+                                    lflags, true) < 0)
+            return -1;
+    } else {
+        if (virDomainObjListCollect(driver->domains, conn, &vms, &nvms,
+                                    virConnectGetAllDomainStatsCheckACL,
+                                    lflags) < 0)
+            return -1;
+    }
+
+    if (VIR_ALLOC_N(tmpstats, nvms + 1) < 0)
+        return -1;
+
+    for (i = 0; i < nvms; i++) {
+        virDomainStatsRecordPtr tmp = NULL;
+        vm = vms[i];
+
+        virObjectLock(vm);
+
+        if (lxcDomainGetStats(conn, vm, stats, &tmp) < 0) {
+            virObjectUnlock(vm);
+            goto cleanup;
+        }
+
+        if (tmp)
+            tmpstats[nstats++] = tmp;
+
+        virObjectUnlock(vm);
+    }
+
+    *retStats = tmpstats;
+    tmpstats = NULL;
+
+    ret = nstats;
+
+ cleanup:
+    virDomainStatsRecordListFree(tmpstats);
+    virObjectListFreeCount(vms, nvms);
+
+    return ret;
+}
 
 /* Function Tables */
 static virHypervisorDriver lxcHypervisorDriver = {
@@ -5579,6 +5716,7 @@ static virHypervisorDriver lxcHypervisor
     .nodeGetFreePages = lxcNodeGetFreePages, /* 1.2.6 */
     .nodeAllocPages = lxcNodeAllocPages, /* 1.2.9 */
     .domainHasManagedSaveImage = lxcDomainHasManagedSaveImage, /* 1.2.13 */
+    .connectGetAllDomainStats = lxcConnectGetAllDomainStats, /* 3.11.0 */
 };
 
 static virConnectDriver lxcConnectDriver = {
