Merge branch 'master' into virt_list_domains
authorDenis Silakov <dsilakov@virtuozzo.com>
Thu, 2 Mar 2017 13:32:23 +0000 (16:32 +0300)
committerDenis Silakov <dsilakov@virtuozzo.com>
Thu, 2 Mar 2017 13:32:23 +0000 (16:32 +0300)
1  2 
src/virt.c

diff --cc src/virt.c
@@@ -529,514 -809,638 +809,666 @@@ static int lv_read(user_data_t *ud) 
                   interface_devices[i].path);
  #endif
  
-     /* Get CPU usage, memory, VCPU usage for each domain. */
-     for (int i = 0; i < nr_domains; ++i) {
-         virDomainInfo info;
-         virVcpuInfoPtr vinfo = NULL;
-         virDomainMemoryStatPtr minfo = NULL;
-         int status;
-         status = virDomainGetInfo (domains[i], &info);
-         if (status != 0)
-         {
-             ERROR (PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.",
-                     status);
-             continue;
-         }
+   /* Get CPU usage, memory, VCPU usage for each domain. */
+   for (int i = 0; i < state->nr_domains; ++i) {
+     struct lv_info info;
+     virVcpuInfoPtr vinfo = NULL;
+     virDomainMemoryStatPtr minfo = NULL;
+     int status;
+     init_lv_info(&info);
+     status = lv_domain_info(state->domains[i], &info);
+     if (status != 0) {
+       ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.",
+             status);
+       continue;
+     }
  
-         if (info.state != VIR_DOMAIN_RUNNING)
-         {
-             /* only gather stats for running domains */
-             continue;
-         }
+     pcpu_submit(state->domains[i], &info);
+     cpu_submit(info.di.cpuTime, state->domains[i], "virt_cpu_total");
+     memory_submit((gauge_t)info.di.memory * 1024, state->domains[i]);
  
-         cpu_submit (info.cpuTime, domains[i], "virt_cpu_total");
-         memory_submit ((gauge_t) info.memory * 1024, domains[i]);
+     vinfo = malloc(info.di.nrVirtCpu * sizeof(vinfo[0]));
+     if (vinfo == NULL) {
+       ERROR(PLUGIN_NAME " plugin: malloc failed.");
+       continue;
+     }
  
-         vinfo = malloc (info.nrVirtCpu * sizeof (vinfo[0]));
-         if (vinfo == NULL) {
-             ERROR (PLUGIN_NAME " plugin: malloc failed.");
-             continue;
-         }
+     status = virDomainGetVcpus(state->domains[i], vinfo, info.di.nrVirtCpu,
+                                /* cpu map = */ NULL, /* cpu map length = */ 0);
+     if (status < 0) {
+       ERROR(PLUGIN_NAME " plugin: virDomainGetVcpus failed with status %i.",
+             status);
+       sfree(vinfo);
+       continue;
+     }
  
-         status = virDomainGetVcpus (domains[i], vinfo, info.nrVirtCpu,
-                 /* cpu map = */ NULL, /* cpu map length = */ 0);
-         if (status < 0)
-         {
-             ERROR (PLUGIN_NAME " plugin: virDomainGetVcpus failed with status %i.",
-                     status);
-             sfree (vinfo);
-             continue;
-         }
+     for (int j = 0; j < info.di.nrVirtCpu; ++j)
+       vcpu_submit(vinfo[j].cpuTime, state->domains[i], vinfo[j].number,
+                   "virt_vcpu");
  
-         for (int j = 0; j < info.nrVirtCpu; ++j)
-             vcpu_submit (vinfo[j].cpuTime,
-                     domains[i], vinfo[j].number, "virt_vcpu");
+     sfree(vinfo);
  
-         sfree (vinfo);
+     minfo =
+         malloc(VIR_DOMAIN_MEMORY_STAT_NR * sizeof(virDomainMemoryStatStruct));
+     if (minfo == NULL) {
+       ERROR("virt plugin: malloc failed.");
+       continue;
+     }
  
-         minfo = malloc (VIR_DOMAIN_MEMORY_STAT_NR * sizeof (virDomainMemoryStatStruct));
-         if (minfo == NULL) {
-             ERROR ("virt plugin: malloc failed.");
-             continue;
-         }
+     status = virDomainMemoryStats(state->domains[i], minfo,
+                                   VIR_DOMAIN_MEMORY_STAT_NR, 0);
  
-         status = virDomainMemoryStats (domains[i], minfo, VIR_DOMAIN_MEMORY_STAT_NR, 0);
+     if (status < 0) {
+       ERROR("virt plugin: virDomainMemoryStats failed with status %i.", status);
+       sfree(minfo);
+       continue;
+     }
  
-         if (status < 0) {
-             ERROR ("virt plugin: virDomainMemoryStats failed with status %i.",
-                     status);
-             sfree (minfo);
-             continue;
-         }
+     for (int j = 0; j < status; j++) {
+       memory_stats_submit((gauge_t)minfo[j].val * 1024, state->domains[i],
+                           minfo[j].tag);
+     }
  
-         for (int j = 0; j < status; j++) {
-             memory_stats_submit ((gauge_t) minfo[j].val * 1024, domains[i], minfo[j].tag);
-         }
+     sfree(minfo);
+   }
+   /* Get block device stats for each domain. */
+   for (int i = 0; i < state->nr_block_devices; ++i) {
+     struct block_device *bdev = &(state->block_devices[i]);
+     struct lv_block_info binfo;
+     init_block_info(&binfo);
+     if (lv_domain_block_info(bdev->dom, bdev->path, &binfo) < 0)
+       continue;
+     char *type_instance = bdev->path;
+     char *path = NULL;
+     if (blockdevice_format_basename && blockdevice_format == source) {
+       path = strdup(bdev->path);
+       if (path == NULL) {
+         WARNING(PLUGIN_NAME
+                 " plugin: error extracting the basename for '%s', skipped",
+                 bdev->path);
+         continue;
+       }
+       type_instance = basename(path);
+     }
  
-         sfree (minfo);
+     disk_submit(&binfo, bdev->dom, type_instance);
+     sfree(path);
+   } /* for (nr_block_devices) */
+   /* Get interface stats for each domain. */
+   for (int i = 0; i < state->nr_interface_devices; ++i) {
+     struct _virDomainInterfaceStats stats;
+     char *display_name = NULL;
+     switch (interface_format) {
+     case if_address:
+       display_name = state->interface_devices[i].address;
+       break;
+     case if_number:
+       display_name = state->interface_devices[i].number;
+       break;
+     case if_name:
+     default:
+       display_name = state->interface_devices[i].path;
      }
  
+     if (virDomainInterfaceStats(state->interface_devices[i].dom,
+                                 state->interface_devices[i].path, &stats,
+                                 sizeof stats) != 0)
+       continue;
+     if ((stats.rx_bytes != -1) && (stats.tx_bytes != -1))
+       submit_derive2("if_octets", (derive_t)stats.rx_bytes,
+                      (derive_t)stats.tx_bytes, state->interface_devices[i].dom,
+                      display_name);
+     if ((stats.rx_packets != -1) && (stats.tx_packets != -1))
+       submit_derive2("if_packets", (derive_t)stats.rx_packets,
+                      (derive_t)stats.tx_packets,
+                      state->interface_devices[i].dom, display_name);
+     if ((stats.rx_errs != -1) && (stats.tx_errs != -1))
+       submit_derive2("if_errors", (derive_t)stats.rx_errs,
+                      (derive_t)stats.tx_errs, state->interface_devices[i].dom,
+                      display_name);
+     if ((stats.rx_drop != -1) && (stats.tx_drop != -1))
+       submit_derive2("if_dropped", (derive_t)stats.rx_drop,
+                      (derive_t)stats.tx_drop, state->interface_devices[i].dom,
+                      display_name);
+   } /* for (nr_interface_devices) */
+   return 0;
+ }
  
