virt: Add domain state metrics dispatch
[collectd.git] / src / virt.c
index 20336b4..1b70b22 100644 (file)
@@ -467,6 +467,7 @@ struct interface_device {
 typedef struct domain_s {
   virDomainPtr ptr;
   virDomainInfo info;
+  _Bool active;
 } domain_t;
 
 struct lv_read_state {
@@ -482,7 +483,8 @@ struct lv_read_state {
 };
 
 static void free_domains(struct lv_read_state *state);
-static int add_domain(struct lv_read_state *state, virDomainPtr dom);
+static int add_domain(struct lv_read_state *state, virDomainPtr dom,
+                      _Bool active);
 
 static void free_block_devices(struct lv_read_state *state);
 static int add_block_device(struct lv_read_state *state, virDomainPtr dom,
@@ -1416,6 +1418,15 @@ static int get_vcpu_stats(virDomainPtr domain, unsigned short nr_virt_cpu) {
 }
 
 #ifdef HAVE_DOM_REASON
+
+static void domain_state_submit(virDomainPtr dom, int state, int reason) {
+  value_t values[] = {
+      {.gauge = (gauge_t)state}, {.gauge = (gauge_t)reason},
+  };
+
+  submit(dom, "domain_state", NULL, values, STATIC_ARRAY_SIZE(values));
+}
+
 static int get_domain_state(virDomainPtr domain) {
   int domain_state = 0;
   int domain_reason = 0;
@@ -1427,6 +1438,8 @@ static int get_domain_state(virDomainPtr domain) {
     return status;
   }
 
+  domain_state_submit(domain, domain_state, domain_reason);
+
   return status;
 }
 
@@ -1991,10 +2004,16 @@ static int lv_read(user_data_t *ud) {
 
   /* Get domains' metrics */
   for (int i = 0; i < state->nr_domains; ++i) {
-    int status = get_domain_metrics(&state->domains[i]);
+    domain_t *dom = &state->domains[i];
+    int status;
+    if (dom->active)
+      status = get_domain_metrics(dom);
+    else
+      status = get_domain_state(dom->ptr);
+
     if (status != 0)
       ERROR(PLUGIN_NAME " failed to get metrics for domain=%s",
-            virDomainGetName(state->domains[i].ptr));
+            virDomainGetName(dom->ptr));
   }
 
   /* Get block device stats for each domain. */
@@ -2178,208 +2197,228 @@ static int refresh_lists(struct lv_read_instance *inst) {
   struct lv_read_state *state = &inst->read_state;
   int n;
 
+#ifndef HAVE_LIST_ALL_DOMAINS
   n = virConnectNumOfDomains(conn);
   if (n < 0) {
     VIRT_ERROR(conn, "reading number of domains");
     return -1;
   }
+#endif
 
   lv_clean_read_state(state);
 
-  if (n > 0) {
+#ifndef HAVE_LIST_ALL_DOMAINS
+  if (n == 0)
+    goto end;
+#endif
+
 #ifdef HAVE_LIST_ALL_DOMAINS
-    virDomainPtr *domains;
-    n = virConnectListAllDomains(conn, &domains,
-                                 VIR_CONNECT_LIST_DOMAINS_ACTIVE);
+  virDomainPtr *domains, *domains_inactive;
+  int m = virConnectListAllDomains(conn, &domains_inactive,
+                                   VIR_CONNECT_LIST_DOMAINS_INACTIVE);
+  n = virConnectListAllDomains(conn, &domains,
+                               VIR_CONNECT_LIST_DOMAINS_ACTIVE);
 #else
-    int *domids;
+  int *domids;
 
-    /* Get list of domains. */
-    domids = malloc(sizeof(*domids) * n);
-    if (domids == NULL) {
-      ERROR(PLUGIN_NAME " plugin: malloc failed.");
-      return -1;
-    }
+  /* Get list of domains. */
+  domids = malloc(sizeof(*domids) * n);
+  if (domids == NULL) {
+    ERROR(PLUGIN_NAME " plugin: malloc failed.");
+    return -1;
+  }
 
-    n = virConnectListDomains(conn, domids, n);
+  n = virConnectListDomains(conn, domids, n);
 #endif
 
-    if (n < 0) {
-      VIRT_ERROR(conn, "reading list of domains");
+  if (n < 0) {
+    VIRT_ERROR(conn, "reading list of domains");
 #ifndef HAVE_LIST_ALL_DOMAINS
-      sfree(domids);
+    sfree(domids);
+#else
+    sfree(domains_inactive);
 #endif
-      return -1;
+    return -1;
+  }
+
+#ifdef HAVE_LIST_ALL_DOMAINS
+  for (int i = 0; i < m; ++i)
+    if (add_domain(state, domains_inactive[i], 0) < 0) {
+      ERROR(PLUGIN_NAME " plugin: malloc failed.");
+      continue;
     }
+#endif
 
-    /* Fetch each domain and add it to the list, unless ignore. */
-    for (int i = 0; i < n; ++i) {
-      const char *name;
-      char *xml = NULL;
-      xmlDocPtr xml_doc = NULL;
-      xmlXPathContextPtr xpath_ctx = NULL;
-      xmlXPathObjectPtr xpath_obj = NULL;
-      char tag[PARTITION_TAG_MAX_LEN] = {'\0'};
-      virDomainInfo info;
-      int status;
+  /* Fetch each domain and add it to the list, unless ignore. */
+  for (int i = 0; i < n; ++i) {
+    const char *name;
+    char *xml = NULL;
+    xmlDocPtr xml_doc = NULL;
+    xmlXPathContextPtr xpath_ctx = NULL;
+    xmlXPathObjectPtr xpath_obj = NULL;
+    char tag[PARTITION_TAG_MAX_LEN] = {'\0'};
+    virDomainInfo info;
+    int status;
 
 #ifdef HAVE_LIST_ALL_DOMAINS
-      virDomainPtr dom = domains[i];
+    virDomainPtr dom = domains[i];
 #else
-      virDomainPtr dom = NULL;
-      dom = virDomainLookupByID(conn, domids[i]);
-      if (dom == NULL) {
-        VIRT_ERROR(conn, "virDomainLookupByID");
-        /* Could be that the domain went away -- ignore it anyway. */
-        continue;
-      }
+    virDomainPtr dom = NULL;
+    dom = virDomainLookupByID(conn, domids[i]);
+    if (dom == NULL) {
+      VIRT_ERROR(conn, "virDomainLookupByID");
+      /* Could be that the domain went away -- ignore it anyway. */
+      continue;
+    }
 #endif
 
-      name = virDomainGetName(dom);
-      if (name == NULL) {
-        VIRT_ERROR(conn, "virDomainGetName");
-        goto cont;
-      }
+    name = virDomainGetName(dom);
+    if (name == NULL) {
+      VIRT_ERROR(conn, "virDomainGetName");
+      goto cont;
+    }
 
-      status = virDomainGetInfo(dom, &info);
-      if (status != 0) {
-        ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.",
-              status);
-        continue;
-      }
+    status = virDomainGetInfo(dom, &info);
+    if (status != 0) {
+      ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.",
+            status);
+      continue;
+    }
 
-      if (info.state != VIR_DOMAIN_RUNNING) {
-        DEBUG(PLUGIN_NAME " plugin: skipping inactive domain %s", name);
-        continue;
-      }
+    if (info.state != VIR_DOMAIN_RUNNING) {
+      DEBUG(PLUGIN_NAME " plugin: skipping inactive domain %s", name);
+      continue;
+    }
 
-      if (il_domains && ignorelist_match(il_domains, name) != 0)
-        goto cont;
+    if (il_domains && ignorelist_match(il_domains, name) != 0)
+      goto cont;
 
-      /* Get a list of devices for this domain. */
-      xml = virDomainGetXMLDesc(dom, 0);
-      if (!xml) {
-        VIRT_ERROR(conn, "virDomainGetXMLDesc");
-        goto cont;
-      }
+    /* Get a list of devices for this domain. */
+    xml = virDomainGetXMLDesc(dom, 0);
+    if (!xml) {
+      VIRT_ERROR(conn, "virDomainGetXMLDesc");
+      goto cont;
+    }
 
-      /* Yuck, XML.  Parse out the devices. */
-      xml_doc = xmlReadDoc((xmlChar *)xml, NULL, NULL, XML_PARSE_NONET);
-      if (xml_doc == NULL) {
-        VIRT_ERROR(conn, "xmlReadDoc");
-        goto cont;
-      }
+    /* Yuck, XML.  Parse out the devices. */
+    xml_doc = xmlReadDoc((xmlChar *)xml, NULL, NULL, XML_PARSE_NONET);
+    if (xml_doc == NULL) {
+      VIRT_ERROR(conn, "xmlReadDoc");
+      goto cont;
+    }
 
-      xpath_ctx = xmlXPathNewContext(xml_doc);
+    xpath_ctx = xmlXPathNewContext(xml_doc);
 
-      if (lv_domain_get_tag(xpath_ctx, name, tag) < 0) {
-        ERROR(PLUGIN_NAME " plugin: lv_domain_get_tag failed.");
-        goto cont;
-      }
+    if (lv_domain_get_tag(xpath_ctx, name, tag) < 0) {
+      ERROR(PLUGIN_NAME " plugin: lv_domain_get_tag failed.");
+      goto cont;
+    }
 
-      if (!lv_instance_include_domain(inst, name, tag))
-        goto cont;
+    if (!lv_instance_include_domain(inst, name, tag))
+      goto cont;
 
-      if (add_domain(state, dom) < 0) {
-        ERROR(PLUGIN_NAME " plugin: malloc failed.");
-        goto cont;
-      }
+    if (add_domain(state, dom, 1) < 0) {
+      ERROR(PLUGIN_NAME " plugin: malloc failed.");
+      goto cont;
+    }
 
-      /* Block devices. */
-      const char *bd_xmlpath = "/domain/devices/disk/target[@dev]";
-      if (blockdevice_format == source)
-        bd_xmlpath = "/domain/devices/disk/source[@dev]";
-      xpath_obj = xmlXPathEval((const xmlChar *)bd_xmlpath, xpath_ctx);
+    /* Block devices. */
+    const char *bd_xmlpath = "/domain/devices/disk/target[@dev]";
+    if (blockdevice_format == source)
+      bd_xmlpath = "/domain/devices/disk/source[@dev]";
+    xpath_obj = xmlXPathEval((const xmlChar *)bd_xmlpath, xpath_ctx);
 
-      if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
-          xpath_obj->nodesetval == NULL)
-        goto cont;
+    if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
+        xpath_obj->nodesetval == NULL)
+      goto cont;
 
-      for (int j = 0; j < xpath_obj->nodesetval->nodeNr; ++j) {
-        xmlNodePtr node;
-        char *path = NULL;
+    for (int j = 0; j < xpath_obj->nodesetval->nodeNr; ++j) {
+      xmlNodePtr node;
+      char *path = NULL;
 
-        node = xpath_obj->nodesetval->nodeTab[j];
-        if (!node)
-          continue;
-        path = (char *)xmlGetProp(node, (xmlChar *)"dev");
-        if (!path)
-          continue;
+      node = xpath_obj->nodesetval->nodeTab[j];
+      if (!node)
+        continue;
+      path = (char *)xmlGetProp(node, (xmlChar *)"dev");
+      if (!path)
+        continue;
 
-        if (il_block_devices &&
-            ignore_device_match(il_block_devices, name, path) != 0)
-          goto cont2;
+      if (il_block_devices &&
+          ignore_device_match(il_block_devices, name, path) != 0)
+        goto cont2;
 
-        add_block_device(state, dom, path);
-      cont2:
-        if (path)
-          xmlFree(path);
-      }
-      xmlXPathFreeObject(xpath_obj);
+      add_block_device(state, dom, path);
+    cont2:
+      if (path)
+        xmlFree(path);
+    }
+    xmlXPathFreeObject(xpath_obj);
 
-      /* Network interfaces. */
-      xpath_obj = xmlXPathEval(
-          (xmlChar *)"/domain/devices/interface[target[@dev]]", xpath_ctx);
-      if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
-          xpath_obj->nodesetval == NULL)
-        goto cont;
+    /* Network interfaces. */
+    xpath_obj = xmlXPathEval(
+        (xmlChar *)"/domain/devices/interface[target[@dev]]", xpath_ctx);
+    if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
+        xpath_obj->nodesetval == NULL)
+      goto cont;
 
-      xmlNodeSetPtr xml_interfaces = xpath_obj->nodesetval;
+    xmlNodeSetPtr xml_interfaces = xpath_obj->nodesetval;
 
-      for (int j = 0; j < xml_interfaces->nodeNr; ++j) {
-        char *path = NULL;
-        char *address = NULL;
-        xmlNodePtr xml_interface;
+    for (int j = 0; j < xml_interfaces->nodeNr; ++j) {
+      char *path = NULL;
+      char *address = NULL;
+      xmlNodePtr xml_interface;
 
-        xml_interface = xml_interfaces->nodeTab[j];
-        if (!xml_interface)
+      xml_interface = xml_interfaces->nodeTab[j];
+      if (!xml_interface)
+        continue;
+
+      for (xmlNodePtr child = xml_interface->children; child;
+           child = child->next) {
+        if (child->type != XML_ELEMENT_NODE)
           continue;
 
-        for (xmlNodePtr child = xml_interface->children; child;
-             child = child->next) {
-          if (child->type != XML_ELEMENT_NODE)
+        if (xmlStrEqual(child->name, (const xmlChar *)"target")) {
+          path = (char *)xmlGetProp(child, (const xmlChar *)"dev");
+          if (!path)
+            continue;
+        } else if (xmlStrEqual(child->name, (const xmlChar *)"mac")) {
+          address = (char *)xmlGetProp(child, (const xmlChar *)"address");
+          if (!address)
             continue;
-
-          if (xmlStrEqual(child->name, (const xmlChar *)"target")) {
-            path = (char *)xmlGetProp(child, (const xmlChar *)"dev");
-            if (!path)
-              continue;
-          } else if (xmlStrEqual(child->name, (const xmlChar *)"mac")) {
-            address = (char *)xmlGetProp(child, (const xmlChar *)"address");
-            if (!address)
-              continue;
-          }
         }
-
-        if (il_interface_devices &&
-            (ignore_device_match(il_interface_devices, name, path) != 0 ||
-             ignore_device_match(il_interface_devices, name, address) != 0))
-          goto cont3;
-
-        add_interface_device(state, dom, path, address, j + 1);
-      cont3:
-        if (path)
-          xmlFree(path);
-        if (address)
-          xmlFree(address);
       }
 
-    cont:
-      if (xpath_obj)
-        xmlXPathFreeObject(xpath_obj);
-      if (xpath_ctx)
-        xmlXPathFreeContext(xpath_ctx);
-      if (xml_doc)
-        xmlFreeDoc(xml_doc);
-      sfree(xml);
+      if (il_interface_devices &&
+          (ignore_device_match(il_interface_devices, name, path) != 0 ||
+           ignore_device_match(il_interface_devices, name, address) != 0))
+        goto cont3;
+
+      add_interface_device(state, dom, path, address, j + 1);
+    cont3:
+      if (path)
+        xmlFree(path);
+      if (address)
+        xmlFree(address);
     }
 
+  cont:
+    if (xpath_obj)
+      xmlXPathFreeObject(xpath_obj);
+    if (xpath_ctx)
+      xmlXPathFreeContext(xpath_ctx);
+    if (xml_doc)
+      xmlFreeDoc(xml_doc);
+    sfree(xml);
+  }
+
 #ifdef HAVE_LIST_ALL_DOMAINS
-    sfree(domains);
+  sfree(domains);
+  sfree(domains_inactive);
 #else
-    sfree(domids);
+  sfree(domids);
+
+end:
 #endif
-  }
 
   DEBUG(PLUGIN_NAME " plugin#%s: refreshing"
                     " domains=%i block_devices=%i iface_devices=%i",
@@ -2399,7 +2438,8 @@ static void free_domains(struct lv_read_state *state) {
   state->nr_domains = 0;
 }
 
-static int add_domain(struct lv_read_state *state, virDomainPtr dom) {
+static int add_domain(struct lv_read_state *state, virDomainPtr dom,
+                      _Bool active) {
   domain_t *new_ptr;
   int new_size = sizeof(state->domains[0]) * (state->nr_domains + 1);
 
@@ -2413,6 +2453,7 @@ static int add_domain(struct lv_read_state *state, virDomainPtr dom) {
 
   state->domains = new_ptr;
   state->domains[state->nr_domains].ptr = dom;
+  state->domains[state->nr_domains].active = active;
   memset(&state->domains[state->nr_domains].info, 0,
          sizeof(state->domains[state->nr_domains].info));