#define NR_INSTANCES_DEFAULT 1
#define NR_INSTANCES_MAX 128
-static size_t nr_instances = NR_INSTANCES_DEFAULT;
+static int nr_instances = NR_INSTANCES_DEFAULT;
static struct lv_user_data lv_read_user_data[NR_INSTANCES_MAX];
/* HostnameFormat. */
if (strcasecmp(key, "Instances") == 0) {
char *eptr = NULL;
- long val = strtol(value, &eptr, 10);
- if (eptr == NULL || *eptr != '\0')
+ double val = strtod(value, &eptr);
+
+ if (*eptr != '\0') {
+ ERROR(PLUGIN_NAME " plugin: Invalid value for Instances = '%s'", value);
return 1;
+ }
if (val <= 0) {
ERROR(PLUGIN_NAME " plugin: Instances <= 0 makes no sense.");
return 1;
}
if (val > NR_INSTANCES_MAX) {
- ERROR(PLUGIN_NAME " plugin: Instances=%li > NR_INSTANCES_MAX=%i"
+ ERROR(PLUGIN_NAME " plugin: Instances=%f > NR_INSTANCES_MAX=%i"
" use a lower setting or recompile the plugin.",
val, NR_INSTANCES_MAX);
return 1;
}
- nr_instances = (size_t)val;
+
+ nr_instances = (int)val;
+ DEBUG(PLUGIN_NAME " plugin: configured %i instances", nr_instances);
return 0;
}
return -1;
}
-static int lv_read(user_data_t *ud) {
- time_t t;
- struct lv_read_instance *inst = ud->data;
- struct lv_read_state *state = &inst->read_state;
- if (!inst) {
- ERROR(PLUGIN_NAME " plugin: NULL userdata");
- return -1;
- }
-
- if (inst->id == 0 && conn == NULL) {
+static int lv_connect(void) {
+ if (conn == NULL) {
/* `conn_string == NULL' is acceptable. */
conn = virConnectOpenReadOnly(conn_string);
if (conn == NULL) {
}
c_release(LOG_NOTICE, &conn_complain,
PLUGIN_NAME " plugin: Connection established.");
+ return 0;
+}
+
+static void lv_disconnect(void) {
+ if (conn != NULL)
+ virConnectClose(conn);
+ conn = NULL;
+ WARNING(PLUGIN_NAME " plugin: closed connection to libvirt");
+}
+
+static int lv_read(user_data_t *ud) {
+ time_t t;
+ struct lv_read_instance *inst = NULL;
+ struct lv_read_state *state = NULL;
+
+ if (ud->data == NULL) {
+ ERROR(PLUGIN_NAME " plugin: NULL userdata");
+ return -1;
+ }
+
+ inst = ud->data;
+ state = &inst->read_state;
+
+ if (inst->id == 0) {
+ if (lv_connect() < 0)
+ return -1;
+ }
time(&t);
if ((last_refresh == (time_t)0) ||
((interval > 0) && ((last_refresh + interval) <= t))) {
if (refresh_lists(inst) != 0) {
- if (conn != NULL)
- virConnectClose(conn);
- conn = NULL;
+ if (inst->id == 0)
+ lv_disconnect();
return -1;
}
last_refresh = t;
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;
+ struct lv_read_instance *inst = &(lv_ud->inst);
memset(lv_ud, 0, sizeof(*lv_ud));
ssnprintf(inst->tag, sizeof(inst->tag), "%s-%zu", PLUGIN_NAME, i);
inst->id = i;
- user_data_t *ud = &lv_ud->ud;
+ user_data_t *ud = &(lv_ud->ud);
ud->data = inst;
ud->free_func = NULL;
- INFO(PLUGIN_NAME "plugin: reader %s initialized", inst->tag);
+ INFO(PLUGIN_NAME " plugin: reader %s initialized", inst->tag);
return plugin_register_complex_read(NULL, inst->tag, callback, 0, ud);
}
+static void lv_clean_read_state(struct lv_read_state *state) {
+ free_block_devices(state);
+ free_interface_devices(state);
+ free_domains(state);
+}
+
+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);
+
+ lv_clean_read_state(state);
+ INFO(PLUGIN_NAME " plugin: reader %s finalized", inst->tag);
+}
+
static int lv_init(void) {
if (virInitialize() != 0)
return -1;
- for (size_t i = 0; i < nr_instances; ++i)
+ 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 err = -1;
+ int ret = -1;
+ int err;
err = xmlXPathRegisterNs(xpath_ctx,
(const xmlChar *)METADATA_VM_PARTITION_PREFIX,
* from now on there is no real error, it's ok if a domain
* doesn't have the metadata partition tag.
*/
- err = 0;
-
+ 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",
}
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 err;
+ return ret;
}
static int is_known_tag(const char *dom_tag) {
- for (size_t i = 0; i < nr_instances; ++i)
+ for (int i = 0; i < nr_instances; ++i)
if (!strcmp(dom_tag, lv_read_user_data[i].inst.tag))
return 1;
return 0;
/* 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: adopted domain %s "
+ DEBUG(PLUGIN_NAME " plugin#%s: refreshing domain %s "
"with unknown tag '%s'",
inst->tag, dom_name, dom_tag);
return 1;
}
static int refresh_lists(struct lv_read_instance *inst) {
+ struct lv_read_state *state = &inst->read_state;
int n;
n = virConnectNumOfDomains(conn);
return -1;
}
+ lv_clean_read_state(state);
+
if (n > 0) {
- struct lv_read_state *state = &inst->read_state;
int *domids;
/* Get list of domains. */
return -1;
}
- free_block_devices(state);
- free_interface_devices(state);
- free_domains(state);
-
/* Fetch each domain and add it to the list, unless ignore. */
for (int i = 0; i < n; ++i) {
virDomainPtr dom = NULL;
xmlDocPtr xml_doc = NULL;
xmlXPathContextPtr xpath_ctx = NULL;
xmlXPathObjectPtr xpath_obj = NULL;
- char tag[PARTITION_TAG_MAX_LEN];
+ char tag[PARTITION_TAG_MAX_LEN] = {'\0'};
dom = virDomainLookupByID(conn, domids[i]);
if (dom == NULL) {
}
/* Block devices. */
- char *bd_xmlpath = "/domain/devices/disk/target[@dev]";
+ const 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);
+ xpath_obj = xmlXPathEval((const xmlChar *)bd_xmlpath, xpath_ctx);
if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
xpath_obj->nodesetval == NULL)
sfree(domids);
}
+ 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 int lv_shutdown(void) {
- for (size_t i = 0; i < nr_instances; ++i) {
- struct lv_read_state *state = &(lv_read_user_data[i].inst.read_state);
- free_block_devices(state);
- free_interface_devices(state);
- free_domains(state);
+ 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;
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_complex_read(NULL, PLUGIN_NAME, lv_read, 0, NULL);
plugin_register_shutdown(PLUGIN_NAME, lv_shutdown);
}
-
-/*
- * vim: shiftwidth=4 tabstop=8 softtabstop=4 expandtab fdm=marker
- */