-     /* Get block device stats for each domain. */
-     for (int i = 0; i < nr_block_devices; ++i) {
-         struct _virDomainBlockStats stats;
+ static int lv_init_instance(size_t i, plugin_read_cb callback) {
+   struct lv_user_data *lv_ud = &(lv_read_user_data[i]);
+   struct lv_read_instance *inst = &(lv_ud->inst);
  
-         if (virDomainBlockStats (block_devices[i].dom, block_devices[i].path,
-                     &stats, sizeof stats) != 0)
-             continue;
+   memset(lv_ud, 0, sizeof(*lv_ud));
  
-         char *type_instance = NULL;
-         if (blockdevice_format_basename && blockdevice_format == source)
-             type_instance = strdup(basename(block_devices[i].path));
-         else
-             type_instance = strdup(block_devices[i].path);
-         if ((stats.rd_req != -1) && (stats.wr_req != -1))
-             submit_derive2 ("disk_ops",
-                     (derive_t) stats.rd_req, (derive_t) stats.wr_req,
-                     block_devices[i].dom, type_instance);
-         if ((stats.rd_bytes != -1) && (stats.wr_bytes != -1))
-             submit_derive2 ("disk_octets",
-                     (derive_t) stats.rd_bytes, (derive_t) stats.wr_bytes,
-                     block_devices[i].dom, type_instance);
-         sfree (type_instance);
-     } /* for (nr_block_devices) */
-     /* Get interface stats for each domain. */
-     for (int i = 0; i < nr_interface_devices; ++i) {
-         struct _virDomainInterfaceStats stats;
-         char *display_name = NULL;
-         switch (interface_format) {
-             case if_address:
-                 display_name = interface_devices[i].address;
-                 break;
-             case if_number:
-                 display_name = interface_devices[i].number;
-                 break;
-             case if_name:
-             default:
-                 display_name = interface_devices[i].path;
-         }
+   ssnprintf(inst->tag, sizeof(inst->tag), "%s-%zu", PLUGIN_NAME, i);
+   inst->id = i;
  
-         if (virDomainInterfaceStats (interface_devices[i].dom,
-                     interface_devices[i].path,
-                     &stats, sizeof stats) != 0)
-             continue;
+   user_data_t *ud = &(lv_ud->ud);
+   ud->data = inst;
+   ud->free_func = NULL;
  
-       if ((stats.rx_bytes != -1) && (stats.tx_bytes != -1))
-           submit_derive2 ("if_octets",
-                   (derive_t) stats.rx_bytes, (derive_t) stats.tx_bytes,
-                   interface_devices[i].dom, display_name);
+   INFO(PLUGIN_NAME " plugin: reader %s initialized", inst->tag);
+   return plugin_register_complex_read(NULL, inst->tag, callback, 0, ud);
+ }
  
-       if ((stats.rx_packets != -1) && (stats.tx_packets != -1))
-           submit_derive2 ("if_packets",
-                   (derive_t) stats.rx_packets, (derive_t) stats.tx_packets,
-                   interface_devices[i].dom, display_name);
+ static void lv_clean_read_state(struct lv_read_state *state) {
+   free_block_devices(state);
+   free_interface_devices(state);
+   free_domains(state);
+ }
  
-       if ((stats.rx_errs != -1) && (stats.tx_errs != -1))
-           submit_derive2 ("if_errors",
-                   (derive_t) stats.rx_errs, (derive_t) stats.tx_errs,
-                   interface_devices[i].dom, display_name);
+ static void lv_fini_instance(size_t i) {
+   struct lv_read_instance *inst = &(lv_read_user_data[i].inst);
+   struct lv_read_state *state = &(inst->read_state);
  
-       if ((stats.rx_drop != -1) && (stats.tx_drop != -1))
-           submit_derive2 ("if_dropped",
-                   (derive_t) stats.rx_drop, (derive_t) stats.tx_drop,
-                   interface_devices[i].dom, display_name);
-     } /* for (nr_interface_devices) */
+   lv_clean_read_state(state);
+   INFO(PLUGIN_NAME " plugin: reader %s finalized", inst->tag);
+ }
  
