X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=data%2Fsrc%2Fstatus.c;h=082053340869ce3d7fd4a799453b8abf465d9636;hb=8b84a18a4fd8c1f8086a7538cae251dac7ee9d57;hp=6dddf105c3a72fc241eb67a985bea9ff7b7e8637;hpb=89fde9ac5bb491484322964016fe247cf11950a8;p=pve-cluster.git diff --git a/data/src/status.c b/data/src/status.c index 6dddf10..0820533 100644 --- a/data/src/status.c +++ b/data/src/status.c @@ -33,9 +33,11 @@ #include #include #include +#include #include "cfs-utils.h" #include "status.h" +#include "memdb.h" #include "logger.h" #define KVSTORE_CPG_GROUP_NAME "pve_kvstore_v1" @@ -75,14 +77,32 @@ typedef struct { } memdb_change_t; static memdb_change_t memdb_change_array[] = { - { .path = "cluster.conf" }, - { .path = "cluster.conf.new" }, + { .path = "corosync.conf" }, + { .path = "corosync.conf.new" }, { .path = "storage.cfg" }, { .path = "user.cfg" }, { .path = "domains.cfg" }, { .path = "priv/shadow.cfg" }, + { .path = "priv/acme/plugins.cfg" }, + { .path = "priv/tfa.cfg" }, + { .path = "priv/token.cfg" }, { .path = "datacenter.cfg" }, { .path = "vzdump.cron" }, + { .path = "ha/crm_commands" }, + { .path = "ha/manager_status" }, + { .path = "ha/resources.cfg" }, + { .path = "ha/groups.cfg" }, + { .path = "ha/fence.cfg" }, + { .path = "status.cfg" }, + { .path = "replication.cfg" }, + { .path = "ceph.conf" }, + { .path = "sdn/vnets.cfg" }, + { .path = "sdn/vnets.cfg.new" }, + { .path = "sdn/zones.cfg" }, + { .path = "sdn/zones.cfg.new" }, + { .path = "sdn/controllers.cfg" }, + { .path = "sdn/controllers.cfg.new" }, + { .path = "virtual-guest/cpu-models.conf" }, }; static GMutex mutex; @@ -150,6 +170,42 @@ static void vminfo_free(vminfo_t *vminfo) g_free(vminfo); } +static const char *vminfo_type_to_string(vminfo_t *vminfo) +{ + if (vminfo->vmtype == VMTYPE_QEMU) { + return "qemu"; + } else if (vminfo->vmtype == VMTYPE_OPENVZ) { + return "openvz"; + } else if (vminfo->vmtype == VMTYPE_LXC) { + return "lxc"; + } else { + return "unknown"; + } +} + +static const char *vminfo_type_to_path_type(vminfo_t *vminfo) +{ + if (vminfo->vmtype == VMTYPE_QEMU) { + return "qemu-server"; // special case.. + } else { + return vminfo_type_to_string(vminfo); + } +} + +int vminfo_to_path(vminfo_t *vminfo, GString *path) +{ + g_return_val_if_fail(vminfo != NULL, -1); + g_return_val_if_fail(path != NULL, -1); + + if (!vminfo->nodename) + return 0; + + const char *type = vminfo_type_to_path_type(vminfo); + g_string_printf(path, "/nodes/%s/%s/%u.conf", vminfo->nodename, type, vminfo->vmid); + + return 1; +} + void cfs_clnode_destroy( cfs_clnode_t *clnode) { @@ -362,7 +418,8 @@ cfs_cluster_log(clog_entry_t *entry) iov[0].iov_base = (char *)entry; iov[0].iov_len = clog_entry_size(entry); - dfsm_send_message(cfs_status.kvstore, KVSTORE_MESSAGE_LOG, iov, 1); + if (dfsm_is_initialized(cfs_status.kvstore)) + dfsm_send_message(cfs_status.kvstore, KVSTORE_MESSAGE_LOG, iov, 1); } } @@ -577,7 +634,8 @@ vmlist_hash_insert_vm( g_return_val_if_fail(vmlist != NULL, FALSE); g_return_val_if_fail(nodename != NULL, FALSE); g_return_val_if_fail(vmid != 0, FALSE); - g_return_val_if_fail(vmtype == VMTYPE_QEMU || vmtype == VMTYPE_OPENVZ, FALSE); + g_return_val_if_fail(vmtype == VMTYPE_QEMU || vmtype == VMTYPE_OPENVZ || + vmtype == VMTYPE_LXC, FALSE); if (!replace && g_hash_table_lookup(vmlist, &vmid)) { cfs_critical("detected duplicate VMID %d", vmid); @@ -606,7 +664,8 @@ vmlist_register_vm( g_return_if_fail(cfs_status.vmlist != NULL); g_return_if_fail(nodename != NULL); g_return_if_fail(vmid != 0); - g_return_if_fail(vmtype == VMTYPE_QEMU || vmtype == VMTYPE_OPENVZ); + g_return_if_fail(vmtype == VMTYPE_QEMU || vmtype == VMTYPE_OPENVZ || + vmtype == VMTYPE_LXC); cfs_debug("vmlist_register_vm: %s/%u %d", nodename, vmid, vmtype); @@ -720,14 +779,7 @@ cfs_create_vmlist_msg(GString *str) int first = 1; while (g_hash_table_iter_next (&iter, &key, &value)) { vminfo_t *vminfo = (vminfo_t *)value; - char *type; - if (vminfo->vmtype == VMTYPE_QEMU) { - type = "qemu"; - } else if (vminfo->vmtype == VMTYPE_OPENVZ) { - type = "openvz"; - } else { - type = "unknown"; - } + const char *type = vminfo_type_to_string(vminfo); if (!first) g_string_append_printf(str, ",\n"); @@ -746,6 +798,171 @@ cfs_create_vmlist_msg(GString *str) return 0; } +// checks the conf for a line starting with '$prop:' and returns the value +// afterwards, whitout initial whitespace(s), we only deal with the format +// restricion imposed by our perl VM config parser, main reference is +// PVE::QemuServer::parse_vm_config this allows to be very fast and still +// relatively simple +// main restrictions used for our advantage is the properties match reges: +// ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) from parse_vm_config +// currently we only look at the current configuration in place, i.e., *no* +// snapshort and *no* pending changes +static char * +_get_property_value(char *conf, int conf_size, const char *prop, int prop_len) +{ + const char *const conf_end = conf + conf_size; + char *line = conf; + size_t remaining_size; + + char *next_newline = memchr(conf, '\n', conf_size); + if (next_newline == NULL) { + return NULL; // valid property lines end with \n, but none in the config + } + *next_newline = '\0'; + + while (line != NULL) { + if (!line[0]) goto next; + + // snapshot or pending section start, but nothing found yet -> not found + if (line[0] == '[') return NULL; + // properties start with /^[a-z]/, so continue early if not + if (line[0] < 'a' || line[0] > 'z') goto next; + + int line_len = strlen(line); + if (line_len <= prop_len + 1) goto next; + + if (line[prop_len] == ':' && memcmp(line, prop, prop_len) == 0) { // found + char *v_start = &line[prop_len + 1]; + + // drop initial value whitespaces here already + while (*v_start && isspace(*v_start)) v_start++; + + if (!*v_start) return NULL; + + char *v_end = &line[line_len - 1]; + while (v_end > v_start && isspace(*v_end)) v_end--; + v_end[1] = '\0'; + + return v_start; + } +next: + line = next_newline + 1; + remaining_size = conf_end - line; + if (remaining_size <= prop_len) { + return NULL; + } + next_newline = memchr(line, '\n', remaining_size); + if (next_newline == NULL) { + return NULL; // valid property lines end with \n, but none in the config + } + *next_newline = '\0'; + } + + return NULL; // not found +} + +static void +_g_str_append_kv_jsonescaped(GString *str, const char *k, const char *v) +{ + g_string_append_printf(str, "\"%s\": \"", k); + + for (; *v; v++) { + if (*v == '\\' || *v == '"') { + g_string_append_c(str, '\\'); + } + g_string_append_c(str, *v); + } + + g_string_append_c(str, '"'); +} + +int +cfs_create_guest_conf_property_msg(GString *str, memdb_t *memdb, const char *prop, uint32_t vmid) +{ + g_return_val_if_fail(cfs_status.vmlist != NULL, -EINVAL); + g_return_val_if_fail(str != NULL, -EINVAL); + + int prop_len = strlen(prop); + int res = 0; + GString *path = NULL; + + // Prelock &memdb->mutex in order to enable the usage of memdb_read_nolock + // to prevent Deadlocks as in #2553 + g_mutex_lock (&memdb->mutex); + g_mutex_lock (&mutex); + + g_string_printf(str,"{\n"); + + GHashTable *ht = cfs_status.vmlist; + gpointer tmp = NULL; + if (!g_hash_table_size(ht)) { + goto ret; + } + + path = g_string_sized_new(256); + if (vmid >= 100) { + vminfo_t *vminfo = (vminfo_t *) g_hash_table_lookup(cfs_status.vmlist, &vmid); + if (vminfo == NULL) goto enoent; + + if (!vminfo_to_path(vminfo, path)) goto err; + + // use memdb_read_nolock because lock is handled here + int size = memdb_read_nolock(memdb, path->str, &tmp); + if (tmp == NULL) goto err; + if (size <= prop_len) goto ret; + + char *val = _get_property_value(tmp, size, prop, prop_len); + if (val == NULL) goto ret; + + g_string_append_printf(str, "\"%u\":{", vmid); + _g_str_append_kv_jsonescaped(str, prop, val); + g_string_append_c(str, '}'); + + } else { + GHashTableIter iter; + g_hash_table_iter_init (&iter, ht); + + gpointer key, value; + int first = 1; + while (g_hash_table_iter_next (&iter, &key, &value)) { + vminfo_t *vminfo = (vminfo_t *)value; + + if (!vminfo_to_path(vminfo, path)) goto err; + + g_free(tmp); // no-op if already null + tmp = NULL; + // use memdb_read_nolock because lock is handled here + int size = memdb_read_nolock(memdb, path->str, &tmp); + if (tmp == NULL || size <= prop_len) continue; + + char *val = _get_property_value(tmp, size, prop, prop_len); + if (val == NULL) continue; + + if (!first) g_string_append_printf(str, ",\n"); + else first = 0; + + g_string_append_printf(str, "\"%u\":{", vminfo->vmid); + _g_str_append_kv_jsonescaped(str, prop, val); + g_string_append_c(str, '}'); + } + } +ret: + g_free(tmp); + if (path != NULL) { + g_string_free(path, TRUE); + } + g_string_append_printf(str,"\n}\n"); + g_mutex_unlock (&mutex); + g_mutex_unlock (&memdb->mutex); + return res; +err: + res = -EIO; + goto ret; +enoent: + res = -ENOENT; + goto ret; +} + void record_memdb_change(const char *path) { @@ -778,7 +995,9 @@ kventry_hash_set( g_return_val_if_fail(data != NULL, FALSE); kventry_t *entry; - if ((entry = (kventry_t *)g_hash_table_lookup(kvhash, key))) { + if (!len) { + g_hash_table_remove(kvhash, key); + } else if ((entry = (kventry_t *)g_hash_table_lookup(kvhash, key))) { g_free(entry->data); entry->data = g_memdup(data, len); entry->len = len; @@ -1064,10 +1283,13 @@ void cfs_rrd_dump(GString *str) { time_t ctime; - time(&ctime); + g_mutex_lock (&mutex); + + time(&ctime); if (rrd_dump_buf && (ctime - rrd_dump_last) < 2) { g_string_assign(str, rrd_dump_buf); + g_mutex_unlock (&mutex); return; } @@ -1096,6 +1318,8 @@ cfs_rrd_dump(GString *str) if (rrd_dump_buf) g_free(rrd_dump_buf); rrd_dump_buf = g_strdup(str->str); + + g_mutex_unlock (&mutex); } static gboolean @@ -1165,6 +1389,8 @@ kvstore_send_update_message( gpointer data, guint32 len) { + if (!dfsm_is_initialized(dfsm)) + return -EACCES; struct iovec iov[2]; @@ -1191,7 +1417,7 @@ kvstore_parse_log_message( g_return_val_if_fail(msg != NULL, NULL); if (msg_len < sizeof(clog_entry_t)) { - cfs_critical("received short log message (%lu < %lu)", msg_len, sizeof(clog_entry_t)); + cfs_critical("received short log message (%zu < %zu)", msg_len, sizeof(clog_entry_t)); return NULL; } @@ -1201,31 +1427,31 @@ kvstore_parse_log_message( entry->ident_len + entry->tag_len + entry->msg_len; if (msg_len != size) { - cfs_critical("received log message with wrong size (%lu != %u)", msg_len, size); + cfs_critical("received log message with wrong size (%zu != %u)", msg_len, size); return NULL; } - msg = entry->data; + char *msgptr = entry->data; - if (*((char *)msg + entry->node_len - 1)) { + if (*((char *)msgptr + entry->node_len - 1)) { cfs_critical("unterminated string in log message"); return NULL; } - msg += entry->node_len; + msgptr += entry->node_len; - if (*((char *)msg + entry->ident_len - 1)) { + if (*((char *)msgptr + entry->ident_len - 1)) { cfs_critical("unterminated string in log message"); return NULL; } - msg += entry->ident_len; + msgptr += entry->ident_len; - if (*((char *)msg + entry->tag_len - 1)) { + if (*((char *)msgptr + entry->tag_len - 1)) { cfs_critical("unterminated string in log message"); return NULL; } - msg += entry->tag_len; + msgptr += entry->tag_len; - if (*((char *)msg + entry->msg_len - 1)) { + if (*((char *)msgptr + entry->msg_len - 1)) { cfs_critical("unterminated string in log message"); return NULL; } @@ -1247,7 +1473,7 @@ kvstore_parse_update_message( g_return_val_if_fail(len != NULL, FALSE); if (msg_len < 256) { - cfs_critical("received short kvstore message (%lu < 256)", msg_len); + cfs_critical("received short kvstore message (%zu < 256)", msg_len); return FALSE; } @@ -1263,7 +1489,7 @@ kvstore_parse_update_message( *len = msg_len - 256; *key = msg; - *data = msg + 256; + *data = (char *) msg + 256; return TRUE; } @@ -1285,7 +1511,7 @@ cfs_create_status_msg( if (!nodename || !nodename[0] || !strcmp(nodename, cfs.nodename)) { kvhash = cfs_status.kvhash; - } else { + } else if (cfs_status.clinfo && cfs_status.clinfo->nodes_byname) { cfs_clnode_t *clnode; if ((clnode = g_hash_table_lookup(cfs_status.clinfo->nodes_byname, nodename))) kvhash = clnode->kvhash; @@ -1649,4 +1875,3 @@ cfs_set_quorate( g_mutex_unlock (&mutex); } -