X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fvirt.c;h=b8809fcbf68b72c29c50d22eca7be9af7f42c8df;hb=0192b4205d66b7a1c67657f7ed6a31c6c7673d74;hp=a828c456bfcccd2cc5133f0c57b715145a723306;hpb=c00630eab6161514c1044e8adb2895f179a535da;p=collectd.git diff --git a/src/virt.c b/src/virt.c index a828c456..b8809fcb 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", @@ -464,7 +466,7 @@ const char *domain_reasons[][DOMAIN_STATE_REASON_MAX_SIZE] = { do { \ status = _f(__VA_ARGS__); \ if (status != 0) \ - ERROR(PLUGIN_NAME ": Failed to get " _name); \ + ERROR(PLUGIN_NAME " plugin: Failed to get " _name); \ } while (0) /* Connection. */ @@ -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; } } @@ -770,7 +880,7 @@ static int init_notif(notification_t *notif, const virDomainPtr domain, value_list_t vl = VALUE_LIST_INIT; if (!notif) { - ERROR(PLUGIN_NAME ": init_notif: NULL pointer"); + ERROR(PLUGIN_NAME " plugin: init_notif: NULL pointer"); return -1; } @@ -849,7 +959,7 @@ static double cpu_ns_to_percent(unsigned int node_cpus, (time_diff_sec * node_cpus * NANOSEC_IN_SEC); } - DEBUG(PLUGIN_NAME ": node_cpus=%u cpu_time_old=%" PRIu64 + DEBUG(PLUGIN_NAME " plugin: node_cpus=%u cpu_time_old=%" PRIu64 " cpu_time_new=%" PRIu64 "cpu_time_diff=%" PRIu64 " time_diff_sec=%f percent=%f", node_cpus, (uint64_t)cpu_time_old, (uint64_t)cpu_time_new, @@ -944,7 +1054,8 @@ static unsigned int parse_ex_stats_flags(char **exstats, int numexstats) { } if (ex_stats_table[j + 1].name == NULL) { - ERROR(PLUGIN_NAME ": Unmatched ExtraStats option: %s", exstats[i]); + ERROR(PLUGIN_NAME " plugin: Unmatched ExtraStats option: %s", + exstats[i]); } } } @@ -953,7 +1064,7 @@ static unsigned int parse_ex_stats_flags(char **exstats, int numexstats) { static void domain_state_submit_notif(virDomainPtr dom, int state, int reason) { if ((state < 0) || ((size_t)state >= STATIC_ARRAY_SIZE(domain_states))) { - ERROR(PLUGIN_NAME ": Array index out of bounds: state=%d", state); + ERROR(PLUGIN_NAME " plugin: Array index out of bounds: state=%d", state); return; } @@ -962,7 +1073,7 @@ static void domain_state_submit_notif(virDomainPtr dom, int state, int reason) { #ifdef HAVE_DOM_REASON if ((reason < 0) || ((size_t)reason >= STATIC_ARRAY_SIZE(domain_reasons[0]))) { - ERROR(PLUGIN_NAME ": Array index out of bounds: reason=%d", reason); + ERROR(PLUGIN_NAME " plugin: Array index out of bounds: reason=%d", reason); return; } @@ -971,8 +1082,8 @@ static void domain_state_submit_notif(virDomainPtr dom, int state, int reason) { * have different number of reasons. We need to check if reason was * successfully parsed */ if (!reason_str) { - ERROR(PLUGIN_NAME ": Invalid reason (%d) for domain state: %s", reason, - state_str); + ERROR(PLUGIN_NAME " plugin: Invalid reason (%d) for domain state: %s", + reason, state_str); return; } #else @@ -1001,7 +1112,7 @@ static void domain_state_submit_notif(virDomainPtr dom, int state, int reason) { severity = NOTIF_FAILURE; break; default: - ERROR(PLUGIN_NAME ": Unrecognized domain state (%d)", state); + ERROR(PLUGIN_NAME " plugin: Unrecognized domain state (%d)", state); return; } submit_notif(dom, severity, msg, "domain_state", NULL); @@ -1082,18 +1193,37 @@ static int lv_config(const char *key, const char *value) { return 0; } - if (strcasecmp(key, "HostnameFormat") == 0) { - char *value_copy; - char *fields[HF_MAX_FIELDS]; - int n; + 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; + } - value_copy = strdup(value); + 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) { ERROR(PLUGIN_NAME " plugin: strdup failed."); return -1; } - n = strsplit(value_copy, fields, HF_MAX_FIELDS); + char *fields[HF_MAX_FIELDS]; + int n = strsplit(value_copy, fields, HF_MAX_FIELDS); if (n < 1) { sfree(value_copy); ERROR(PLUGIN_NAME " plugin: HostnameFormat: no fields"); @@ -1107,6 +1237,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]); @@ -1123,17 +1255,14 @@ static int lv_config(const char *key, const char *value) { } if (strcasecmp(key, "PluginInstanceFormat") == 0) { - char *value_copy; - char *fields[PLGINST_MAX_FIELDS]; - int n; - - value_copy = strdup(value); + char *value_copy = strdup(value); if (value_copy == NULL) { ERROR(PLUGIN_NAME " plugin: strdup failed."); return -1; } - n = strsplit(value_copy, fields, PLGINST_MAX_FIELDS); + char *fields[PLGINST_MAX_FIELDS]; + int n = strsplit(value_copy, fields, PLGINST_MAX_FIELDS); if (n < 1) { sfree(value_copy); ERROR(PLUGIN_NAME " plugin: PluginInstanceFormat: no fields"); @@ -1148,6 +1277,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]); @@ -1249,7 +1380,7 @@ static int lv_connect(void) { } int status = virNodeGetInfo(conn, &nodeinfo); if (status != 0) { - ERROR(PLUGIN_NAME ": virNodeGetInfo failed"); + ERROR(PLUGIN_NAME " plugin: virNodeGetInfo failed"); return -1; } } @@ -1696,7 +1827,7 @@ static int get_job_stats(virDomainPtr domain) { static int get_domain_metrics(domain_t *domain) { if (!domain || !domain->ptr) { - ERROR(PLUGIN_NAME "plugin: get_domain_metrics: NULL pointer"); + ERROR(PLUGIN_NAME " plugin: get_domain_metrics: NULL pointer"); return -1; } @@ -1871,7 +2002,7 @@ static int virt_notif_thread_init(virt_notif_thread_t *thread_data) { assert(thread_data != NULL); ret = pthread_mutex_init(&thread_data->active_mutex, NULL); if (ret != 0) { - ERROR(PLUGIN_NAME ": Failed to initialize mutex, err %u", ret); + ERROR(PLUGIN_NAME " plugin: Failed to initialize mutex, err %u", ret); return ret; } @@ -2071,7 +2202,7 @@ static int lv_read(user_data_t *ud) { #endif if (status != 0) - ERROR(PLUGIN_NAME " failed to get metrics for domain=%s", + ERROR(PLUGIN_NAME " plugin: failed to get metrics for domain=%s", virDomainGetName(dom->ptr)); } @@ -2080,7 +2211,7 @@ static int lv_read(user_data_t *ud) { int status = get_block_stats(&state->block_devices[i]); if (status != 0) ERROR(PLUGIN_NAME - " failed to get stats for block device (%s) in domain %s", + " plugin: failed to get stats for block device (%s) in domain %s", state->block_devices[i].path, virDomainGetName(state->block_devices[i].dom)); } @@ -2089,10 +2220,11 @@ static int lv_read(user_data_t *ud) { for (int i = 0; i < state->nr_interface_devices; ++i) { int status = get_if_dev_stats(&state->interface_devices[i]); if (status != 0) - ERROR(PLUGIN_NAME - " failed to get interface stats for device (%s) in domain %s", - state->interface_devices[i].path, - virDomainGetName(state->interface_devices[i].dom)); + ERROR( + PLUGIN_NAME + " plugin: failed to get interface stats for device (%s) in domain %s", + state->interface_devices[i].path, + virDomainGetName(state->interface_devices[i].dom)); } return 0; @@ -2516,14 +2648,10 @@ static void free_domains(struct lv_read_state *state) { 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); - if (state->domains) - new_ptr = realloc(state->domains, new_size); - else - new_ptr = malloc(new_size); + int new_size = sizeof(state->domains[0]) * (state->nr_domains + 1); + domain_t *new_ptr = realloc(state->domains, new_size); if (new_ptr == NULL) return -1; @@ -2548,20 +2676,15 @@ static void free_block_devices(struct lv_read_state *state) { 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); + char *path_copy = strdup(path); if (!path_copy) return -1; - if (state->block_devices) - new_ptr = realloc(state->block_devices, new_size); - else - new_ptr = malloc(new_size); + int new_size = + sizeof(state->block_devices[0]) * (state->nr_block_devices + 1); + struct block_device *new_ptr = realloc(state->block_devices, new_size); if (new_ptr == NULL) { sfree(path_copy); return -1; @@ -2588,42 +2711,46 @@ static void free_interface_devices(struct lv_read_state *state) { 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[21]; if ((path == NULL) || (address == NULL)) return EINVAL; - path_copy = strdup(path); + char *path_copy = strdup(path); if (!path_copy) return -1; - address_copy = strdup(address); + char *address_copy = strdup(address); if (!address_copy) { sfree(path_copy); return -1; } + char number_string[21]; snprintf(number_string, sizeof(number_string), "interface-%u", number); + char *number_copy = strdup(number_string); + if (!number_copy) { + sfree(path_copy); + sfree(address_copy); + return -1; + } - if (state->interface_devices) - new_ptr = realloc(state->interface_devices, new_size); - else - new_ptr = malloc(new_size); + int new_size = + sizeof(state->interface_devices[0]) * (state->nr_interface_devices + 1); + struct interface_device *new_ptr = + realloc(state->interface_devices, new_size); if (new_ptr == NULL) { sfree(path_copy); sfree(address_copy); + sfree(number_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); + state->interface_devices[state->nr_interface_devices].number = number_copy; return state->nr_interface_devices++; }