-     return 0;
+ static int lv_init(void) {
+   if (virInitialize() != 0)
+     return -1;
+   if (lv_connect() != 0)
+     return -1;
+   DEBUG(PLUGIN_NAME " plugin: starting %i instances", nr_instances);
+   for (int i = 0; i < nr_instances; ++i)
+     lv_init_instance(i, lv_read);
+   return 0;
+ }
+ /*
+  * returns 0 on success and <0 on error
+  */
+ static int lv_domain_get_tag(xmlXPathContextPtr xpath_ctx, const char *dom_name,
+                              char *dom_tag) {
+   char xpath_str[BUFFER_MAX_LEN] = {'\0'};
+   xmlXPathObjectPtr xpath_obj = NULL;
+   xmlNodePtr xml_node = NULL;
+   int ret = -1;
+   int err;
+   err = xmlXPathRegisterNs(xpath_ctx,
+                            (const xmlChar *)METADATA_VM_PARTITION_PREFIX,
+                            (const xmlChar *)METADATA_VM_PARTITION_URI);
+   if (err) {
+     ERROR(PLUGIN_NAME " plugin: xmlXpathRegisterNs(%s, %s) failed on domain %s",
+           METADATA_VM_PARTITION_PREFIX, METADATA_VM_PARTITION_URI, dom_name);
+     goto done;
+   }
+   ssnprintf(xpath_str, sizeof(xpath_str), "/domain/metadata/%s:%s/text()",
+             METADATA_VM_PARTITION_PREFIX, METADATA_VM_PARTITION_ELEMENT);
+   xpath_obj = xmlXPathEvalExpression((xmlChar *)xpath_str, xpath_ctx);
+   if (xpath_obj == NULL) {
+     ERROR(PLUGIN_NAME " plugin: xmlXPathEval(%s) failed on domain %s",
+           xpath_str, dom_name);
+     goto done;
+   }
+   if (xpath_obj->type != XPATH_NODESET) {
+     ERROR(PLUGIN_NAME " plugin: xmlXPathEval(%s) unexpected return type %d "
+                       "(wanted %d) on domain %s",
+           xpath_str, xpath_obj->type, XPATH_NODESET, dom_name);
+     goto done;
+   }
+   /*
+    * from now on there is no real error, it's ok if a domain
+    * doesn't have the metadata partition tag.
+    */
+   ret = 0;
+   if (xpath_obj->nodesetval == NULL || xpath_obj->nodesetval->nodeNr != 1) {
+     DEBUG(PLUGIN_NAME " plugin: xmlXPathEval(%s) return nodeset size=%i "
+                       "expected=1 on domain %s",
+           xpath_str,
+           (xpath_obj->nodesetval == NULL) ? 0 : xpath_obj->nodesetval->nodeNr,
+           dom_name);
+   } else {
+     xml_node = xpath_obj->nodesetval->nodeTab[0];
+     sstrncpy(dom_tag, (const char *)xml_node->content, PARTITION_TAG_MAX_LEN);
+   }
+ done:
+   /* deregister to clean up */
+   err = xmlXPathRegisterNs(xpath_ctx,
+                            (const xmlChar *)METADATA_VM_PARTITION_PREFIX, NULL);
+   if (err) {
+     /* we can't really recover here */
+     ERROR(PLUGIN_NAME
+           " plugin: deregistration of namespace %s failed for domain %s",
+           METADATA_VM_PARTITION_PREFIX, dom_name);
+   }
+   if (xpath_obj)
+     xmlXPathFreeObject(xpath_obj);
+   return ret;
+ }
+ static int is_known_tag(const char *dom_tag) {
+   for (int i = 0; i < nr_instances; ++i)
+     if (!strcmp(dom_tag, lv_read_user_data[i].inst.tag))
+       return 1;
+   return 0;
+ }
+ static int lv_instance_include_domain(struct lv_read_instance *inst,
+                                       const char *dom_name,
+                                       const char *dom_tag) {
+   if ((dom_tag[0] != '\0') && (strcmp(dom_tag, inst->tag) == 0))
+     return 1;
+   /* instance#0 will always be there, so it is in charge of extra duties */
+   if (inst->id == 0) {
+     if (dom_tag[0] == '\0' || !is_known_tag(dom_tag)) {
+       DEBUG(PLUGIN_NAME " plugin#%s: refreshing domain %s "
+                         "with unknown tag '%s'",
+             inst->tag, dom_name, dom_tag);
+       return 1;
+     }
+   }
+   return 0;
  }
  
