X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fvirt.c;h=bdb6445caf89b5f52b2c58b7dbd7b70641bd2541;hb=d0b5df47bb6fc6ae8a5ff9ed5a43349ec84721e2;hp=c6ac5905f7b0f5b5c45441c5edaa6d97542acfb0;hpb=3e25f407d1221cc78e8bc8ec3be96d68997228a2;p=collectd.git diff --git a/src/virt.c b/src/virt.c index c6ac5905..bdb6445c 100644 --- a/src/virt.c +++ b/src/virt.c @@ -129,6 +129,8 @@ static const char *config_keys[] = {"Connection", "IgnoreSelected", "HostnameFormat", + "HostnameMetadataNS", + "HostnameMetadataXPath", "InterfaceFormat", "PluginInstanceFormat", @@ -557,20 +559,29 @@ static int nr_instances = NR_INSTANCES_DEFAULT; static struct lv_user_data lv_read_user_data[NR_INSTANCES_MAX]; /* HostnameFormat. */ -#define HF_MAX_FIELDS 3 +#define HF_MAX_FIELDS 4 -enum hf_field { hf_none = 0, hf_hostname, hf_name, hf_uuid }; +enum hf_field { hf_none = 0, hf_hostname, hf_name, hf_uuid, hf_metadata }; static enum hf_field hostname_format[HF_MAX_FIELDS] = {hf_name}; /* PluginInstanceFormat */ -#define PLGINST_MAX_FIELDS 2 +#define PLGINST_MAX_FIELDS 3 -enum plginst_field { plginst_none = 0, plginst_name, plginst_uuid }; +enum plginst_field { + plginst_none = 0, + plginst_name, + plginst_uuid, + plginst_metadata +}; static enum plginst_field plugin_instance_format[PLGINST_MAX_FIELDS] = { plginst_none}; +/* HostnameMetadataNS && HostnameMetadataXPath */ +static char *hm_xpath; +static char *hm_ns; + /* BlockDeviceFormat */ enum bd_field { target, source }; @@ -705,6 +716,95 @@ static int get_block_info(struct lv_block_info *binfo, ERROR(PLUGIN_NAME " plugin: %s failed: %s", (s), err->message); \ } while (0) +char *metadata_get_hostname(virDomainPtr dom) { + const char *xpath_str = NULL; + if (hm_xpath == NULL) + xpath_str = "/instance/name/text()"; + else + xpath_str = hm_xpath; + + const char *namespace = NULL; + if (hm_ns == NULL) { + namespace = "http://openstack.org/xmlns/libvirt/nova/1.0"; + } else { + namespace = hm_ns; + } + + char *metadata_str = virDomainGetMetadata( + dom, VIR_DOMAIN_METADATA_ELEMENT, namespace, VIR_DOMAIN_AFFECT_CURRENT); + if (metadata_str == NULL) { + return NULL; + } + + char *hostname = NULL; + xmlXPathContextPtr xpath_ctx = NULL; + xmlXPathObjectPtr xpath_obj = NULL; + xmlNodePtr xml_node = NULL; + + xmlDocPtr xml_doc = + xmlReadDoc((xmlChar *)metadata_str, NULL, NULL, XML_PARSE_NONET); + if (xml_doc == NULL) { + ERROR(PLUGIN_NAME " plugin: xmlReadDoc failed to read metadata"); + goto metadata_end; + } + + xpath_ctx = xmlXPathNewContext(xml_doc); + if (xpath_ctx == NULL) { + ERROR(PLUGIN_NAME " plugin: xmlXPathNewContext(%s) failed for metadata", + metadata_str); + goto metadata_end; + } + xpath_obj = xmlXPathEval((xmlChar *)xpath_str, xpath_ctx); + if (xpath_obj == NULL) { + ERROR(PLUGIN_NAME " plugin: xmlXPathEval(%s) failed for metadata", + xpath_str); + goto metadata_end; + } + + if (xpath_obj->type != XPATH_NODESET) { + ERROR(PLUGIN_NAME " plugin: xmlXPathEval(%s) unexpected return type %d " + "(wanted %d) for metadata", + xpath_str, xpath_obj->type, XPATH_NODESET); + goto metadata_end; + } + + // TODO(sileht): We can support || operator by looping on nodes here + if (xpath_obj->nodesetval == NULL || xpath_obj->nodesetval->nodeNr != 1) { + WARNING(PLUGIN_NAME " plugin: xmlXPathEval(%s) return nodeset size=%i " + "expected=1 for metadata", + xpath_str, + (xpath_obj->nodesetval == NULL) ? 0 + : xpath_obj->nodesetval->nodeNr); + goto metadata_end; + } + + xml_node = xpath_obj->nodesetval->nodeTab[0]; + if (xml_node->type == XML_TEXT_NODE) { + hostname = strdup((const char *)xml_node->content); + } else if (xml_node->type == XML_ATTRIBUTE_NODE) { + hostname = strdup((const char *)xml_node->children->content); + } else { + ERROR(PLUGIN_NAME " plugin: xmlXPathEval(%s) unsupported node type %d", + xpath_str, xml_node->type); + goto metadata_end; + } + + if (hostname == NULL) { + ERROR(PLUGIN_NAME " plugin: strdup(%s) hostname failed", xpath_str); + goto metadata_end; + } + +metadata_end: + if (xpath_obj) + xmlXPathFreeObject(xpath_obj); + if (xpath_ctx) + xmlXPathFreeContext(xpath_ctx); + if (xml_doc) + xmlFreeDoc(xml_doc); + sfree(metadata_str); + return hostname; +} + static void init_value_list(value_list_t *vl, virDomainPtr dom) { const char *name; char uuid[VIR_UUID_STRING_BUFLEN]; @@ -736,6 +836,11 @@ static void init_value_list(value_list_t *vl, virDomainPtr dom) { if (virDomainGetUUIDString(dom, uuid) == 0) SSTRNCAT(vl->host, uuid, sizeof(vl->host)); break; + case hf_metadata: + name = metadata_get_hostname(dom); + if (name) + SSTRNCAT(vl->host, name, sizeof(vl->host)); + break; } } @@ -759,6 +864,11 @@ static void init_value_list(value_list_t *vl, virDomainPtr dom) { if (virDomainGetUUIDString(dom, uuid) == 0) SSTRNCAT(vl->plugin_instance, uuid, sizeof(vl->plugin_instance)); break; + case plginst_metadata: + name = metadata_get_hostname(dom); + if (name) + SSTRNCAT(vl->plugin_instance, name, sizeof(vl->plugin_instance)); + break; } } @@ -1008,10 +1118,7 @@ static void domain_state_submit_notif(virDomainPtr dom, int state, int reason) { submit_notif(dom, severity, msg, "domain_state", NULL); } -static int lv_config(const char *key, const char *value) { - if (virInitialize() != 0) - return 1; - +static int lv_init_ignorelists() { if (il_domains == NULL) il_domains = ignorelist_create(1); if (il_block_devices == NULL) @@ -1019,6 +1126,19 @@ static int lv_config(const char *key, const char *value) { if (il_interface_devices == NULL) il_interface_devices = ignorelist_create(1); + if (!il_domains || !il_block_devices || !il_interface_devices) + return 1; + + return 0; +} + +static int lv_config(const char *key, const char *value) { + if (virInitialize() != 0) + return 1; + + if (lv_init_ignorelists() != 0) + return 1; + if (strcasecmp(key, "Connection") == 0) { char *tmp = strdup(value); if (tmp == NULL) { @@ -1083,6 +1203,28 @@ static int lv_config(const char *key, const char *value) { return 0; } + if (strcasecmp(key, "HostnameMetadataNS") == 0) { + char *tmp = strdup(value); + if (tmp == NULL) { + ERROR(PLUGIN_NAME " plugin: HostnameMetadataNS strdup failed."); + return 1; + } + sfree(hm_ns); + hm_ns = tmp; + return 0; + } + + if (strcasecmp(key, "HostnameMetadataXPath") == 0) { + char *tmp = strdup(value); + if (tmp == NULL) { + ERROR(PLUGIN_NAME " plugin: HostnameMetadataXPath strdup failed."); + return 1; + } + sfree(hm_xpath); + hm_xpath = tmp; + return 0; + } + if (strcasecmp(key, "HostnameFormat") == 0) { char *value_copy = strdup(value); if (value_copy == NULL) { @@ -1105,6 +1247,8 @@ static int lv_config(const char *key, const char *value) { hostname_format[i] = hf_name; else if (strcasecmp(fields[i], "uuid") == 0) hostname_format[i] = hf_uuid; + else if (strcasecmp(fields[i], "metadata") == 0) + hostname_format[i] = hf_metadata; else { ERROR(PLUGIN_NAME " plugin: unknown HostnameFormat field: %s", fields[i]); @@ -1143,6 +1287,8 @@ static int lv_config(const char *key, const char *value) { plugin_instance_format[i] = plginst_name; else if (strcasecmp(fields[i], "uuid") == 0) plugin_instance_format[i] = plginst_uuid; + else if (strcasecmp(fields[i], "metadata") == 0) + plugin_instance_format[i] = plginst_metadata; else { ERROR(PLUGIN_NAME " plugin: unknown PluginInstanceFormat field: %s", fields[i]); @@ -2131,6 +2277,10 @@ static int lv_init(void) { if (virInitialize() != 0) return -1; + /* Init ignorelists if there was no explicit configuration */ + if (lv_init_ignorelists() != 0) + return -1; + /* event implementation must be registered before connection is opened */ if (!persistent_notification) if (register_event_impl() != 0) @@ -2311,14 +2461,6 @@ static int refresh_lists(struct lv_read_instance *inst) { /* 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]; @@ -2343,16 +2485,17 @@ static int refresh_lists(struct lv_read_instance *inst) { */ ERROR(PLUGIN_NAME " plugin: malloc failed."); virDomainFree(dom); - goto cont; + continue; } - name = virDomainGetName(dom); - if (name == NULL) { + const char *domname = virDomainGetName(dom); + if (domname == NULL) { VIRT_ERROR(conn, "virDomainGetName"); - goto cont; + continue; } - status = virDomainGetInfo(dom, &info); + virDomainInfo info; + int status = virDomainGetInfo(dom, &info); if (status != 0) { ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.", status); @@ -2364,11 +2507,15 @@ static int refresh_lists(struct lv_read_instance *inst) { continue; } - if (il_domains && ignorelist_match(il_domains, name) != 0) - goto cont; + if (ignorelist_match(il_domains, domname) != 0) + continue; /* Get a list of devices for this domain. */ - xml = virDomainGetXMLDesc(dom, 0); + xmlDocPtr xml_doc = NULL; + xmlXPathContextPtr xpath_ctx = NULL; + xmlXPathObjectPtr xpath_obj = NULL; + + char *xml = virDomainGetXMLDesc(dom, 0); if (!xml) { VIRT_ERROR(conn, "virDomainGetXMLDesc"); goto cont; @@ -2383,12 +2530,13 @@ static int refresh_lists(struct lv_read_instance *inst) { xpath_ctx = xmlXPathNewContext(xml_doc); - if (lv_domain_get_tag(xpath_ctx, name, tag) < 0) { + char tag[PARTITION_TAG_MAX_LEN] = {'\0'}; + if (lv_domain_get_tag(xpath_ctx, domname, tag) < 0) { ERROR(PLUGIN_NAME " plugin: lv_domain_get_tag failed."); goto cont; } - if (!lv_instance_include_domain(inst, name, tag)) + if (!lv_instance_include_domain(inst, domname, tag)) goto cont; /* Block devices. */ @@ -2402,24 +2550,18 @@ static int refresh_lists(struct lv_read_instance *inst) { goto cont; for (int j = 0; j < xpath_obj->nodesetval->nodeNr; ++j) { - xmlNodePtr node; - char *path = NULL; - - node = xpath_obj->nodesetval->nodeTab[j]; + xmlNodePtr node = xpath_obj->nodesetval->nodeTab[j]; if (!node) continue; - path = (char *)xmlGetProp(node, (xmlChar *)"dev"); + + char *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 (ignore_device_match(il_block_devices, domname, path) == 0) + add_block_device(state, dom, path); - add_block_device(state, dom, path); - cont2: - if (path) - xmlFree(path); + xmlFree(path); } xmlXPathFreeObject(xpath_obj); @@ -2435,9 +2577,8 @@ static int refresh_lists(struct lv_read_instance *inst) { for (int j = 0; j < xml_interfaces->nodeNr; ++j) { char *path = NULL; char *address = NULL; - xmlNodePtr xml_interface; - xml_interface = xml_interfaces->nodeTab[j]; + xmlNodePtr xml_interface = xml_interfaces->nodeTab[j]; if (!xml_interface) continue; @@ -2457,13 +2598,11 @@ static int refresh_lists(struct lv_read_instance *inst) { } } - if (il_interface_devices && - (ignore_device_match(il_interface_devices, name, path) != 0 || - ignore_device_match(il_interface_devices, name, address) != 0)) - goto cont3; + if ((ignore_device_match(il_interface_devices, domname, path) == 0 && + ignore_device_match(il_interface_devices, domname, address) == 0)) { + add_interface_device(state, dom, path, address, j + 1); + } - add_interface_device(state, dom, path, address, j + 1); - cont3: if (path) xmlFree(path); if (address) @@ -2620,20 +2759,17 @@ static int add_interface_device(struct lv_read_state *state, virDomainPtr dom, static int ignore_device_match(ignorelist_t *il, const char *domname, const char *devpath) { - char *name; - int r; - if ((domname == NULL) || (devpath == NULL)) return 0; size_t n = strlen(domname) + strlen(devpath) + 2; - name = malloc(n); + char *name = malloc(n); if (name == NULL) { ERROR(PLUGIN_NAME " plugin: malloc failed."); return 0; } snprintf(name, n, "%s:%s", domname, devpath); - r = ignorelist_match(il, name); + int r = ignorelist_match(il, name); sfree(name); return r; }