- static int
- refresh_lists (void)
- {
-     int n;
 +/*
 +  virConnectListAllDomains() appeared in 0.10.2
 +  Note that LIBVIR_CHECK_VERSION appeared a year later, so
 +  in some systems which actually have virConnectListAllDomains()
 +  we can't detect this.
 + */
 +#ifdef LIBVIR_CHECK_VERSION
 +# if LIBVIR_CHECK_VERSION(0,10,2)
 +#  define HAVE_LIST_ALL_DOMAINS 1
 +# endif
 +#endif
 +
+ static int refresh_lists(struct lv_read_instance *inst) {
+   struct lv_read_state *state = &inst->read_state;
+   int n;
  
-     n = virConnectNumOfDomains (conn);
-     if (n < 0) {
-         VIRT_ERROR (conn, "reading number of domains");
-         return -1;
-     }
+   n = virConnectNumOfDomains(conn);
+   if (n < 0) {
+     VIRT_ERROR(conn, "reading number of domains");
+     return -1;
+   }
  
-     if (n > 0) {
+   lv_clean_read_state(state);
+   if (n > 0) {
 +#ifdef HAVE_LIST_ALL_DOMAINS
-         virDomainPtr *domains;
-         n = virConnectListAllDomains (conn, &domains, VIR_CONNECT_LIST_DOMAINS_ACTIVE);
++    virDomainPtr *domains;
++    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);
 +#endif
-             return -1;
-         }
-         free_block_devices ();
-         free_interface_devices ();
-         free_domains ();
+       return -1;
+     }
  
-         /* 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;
+     /* Fetch each domain and add it to the list, unless ignore. */
+     for (int i = 0; i < n; ++i) {
 -      virDomainPtr dom = NULL;
+       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;
  
-             virDomainPtr dom = domains[i];
 +#ifdef HAVE_LIST_ALL_DOMAINS
-             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 = 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;
+       }
 +#endif
  
-             name = virDomainGetName (dom);
-             if (name == NULL) {
-                 VIRT_ERROR (conn, "virDomainGetName");
-                 goto cont;
-             }
-             if (il_domains && ignorelist_match (il_domains, name) != 0)
-                 goto cont;
-             if (add_domain (dom) < 0) {
-                 ERROR (PLUGIN_NAME " plugin: malloc failed.");
-                 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;
-             }
-             xpath_ctx = xmlXPathNewContext (xml_doc);
-             /* Block devices. */
-             char *bd_xmlpath = "/domain/devices/disk/target[@dev]";
-             if (blockdevice_format == source)
-                 bd_xmlpath = "/domain/devices/disk/source[@dev]";
-             xpath_obj = xmlXPathEval ((xmlChar *) bd_xmlpath, xpath_ctx);
-             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;
-                 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;
-                 add_block_device (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;
-             xmlNodeSetPtr xml_interfaces = xpath_obj->nodesetval;
-             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) continue;
-                 for (xmlNodePtr child = xml_interface->children; child; child = child->next) {
-                     if (child->type != XML_ELEMENT_NODE) 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 (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);
+       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;
+       }
+       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;
+       /* 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;
+       }
+       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_instance_include_domain(inst, name, tag))
+         goto cont;
+       if (add_domain(state, dom) < 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);
+       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;
+         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;
+         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;
+       xmlNodeSetPtr xml_interfaces = xpath_obj->nodesetval;
+       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)
+           continue;
+         for (xmlNodePtr child = xml_interface->children; child;
+              child = child->next) {
+           if (child->type != XML_ELEMENT_NODE)
+             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;
+           }
          }
  
-         sfree (domains);
+         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 (domids);
++    sfree (domains);
 +#else
-     }
+     sfree(domids);
 +#endif
+   }
  
-     return 0;
+   DEBUG(PLUGIN_NAME " plugin#%s: refreshing"
+                     " domains=%i block_devices=%i iface_devices=%i",
+         inst->tag, state->nr_domains, state->nr_block_devices,
+         state->nr_interface_devices);
+   return 0;
  }
  
- static void
- free_domains (void)
- {
-     if (domains) {
-         for (int i = 0; i < nr_domains; ++i)
-             virDomainFree (domains[i]);
-         sfree (domains);
-     }
-     domains = NULL;
-     nr_domains = 0;
+ static void free_domains(struct lv_read_state *state) {
+   if (state->domains) {
+     for (int i = 0; i < state->nr_domains; ++i)
+       virDomainFree(state->domains[i]);
+     sfree(state->domains);
+   }
+   state->domains = NULL;
+   state->nr_domains = 0;
  }
  
- static int
- add_domain (virDomainPtr dom)
- {
-     virDomainPtr *new_ptr;
-     int new_size = sizeof (domains[0]) * (nr_domains+1);
+ static int add_domain(struct lv_read_state *state, virDomainPtr dom) {
+   virDomainPtr *new_ptr;
+   int new_size = sizeof(state->domains[0]) * (state->nr_domains + 1);
  
-     if (domains)
-         new_ptr = realloc (domains, new_size);
-     else
-         new_ptr = malloc (new_size);
+   if (state->domains)
+     new_ptr = realloc(state->domains, new_size);
+   else
+     new_ptr = malloc(new_size);
  
-     if (new_ptr == NULL)
-         return -1;
+   if (new_ptr == NULL)
+     return -1;
  
-     domains = new_ptr;
-     domains[nr_domains] = dom;
-     return nr_domains++;
+   state->domains = new_ptr;
+   state->domains[state->nr_domains] = dom;
+   return state->nr_domains++;
  }
  
- static void
- free_block_devices (void)
- {
-     if (block_devices) {
-         for (int i = 0; i < nr_block_devices; ++i)
-             sfree (block_devices[i].path);
-         sfree (block_devices);
-     }
-     block_devices = NULL;
-     nr_block_devices = 0;
+ static void free_block_devices(struct lv_read_state *state) {
+   if (state->block_devices) {
+     for (int i = 0; i < state->nr_block_devices; ++i)
+       sfree(state->block_devices[i].path);
+     sfree(state->block_devices);
+   }
+   state->block_devices = NULL;
+   state->nr_block_devices = 0;
  }
  
- static int
- add_block_device (virDomainPtr dom, const char *path)
- {
-     struct block_device *new_ptr;
-     int new_size = sizeof (block_devices[0]) * (nr_block_devices+1);
-     char *path_copy;
+ static int add_block_device(struct lv_read_state *state, virDomainPtr dom,
+                             const char *path) {
+   struct block_device *new_ptr;
+   int new_size =
+       sizeof(state->block_devices[0]) * (state->nr_block_devices + 1);
+   char *path_copy;
  
-     path_copy = strdup (path);
-     if (!path_copy)
-         return -1;
+   path_copy = strdup(path);
+   if (!path_copy)
+     return -1;
  
-     if (block_devices)
-         new_ptr = realloc (block_devices, new_size);
-     else
-         new_ptr = malloc (new_size);
+   if (state->block_devices)
+     new_ptr = realloc(state->block_devices, new_size);
+   else
+     new_ptr = malloc(new_size);
  
-     if (new_ptr == NULL) {
-         sfree (path_copy);
-         return -1;
-     }
-     block_devices = new_ptr;
-     block_devices[nr_block_devices].dom = dom;
-     block_devices[nr_block_devices].path = path_copy;
-     return nr_block_devices++;
+   if (new_ptr == NULL) {
+     sfree(path_copy);
+     return -1;
+   }
+   state->block_devices = new_ptr;
+   state->block_devices[state->nr_block_devices].dom = dom;
+   state->block_devices[state->nr_block_devices].path = path_copy;
+   return state->nr_block_devices++;
  }
  
- static void
- free_interface_devices (void)
- {
-     if (interface_devices) {
-         for (int i = 0; i < nr_interface_devices; ++i) {
-             sfree (interface_devices[i].path);
-             sfree (interface_devices[i].address);
-             sfree (interface_devices[i].number);
-         }
-         sfree (interface_devices);
+ static void free_interface_devices(struct lv_read_state *state) {
+   if (state->interface_devices) {
+     for (int i = 0; i < state->nr_interface_devices; ++i) {
+       sfree(state->interface_devices[i].path);
+       sfree(state->interface_devices[i].address);
+       sfree(state->interface_devices[i].number);
      }
-     interface_devices = NULL;
-     nr_interface_devices = 0;
+     sfree(state->interface_devices);
+   }
+   state->interface_devices = NULL;
+   state->nr_interface_devices = 0;
  }
  
- static int
- add_interface_device (virDomainPtr dom, const char *path, const char *address, unsigned int number)
- {
-     struct interface_device *new_ptr;
-     int new_size = sizeof (interface_devices[0]) * (nr_interface_devices+1);
-     char *path_copy, *address_copy, number_string[15];
+ static int add_interface_device(struct lv_read_state *state, virDomainPtr dom,
+                                 const char *path, const char *address,
+                                 unsigned int number) {
+   struct interface_device *new_ptr;
+   int new_size =
+       sizeof(state->interface_devices[0]) * (state->nr_interface_devices + 1);
+   char *path_copy, *address_copy, number_string[15];
  
-     if ((path == NULL) || (address == NULL))
-         return EINVAL;
+   if ((path == NULL) || (address == NULL))
+     return EINVAL;
  
-     path_copy = strdup (path);
-     if (!path_copy) return -1;
+   path_copy = strdup(path);
+   if (!path_copy)
+     return -1;
  
-     address_copy = strdup (address);
-     if (!address_copy) {
-         sfree(path_copy);
-         return -1;
-     }
+   address_copy = strdup(address);
+   if (!address_copy) {
+     sfree(path_copy);
+     return -1;
+   }
  
-     snprintf(number_string, sizeof (number_string), "interface-%u", number);
+   snprintf(number_string, sizeof(number_string), "interface-%u", number);
  
-     if (interface_devices)
-         new_ptr = realloc (interface_devices, new_size);
-     else
-         new_ptr = malloc (new_size);
+   if (state->interface_devices)
+     new_ptr = realloc(state->interface_devices, new_size);
+   else
+     new_ptr = malloc(new_size);
  
-     if (new_ptr == NULL) {
-         sfree (path_copy);
-         sfree (address_copy);
-         return -1;
-     }
-     interface_devices = new_ptr;
-     interface_devices[nr_interface_devices].dom = dom;
-     interface_devices[nr_interface_devices].path = path_copy;
-     interface_devices[nr_interface_devices].address = address_copy;
-     interface_devices[nr_interface_devices].number = strdup(number_string);
-     return nr_interface_devices++;
+   if (new_ptr == NULL) {
+     sfree(path_copy);
+     sfree(address_copy);
+     return -1;
+   }
+   state->interface_devices = new_ptr;
+   state->interface_devices[state->nr_interface_devices].dom = dom;
+   state->interface_devices[state->nr_interface_devices].path = path_copy;
+   state->interface_devices[state->nr_interface_devices].address = address_copy;
+   state->interface_devices[state->nr_interface_devices].number =
+       strdup(number_string);
+   return state->nr_interface_devices++;
  }
  
- static int
- ignore_device_match (ignorelist_t *il, const char *domname, const char *devpath)
- {
-     char *name;
-     int n, r;
+ static int ignore_device_match(ignorelist_t *il, const char *domname,
+                                const char *devpath) {
+   char *name;
+   int n, r;
  
-     if ((domname == NULL) || (devpath == NULL))
-         return 0;
+   if ((domname == NULL) || (devpath == NULL))
+     return 0;
  
-     n = sizeof (char) * (strlen (domname) + strlen (devpath) + 2);
-     name = malloc (n);
-     if (name == NULL) {
-         ERROR (PLUGIN_NAME " plugin: malloc failed.");
-         return 0;
-     }
-     ssnprintf (name, n, "%s:%s", domname, devpath);
-     r = ignorelist_match (il, name);
-     sfree (name);
-     return r;
+   n = sizeof(char) * (strlen(domname) + strlen(devpath) + 2);
+   name = malloc(n);
+   if (name == NULL) {
+     ERROR(PLUGIN_NAME " plugin: malloc failed.");
+     return 0;
+   }
+   ssnprintf(name, n, "%s:%s", domname, devpath);
+   r = ignorelist_match(il, name);
+   sfree(name);
+   return r;
  }
  
- static int
- lv_shutdown (void)
- {
-     free_block_devices ();
-     free_interface_devices ();
-     free_domains ();
+ static int lv_shutdown(void) {
+   for (int i = 0; i < nr_instances; ++i) {
+     lv_fini_instance(i);
+   }
  
-     if (conn != NULL)
-         virConnectClose (conn);
-     conn = NULL;
+   lv_disconnect();
  
-     ignorelist_free (il_domains);
-     il_domains = NULL;
-     ignorelist_free (il_block_devices);
-     il_block_devices = NULL;
-     ignorelist_free (il_interface_devices);
-     il_interface_devices = NULL;
+   ignorelist_free(il_domains);
+   il_domains = NULL;
+   ignorelist_free(il_block_devices);
+   il_block_devices = NULL;
+   ignorelist_free(il_interface_devices);
+   il_interface_devices = NULL;
  
-     return 0;
+   return 0;
  }
  
- void
- module_register (void)
- {
-     plugin_register_config (PLUGIN_NAME,
-     lv_config,
-     config_keys, NR_CONFIG_KEYS);
-     plugin_register_init (PLUGIN_NAME, lv_init);
-     plugin_register_read (PLUGIN_NAME, lv_read);
-     plugin_register_shutdown (PLUGIN_NAME, lv_shutdown);
+ void module_register(void) {
+   plugin_register_config(PLUGIN_NAME, lv_config, config_keys, NR_CONFIG_KEYS);
+   plugin_register_init(PLUGIN_NAME, lv_init);
+   plugin_register_shutdown(PLUGIN_NAME, lv_shutdown);
  }
- /*
-  * vim: shiftwidth=4 tabstop=8 softtabstop=4 expandtab fdm=marker
-  */