2 Copyright (C) 2010 - 2020 Proxmox Server Solutions GmbH
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Affero General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Affero General Public License for more details.
14 You should have received a copy of the GNU Affero General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 Author: Dietmar Maurer <dietmar@proxmox.com>
21 #define G_LOG_DOMAIN "status"
25 #endif /* HAVE_CONFIG_H */
32 #include <sys/syslog.h>
34 #include <rrd_client.h>
38 #include "cfs-utils.h"
43 #define KVSTORE_CPG_GROUP_NAME "pve_kvstore_v1"
46 KVSTORE_MESSAGE_UPDATE
= 1,
47 KVSTORE_MESSAGE_UPDATE_COMPLETE
= 2,
48 KVSTORE_MESSAGE_LOG
= 3,
51 static uint32_t vminfo_version_counter
;
79 static memdb_change_t memdb_change_array
[] = {
80 { .path
= "corosync.conf" },
81 { .path
= "corosync.conf.new" },
82 { .path
= "storage.cfg" },
83 { .path
= "user.cfg" },
84 { .path
= "domains.cfg" },
85 { .path
= "priv/shadow.cfg" },
86 { .path
= "priv/acme/plugins.cfg" },
87 { .path
= "priv/tfa.cfg" },
88 { .path
= "priv/token.cfg" },
89 { .path
= "priv/ipam.db" },
90 { .path
= "datacenter.cfg" },
91 { .path
= "vzdump.cron" },
92 { .path
= "ha/crm_commands" },
93 { .path
= "ha/manager_status" },
94 { .path
= "ha/resources.cfg" },
95 { .path
= "ha/groups.cfg" },
96 { .path
= "ha/fence.cfg" },
97 { .path
= "status.cfg" },
98 { .path
= "replication.cfg" },
99 { .path
= "ceph.conf" },
100 { .path
= "sdn/vnets.cfg" },
101 { .path
= "sdn/zones.cfg" },
102 { .path
= "sdn/controllers.cfg" },
103 { .path
= "sdn/subnets.cfg" },
104 { .path
= "sdn/ipams.cfg" },
105 { .path
= "sdn/.version" },
106 { .path
= "virtual-guest/cpu-models.conf" },
116 cfs_clinfo_t
*clinfo
;
117 uint32_t clinfo_version
;
120 uint32_t vmlist_version
;
127 GHashTable
*memdb_changes
;
129 clusterlog_t
*clusterlog
;
132 static cfs_status_t cfs_status
;
144 uint32_t cman_version
;
146 GHashTable
*nodes_byid
;
147 GHashTable
*nodes_byname
;
151 g_int32_hash (gconstpointer v
)
153 return *(const uint32_t *) v
;
157 g_int32_equal (gconstpointer v1
,
160 return *((const uint32_t*) v1
) == *((const uint32_t*) v2
);
163 static void vminfo_free(vminfo_t
*vminfo
)
165 g_return_if_fail(vminfo
!= NULL
);
167 if (vminfo
->nodename
)
168 g_free(vminfo
->nodename
);
174 static const char *vminfo_type_to_string(vminfo_t
*vminfo
)
176 if (vminfo
->vmtype
== VMTYPE_QEMU
) {
178 } else if (vminfo
->vmtype
== VMTYPE_OPENVZ
) {
179 // FIXME: remove openvz stuff for 7.x
181 } else if (vminfo
->vmtype
== VMTYPE_LXC
) {
188 static const char *vminfo_type_to_path_type(vminfo_t
*vminfo
)
190 if (vminfo
->vmtype
== VMTYPE_QEMU
) {
191 return "qemu-server"; // special case..
193 return vminfo_type_to_string(vminfo
);
197 int vminfo_to_path(vminfo_t
*vminfo
, GString
*path
)
199 g_return_val_if_fail(vminfo
!= NULL
, -1);
200 g_return_val_if_fail(path
!= NULL
, -1);
202 if (!vminfo
->nodename
)
205 const char *type
= vminfo_type_to_path_type(vminfo
);
206 g_string_printf(path
, "/nodes/%s/%s/%u.conf", vminfo
->nodename
, type
, vminfo
->vmid
);
211 void cfs_clnode_destroy(
212 cfs_clnode_t
*clnode
)
214 g_return_if_fail(clnode
!= NULL
);
217 g_hash_table_destroy(clnode
->kvhash
);
220 g_free(clnode
->name
);
225 cfs_clnode_t
*cfs_clnode_new(
230 g_return_val_if_fail(name
!= NULL
, NULL
);
232 cfs_clnode_t
*clnode
= g_new0(cfs_clnode_t
, 1);
236 clnode
->name
= g_strdup(name
);
237 clnode
->nodeid
= nodeid
;
238 clnode
->votes
= votes
;
243 gboolean
cfs_clinfo_destroy(
244 cfs_clinfo_t
*clinfo
)
246 g_return_val_if_fail(clinfo
!= NULL
, FALSE
);
248 if (clinfo
->cluster_name
)
249 g_free(clinfo
->cluster_name
);
251 if (clinfo
->nodes_byname
)
252 g_hash_table_destroy(clinfo
->nodes_byname
);
254 if (clinfo
->nodes_byid
)
255 g_hash_table_destroy(clinfo
->nodes_byid
);
262 cfs_clinfo_t
*cfs_clinfo_new(
263 const char *cluster_name
,
264 uint32_t cman_version
)
266 g_return_val_if_fail(cluster_name
!= NULL
, NULL
);
268 cfs_clinfo_t
*clinfo
= g_new0(cfs_clinfo_t
, 1);
272 clinfo
->cluster_name
= g_strdup(cluster_name
);
273 clinfo
->cman_version
= cman_version
;
275 if (!(clinfo
->nodes_byid
= g_hash_table_new_full(
276 g_int32_hash
, g_int32_equal
, NULL
,
277 (GDestroyNotify
)cfs_clnode_destroy
)))
280 if (!(clinfo
->nodes_byname
= g_hash_table_new(g_str_hash
, g_str_equal
)))
286 cfs_clinfo_destroy(clinfo
);
291 gboolean
cfs_clinfo_add_node(
292 cfs_clinfo_t
*clinfo
,
293 cfs_clnode_t
*clnode
)
295 g_return_val_if_fail(clinfo
!= NULL
, FALSE
);
296 g_return_val_if_fail(clnode
!= NULL
, FALSE
);
298 g_hash_table_replace(clinfo
->nodes_byid
, &clnode
->nodeid
, clnode
);
299 g_hash_table_replace(clinfo
->nodes_byname
, clnode
->name
, clnode
);
305 cfs_create_memberlist_msg(
308 g_return_val_if_fail(str
!= NULL
, -EINVAL
);
310 g_mutex_lock (&mutex
);
312 g_string_append_printf(str
,"{\n");
316 cfs_clinfo_t
*clinfo
= cfs_status
.clinfo
;
318 if (clinfo
&& clinfo
->nodes_byid
)
319 nodecount
= g_hash_table_size(clinfo
->nodes_byid
);
322 g_string_append_printf(str
, "\"nodename\": \"%s\",\n", cfs
.nodename
);
323 g_string_append_printf(str
, "\"version\": %u,\n", cfs_status
.clinfo_version
);
325 g_string_append_printf(str
, "\"cluster\": { ");
326 g_string_append_printf(str
, "\"name\": \"%s\", \"version\": %d, "
327 "\"nodes\": %d, \"quorate\": %d ",
328 clinfo
->cluster_name
, clinfo
->cman_version
,
329 nodecount
, cfs_status
.quorate
);
331 g_string_append_printf(str
,"},\n");
332 g_string_append_printf(str
,"\"nodelist\": {\n");
334 GHashTable
*ht
= clinfo
->nodes_byid
;
338 g_hash_table_iter_init (&iter
, ht
);
341 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
342 cfs_clnode_t
*node
= (cfs_clnode_t
*)value
;
343 if (i
) g_string_append_printf(str
, ",\n");
346 g_string_append_printf(str
, " \"%s\": { \"id\": %d, \"online\": %d",
347 node
->name
, node
->nodeid
, node
->online
);
350 char *ip
= (char *)g_hash_table_lookup(cfs_status
.iphash
, node
->name
);
352 g_string_append_printf(str
, ", \"ip\": \"%s\"", ip
);
355 g_string_append_printf(str
, "}");
358 g_string_append_printf(str
,"\n }\n");
360 g_string_append_printf(str
, "\"nodename\": \"%s\",\n", cfs
.nodename
);
361 g_string_append_printf(str
, "\"version\": %u\n", cfs_status
.clinfo_version
);
364 g_string_append_printf(str
,"}\n");
366 g_mutex_unlock (&mutex
);
372 kventry_free(kventry_t
*entry
)
374 g_return_if_fail(entry
!= NULL
);
382 kventry_hash_new(void)
384 return g_hash_table_new_full(g_str_hash
, g_str_equal
, NULL
,
385 (GDestroyNotify
)kventry_free
);
389 rrdentry_free(rrdentry_t
*entry
)
391 g_return_if_fail(entry
!= NULL
);
399 rrdentry_hash_new(void)
401 return g_hash_table_new_full(g_str_hash
, g_str_equal
, NULL
,
402 (GDestroyNotify
)rrdentry_free
);
406 cfs_cluster_log_dump(GString
*str
, const char *user
, guint max_entries
)
408 clusterlog_dump(cfs_status
.clusterlog
, str
, user
, max_entries
);
412 cfs_cluster_log(clog_entry_t
*entry
)
414 g_return_if_fail(entry
!= NULL
);
416 clusterlog_insert(cfs_status
.clusterlog
, entry
);
418 if (cfs_status
.kvstore
) {
420 iov
[0].iov_base
= (char *)entry
;
421 iov
[0].iov_len
= clog_entry_size(entry
);
423 if (dfsm_is_initialized(cfs_status
.kvstore
))
424 dfsm_send_message(cfs_status
.kvstore
, KVSTORE_MESSAGE_LOG
, iov
, 1);
428 void cfs_status_init(void)
430 g_mutex_lock (&mutex
);
432 cfs_status
.start_time
= time(NULL
);
434 cfs_status
.vmlist
= vmlist_hash_new();
436 cfs_status
.kvhash
= kventry_hash_new();
438 cfs_status
.rrdhash
= rrdentry_hash_new();
440 cfs_status
.iphash
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
442 cfs_status
.memdb_changes
= g_hash_table_new(g_str_hash
, g_str_equal
);
444 for (int i
= 0; i
< G_N_ELEMENTS(memdb_change_array
); i
++) {
445 g_hash_table_replace(cfs_status
.memdb_changes
,
446 memdb_change_array
[i
].path
,
447 &memdb_change_array
[i
]);
450 cfs_status
.clusterlog
= clusterlog_new();
453 clusterlog_add(cfs_status
.clusterlog
, "root", "cluster", getpid(),
454 LOG_INFO
, "starting cluster log");
456 g_mutex_unlock (&mutex
);
459 void cfs_status_cleanup(void)
461 g_mutex_lock (&mutex
);
463 cfs_status
.clinfo_version
++;
465 if (cfs_status
.clinfo
) {
466 cfs_clinfo_destroy(cfs_status
.clinfo
);
467 cfs_status
.clinfo
= NULL
;
470 if (cfs_status
.vmlist
) {
471 g_hash_table_destroy(cfs_status
.vmlist
);
472 cfs_status
.vmlist
= NULL
;
475 if (cfs_status
.kvhash
) {
476 g_hash_table_destroy(cfs_status
.kvhash
);
477 cfs_status
.kvhash
= NULL
;
480 if (cfs_status
.rrdhash
) {
481 g_hash_table_destroy(cfs_status
.rrdhash
);
482 cfs_status
.rrdhash
= NULL
;
485 if (cfs_status
.iphash
) {
486 g_hash_table_destroy(cfs_status
.iphash
);
487 cfs_status
.iphash
= NULL
;
490 if (cfs_status
.clusterlog
)
491 clusterlog_destroy(cfs_status
.clusterlog
);
493 g_mutex_unlock (&mutex
);
496 void cfs_status_set_clinfo(
497 cfs_clinfo_t
*clinfo
)
499 g_return_if_fail(clinfo
!= NULL
);
501 g_mutex_lock (&mutex
);
503 cfs_status
.clinfo_version
++;
505 cfs_clinfo_t
*old
= cfs_status
.clinfo
;
507 cfs_status
.clinfo
= clinfo
;
509 cfs_message("update cluster info (cluster name %s, version = %d)",
510 clinfo
->cluster_name
, clinfo
->cman_version
);
513 if (old
&& old
->nodes_byid
&& clinfo
->nodes_byid
) {
515 GHashTable
*ht
= clinfo
->nodes_byid
;
519 g_hash_table_iter_init (&iter
, ht
);
521 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
522 cfs_clnode_t
*node
= (cfs_clnode_t
*)value
;
523 cfs_clnode_t
*oldnode
;
524 if ((oldnode
= g_hash_table_lookup(old
->nodes_byid
, key
))) {
525 node
->online
= oldnode
->online
;
526 node
->kvhash
= oldnode
->kvhash
;
527 oldnode
->kvhash
= NULL
;
534 cfs_clinfo_destroy(old
);
537 g_mutex_unlock (&mutex
);
541 dump_kvstore_versions(
544 const char *nodename
)
546 g_return_if_fail(kvhash
!= NULL
);
547 g_return_if_fail(str
!= NULL
);
548 g_return_if_fail(nodename
!= NULL
);
550 GHashTable
*ht
= kvhash
;
554 g_string_append_printf(str
, "\"%s\": {\n", nodename
);
556 g_hash_table_iter_init (&iter
, ht
);
559 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
560 kventry_t
*entry
= (kventry_t
*)value
;
561 if (i
) g_string_append_printf(str
, ",\n");
563 g_string_append_printf(str
,"\"%s\": %u", entry
->key
, entry
->version
);
566 g_string_append_printf(str
, "}\n");
570 cfs_create_version_msg(GString
*str
)
572 g_return_val_if_fail(str
!= NULL
, -EINVAL
);
574 g_mutex_lock (&mutex
);
576 g_string_append_printf(str
,"{\n");
578 g_string_append_printf(str
, "\"starttime\": %lu,\n", (unsigned long)cfs_status
.start_time
);
580 g_string_append_printf(str
, "\"clinfo\": %u,\n", cfs_status
.clinfo_version
);
582 g_string_append_printf(str
, "\"vmlist\": %u,\n", cfs_status
.vmlist_version
);
584 for (int i
= 0; i
< G_N_ELEMENTS(memdb_change_array
); i
++) {
585 g_string_append_printf(str
, "\"%s\": %u,\n",
586 memdb_change_array
[i
].path
,
587 memdb_change_array
[i
].version
);
590 g_string_append_printf(str
, "\"kvstore\": {\n");
592 dump_kvstore_versions(str
, cfs_status
.kvhash
, cfs
.nodename
);
594 cfs_clinfo_t
*clinfo
= cfs_status
.clinfo
;
596 if (clinfo
&& clinfo
->nodes_byid
) {
597 GHashTable
*ht
= clinfo
->nodes_byid
;
601 g_hash_table_iter_init (&iter
, ht
);
603 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
604 cfs_clnode_t
*node
= (cfs_clnode_t
*)value
;
607 g_string_append_printf(str
, ",\n");
608 dump_kvstore_versions(str
, node
->kvhash
, node
->name
);
612 g_string_append_printf(str
,"}\n");
614 g_string_append_printf(str
,"}\n");
616 g_mutex_unlock (&mutex
);
622 vmlist_hash_new(void)
624 return g_hash_table_new_full(g_int_hash
, g_int_equal
, NULL
,
625 (GDestroyNotify
)vminfo_free
);
629 vmlist_hash_insert_vm(
633 const char *nodename
,
636 g_return_val_if_fail(vmlist
!= NULL
, FALSE
);
637 g_return_val_if_fail(nodename
!= NULL
, FALSE
);
638 g_return_val_if_fail(vmid
!= 0, FALSE
);
639 // FIXME: remove openvz stuff for 7.x
640 g_return_val_if_fail(vmtype
== VMTYPE_QEMU
|| vmtype
== VMTYPE_OPENVZ
||
641 vmtype
== VMTYPE_LXC
, FALSE
);
643 if (!replace
&& g_hash_table_lookup(vmlist
, &vmid
)) {
644 cfs_critical("detected duplicate VMID %d", vmid
);
648 vminfo_t
*vminfo
= g_new0(vminfo_t
, 1);
651 vminfo
->vmtype
= vmtype
;
652 vminfo
->nodename
= g_strdup(nodename
);
654 vminfo
->version
= ++vminfo_version_counter
;
656 g_hash_table_replace(vmlist
, &vminfo
->vmid
, vminfo
);
665 const char *nodename
)
667 g_return_if_fail(cfs_status
.vmlist
!= NULL
);
668 g_return_if_fail(nodename
!= NULL
);
669 g_return_if_fail(vmid
!= 0);
670 // FIXME: remove openvz stuff for 7.x
671 g_return_if_fail(vmtype
== VMTYPE_QEMU
|| vmtype
== VMTYPE_OPENVZ
||
672 vmtype
== VMTYPE_LXC
);
674 cfs_debug("vmlist_register_vm: %s/%u %d", nodename
, vmid
, vmtype
);
676 g_mutex_lock (&mutex
);
678 cfs_status
.vmlist_version
++;
680 vmlist_hash_insert_vm(cfs_status
.vmlist
, vmtype
, vmid
, nodename
, TRUE
);
682 g_mutex_unlock (&mutex
);
686 vmlist_different_vm_exists(
689 const char *nodename
)
691 g_return_val_if_fail(cfs_status
.vmlist
!= NULL
, FALSE
);
692 g_return_val_if_fail(vmid
!= 0, FALSE
);
694 gboolean res
= FALSE
;
696 g_mutex_lock (&mutex
);
699 if ((vminfo
= (vminfo_t
*)g_hash_table_lookup(cfs_status
.vmlist
, &vmid
))) {
700 if (!(vminfo
->vmtype
== vmtype
&& strcmp(vminfo
->nodename
, nodename
) == 0))
703 g_mutex_unlock (&mutex
);
712 g_return_val_if_fail(cfs_status
.vmlist
!= NULL
, FALSE
);
713 g_return_val_if_fail(vmid
!= 0, FALSE
);
715 g_mutex_lock (&mutex
);
717 gpointer res
= g_hash_table_lookup(cfs_status
.vmlist
, &vmid
);
719 g_mutex_unlock (&mutex
);
728 g_return_if_fail(cfs_status
.vmlist
!= NULL
);
729 g_return_if_fail(vmid
!= 0);
731 g_mutex_lock (&mutex
);
733 cfs_status
.vmlist_version
++;
735 g_hash_table_remove(cfs_status
.vmlist
, &vmid
);
737 g_mutex_unlock (&mutex
);
740 void cfs_status_set_vmlist(
743 g_return_if_fail(vmlist
!= NULL
);
745 g_mutex_lock (&mutex
);
747 cfs_status
.vmlist_version
++;
749 if (cfs_status
.vmlist
)
750 g_hash_table_destroy(cfs_status
.vmlist
);
752 cfs_status
.vmlist
= vmlist
;
754 g_mutex_unlock (&mutex
);
758 cfs_create_vmlist_msg(GString
*str
)
760 g_return_val_if_fail(cfs_status
.vmlist
!= NULL
, -EINVAL
);
761 g_return_val_if_fail(str
!= NULL
, -EINVAL
);
763 g_mutex_lock (&mutex
);
765 g_string_append_printf(str
,"{\n");
767 GHashTable
*ht
= cfs_status
.vmlist
;
769 guint count
= g_hash_table_size(ht
);
772 g_string_append_printf(str
,"\"version\": %u\n", cfs_status
.vmlist_version
);
774 g_string_append_printf(str
,"\"version\": %u,\n", cfs_status
.vmlist_version
);
776 g_string_append_printf(str
,"\"ids\": {\n");
781 g_hash_table_iter_init (&iter
, ht
);
784 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
785 vminfo_t
*vminfo
= (vminfo_t
*)value
;
786 const char *type
= vminfo_type_to_string(vminfo
);
789 g_string_append_printf(str
, ",\n");
792 g_string_append_printf(str
,"\"%u\": { \"node\": \"%s\", \"type\": \"%s\", \"version\": %u }",
793 vminfo
->vmid
, vminfo
->nodename
, type
, vminfo
->version
);
796 g_string_append_printf(str
,"}\n");
798 g_string_append_printf(str
,"\n}\n");
800 g_mutex_unlock (&mutex
);
805 // checks the conf for a line starting with '$prop:' and returns the value
806 // afterwards, whitout initial whitespace(s), we only deal with the format
807 // restricion imposed by our perl VM config parser, main reference is
808 // PVE::QemuServer::parse_vm_config this allows to be very fast and still
810 // main restrictions used for our advantage is the properties match reges:
811 // ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) from parse_vm_config
812 // currently we only look at the current configuration in place, i.e., *no*
813 // snapshort and *no* pending changes
815 _get_property_value(char *conf
, int conf_size
, const char *prop
, int prop_len
)
817 const char *const conf_end
= conf
+ conf_size
;
819 size_t remaining_size
;
821 char *next_newline
= memchr(conf
, '\n', conf_size
);
822 if (next_newline
== NULL
) {
823 return NULL
; // valid property lines end with \n, but none in the config
825 *next_newline
= '\0';
827 while (line
!= NULL
) {
828 if (!line
[0]) goto next
;
830 // snapshot or pending section start, but nothing found yet -> not found
831 if (line
[0] == '[') return NULL
;
832 // properties start with /^[a-z]/, so continue early if not
833 if (line
[0] < 'a' || line
[0] > 'z') goto next
;
835 int line_len
= strlen(line
);
836 if (line_len
<= prop_len
+ 1) goto next
;
838 if (line
[prop_len
] == ':' && memcmp(line
, prop
, prop_len
) == 0) { // found
839 char *v_start
= &line
[prop_len
+ 1];
841 // drop initial value whitespaces here already
842 while (*v_start
&& isspace(*v_start
)) v_start
++;
844 if (!*v_start
) return NULL
;
846 char *v_end
= &line
[line_len
- 1];
847 while (v_end
> v_start
&& isspace(*v_end
)) v_end
--;
853 line
= next_newline
+ 1;
854 remaining_size
= conf_end
- line
;
855 if (remaining_size
<= prop_len
) {
858 next_newline
= memchr(line
, '\n', remaining_size
);
859 if (next_newline
== NULL
) {
860 return NULL
; // valid property lines end with \n, but none in the config
862 *next_newline
= '\0';
865 return NULL
; // not found
869 _g_str_append_kv_jsonescaped(GString
*str
, const char *k
, const char *v
)
871 g_string_append_printf(str
, "\"%s\": \"", k
);
874 if (*v
== '\\' || *v
== '"') {
875 g_string_append_c(str
, '\\');
877 g_string_append_c(str
, *v
);
880 g_string_append_c(str
, '"');
884 cfs_create_guest_conf_property_msg(GString
*str
, memdb_t
*memdb
, const char *prop
, uint32_t vmid
)
886 g_return_val_if_fail(cfs_status
.vmlist
!= NULL
, -EINVAL
);
887 g_return_val_if_fail(str
!= NULL
, -EINVAL
);
889 int prop_len
= strlen(prop
);
891 GString
*path
= NULL
;
893 // Prelock &memdb->mutex in order to enable the usage of memdb_read_nolock
894 // to prevent Deadlocks as in #2553
895 g_mutex_lock (&memdb
->mutex
);
896 g_mutex_lock (&mutex
);
898 g_string_printf(str
,"{\n");
900 GHashTable
*ht
= cfs_status
.vmlist
;
902 if (!g_hash_table_size(ht
)) {
906 if ((path
= g_string_sized_new(256)) == NULL
) {
912 vminfo_t
*vminfo
= (vminfo_t
*) g_hash_table_lookup(cfs_status
.vmlist
, &vmid
);
913 if (vminfo
== NULL
) goto enoent
;
915 if (!vminfo_to_path(vminfo
, path
)) goto err
;
917 // use memdb_read_nolock because lock is handled here
918 int size
= memdb_read_nolock(memdb
, path
->str
, &tmp
);
919 if (tmp
== NULL
) goto err
;
920 if (size
<= prop_len
) goto ret
;
922 char *val
= _get_property_value(tmp
, size
, prop
, prop_len
);
923 if (val
== NULL
) goto ret
;
925 g_string_append_printf(str
, "\"%u\":{", vmid
);
926 _g_str_append_kv_jsonescaped(str
, prop
, val
);
927 g_string_append_c(str
, '}');
931 g_hash_table_iter_init (&iter
, ht
);
935 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
936 vminfo_t
*vminfo
= (vminfo_t
*)value
;
938 if (!vminfo_to_path(vminfo
, path
)) goto err
;
940 g_free(tmp
); // no-op if already null
942 // use memdb_read_nolock because lock is handled here
943 int size
= memdb_read_nolock(memdb
, path
->str
, &tmp
);
944 if (tmp
== NULL
|| size
<= prop_len
) continue;
946 char *val
= _get_property_value(tmp
, size
, prop
, prop_len
);
947 if (val
== NULL
) continue;
949 if (!first
) g_string_append_printf(str
, ",\n");
952 g_string_append_printf(str
, "\"%u\":{", vminfo
->vmid
);
953 _g_str_append_kv_jsonescaped(str
, prop
, val
);
954 g_string_append_c(str
, '}');
960 g_string_free(path
, TRUE
);
962 g_string_append_printf(str
,"\n}\n");
963 g_mutex_unlock (&mutex
);
964 g_mutex_unlock (&memdb
->mutex
);
975 record_memdb_change(const char *path
)
977 g_return_if_fail(cfs_status
.memdb_changes
!= 0);
981 if ((ce
= (memdb_change_t
*)g_hash_table_lookup(cfs_status
.memdb_changes
, path
))) {
987 record_memdb_reload(void)
989 for (int i
= 0; i
< G_N_ELEMENTS(memdb_change_array
); i
++) {
990 memdb_change_array
[i
].version
++;
1001 g_return_val_if_fail(kvhash
!= NULL
, FALSE
);
1002 g_return_val_if_fail(key
!= NULL
, FALSE
);
1003 g_return_val_if_fail(data
!= NULL
, FALSE
);
1007 g_hash_table_remove(kvhash
, key
);
1008 } else if ((entry
= (kventry_t
*)g_hash_table_lookup(kvhash
, key
))) {
1009 g_free(entry
->data
);
1010 entry
->data
= g_memdup(data
, len
);
1014 kventry_t
*entry
= g_new0(kventry_t
, 1);
1016 entry
->key
= g_strdup(key
);
1017 entry
->data
= g_memdup(data
, len
);
1020 g_hash_table_replace(kvhash
, entry
->key
, entry
);
1026 static const char *rrd_def_node
[] = {
1027 "DS:loadavg:GAUGE:120:0:U",
1028 "DS:maxcpu:GAUGE:120:0:U",
1029 "DS:cpu:GAUGE:120:0:U",
1030 "DS:iowait:GAUGE:120:0:U",
1031 "DS:memtotal:GAUGE:120:0:U",
1032 "DS:memused:GAUGE:120:0:U",
1033 "DS:swaptotal:GAUGE:120:0:U",
1034 "DS:swapused:GAUGE:120:0:U",
1035 "DS:roottotal:GAUGE:120:0:U",
1036 "DS:rootused:GAUGE:120:0:U",
1037 "DS:netin:DERIVE:120:0:U",
1038 "DS:netout:DERIVE:120:0:U",
1040 "RRA:AVERAGE:0.5:1:70", // 1 min avg - one hour
1041 "RRA:AVERAGE:0.5:30:70", // 30 min avg - one day
1042 "RRA:AVERAGE:0.5:180:70", // 3 hour avg - one week
1043 "RRA:AVERAGE:0.5:720:70", // 12 hour avg - one month
1044 "RRA:AVERAGE:0.5:10080:70", // 7 day avg - ony year
1046 "RRA:MAX:0.5:1:70", // 1 min max - one hour
1047 "RRA:MAX:0.5:30:70", // 30 min max - one day
1048 "RRA:MAX:0.5:180:70", // 3 hour max - one week
1049 "RRA:MAX:0.5:720:70", // 12 hour max - one month
1050 "RRA:MAX:0.5:10080:70", // 7 day max - ony year
1054 static const char *rrd_def_vm
[] = {
1055 "DS:maxcpu:GAUGE:120:0:U",
1056 "DS:cpu:GAUGE:120:0:U",
1057 "DS:maxmem:GAUGE:120:0:U",
1058 "DS:mem:GAUGE:120:0:U",
1059 "DS:maxdisk:GAUGE:120:0:U",
1060 "DS:disk:GAUGE:120:0:U",
1061 "DS:netin:DERIVE:120:0:U",
1062 "DS:netout:DERIVE:120:0:U",
1063 "DS:diskread:DERIVE:120:0:U",
1064 "DS:diskwrite:DERIVE:120:0:U",
1066 "RRA:AVERAGE:0.5:1:70", // 1 min avg - one hour
1067 "RRA:AVERAGE:0.5:30:70", // 30 min avg - one day
1068 "RRA:AVERAGE:0.5:180:70", // 3 hour avg - one week
1069 "RRA:AVERAGE:0.5:720:70", // 12 hour avg - one month
1070 "RRA:AVERAGE:0.5:10080:70", // 7 day avg - ony year
1072 "RRA:MAX:0.5:1:70", // 1 min max - one hour
1073 "RRA:MAX:0.5:30:70", // 30 min max - one day
1074 "RRA:MAX:0.5:180:70", // 3 hour max - one week
1075 "RRA:MAX:0.5:720:70", // 12 hour max - one month
1076 "RRA:MAX:0.5:10080:70", // 7 day max - ony year
1080 static const char *rrd_def_storage
[] = {
1081 "DS:total:GAUGE:120:0:U",
1082 "DS:used:GAUGE:120:0:U",
1084 "RRA:AVERAGE:0.5:1:70", // 1 min avg - one hour
1085 "RRA:AVERAGE:0.5:30:70", // 30 min avg - one day
1086 "RRA:AVERAGE:0.5:180:70", // 3 hour avg - one week
1087 "RRA:AVERAGE:0.5:720:70", // 12 hour avg - one month
1088 "RRA:AVERAGE:0.5:10080:70", // 7 day avg - ony year
1090 "RRA:MAX:0.5:1:70", // 1 min max - one hour
1091 "RRA:MAX:0.5:30:70", // 30 min max - one day
1092 "RRA:MAX:0.5:180:70", // 3 hour max - one week
1093 "RRA:MAX:0.5:720:70", // 12 hour max - one month
1094 "RRA:MAX:0.5:10080:70", // 7 day max - ony year
1098 #define RRDDIR "/var/lib/rrdcached/db"
1102 const char *filename
,
1104 const char *rrddef
[])
1106 /* start at day boundary */
1109 struct tm
*ltm
= localtime(&ctime
);
1115 if (rrd_create_r(filename
, 60, timelocal(ltm
), argcount
, rrddef
)) {
1116 cfs_message("RRD create error %s: %s", filename
, rrd_get_error());
1120 static inline const char *
1126 while (*data
&& found
< count
) {
1139 g_return_if_fail(key
!= NULL
);
1140 g_return_if_fail(data
!= NULL
);
1141 g_return_if_fail(len
> 0);
1142 g_return_if_fail(len
< 4096);
1144 static const char *rrdcsock
= "unix:/var/run/rrdcached.sock";
1147 if (rrdc_connect(rrdcsock
) != 0)
1150 char *filename
= NULL
;
1154 if (strncmp(key
, "pve2-node/", 10) == 0) {
1155 const char *node
= key
+ 10;
1159 if (strchr(node
, '/') != NULL
)
1162 if (strlen(node
) < 1)
1165 filename
= g_strdup_printf(RRDDIR
"/%s", key
);
1167 if (!g_file_test(filename
, G_FILE_TEST_EXISTS
)) {
1169 mkdir(RRDDIR
"/pve2-node", 0755);
1170 int argcount
= sizeof(rrd_def_node
)/sizeof(void*) - 1;
1171 create_rrd_file(filename
, argcount
, rrd_def_node
);
1174 } else if ((strncmp(key
, "pve2-vm/", 8) == 0) ||
1175 (strncmp(key
, "pve2.3-vm/", 10) == 0)) {
1178 if (strncmp(key
, "pve2-vm/", 8) == 0) {
1186 if (strchr(vmid
, '/') != NULL
)
1189 if (strlen(vmid
) < 1)
1192 filename
= g_strdup_printf(RRDDIR
"/%s/%s", "pve2-vm", vmid
);
1194 if (!g_file_test(filename
, G_FILE_TEST_EXISTS
)) {
1196 mkdir(RRDDIR
"/pve2-vm", 0755);
1197 int argcount
= sizeof(rrd_def_vm
)/sizeof(void*) - 1;
1198 create_rrd_file(filename
, argcount
, rrd_def_vm
);
1201 } else if (strncmp(key
, "pve2-storage/", 13) == 0) {
1202 const char *node
= key
+ 13;
1204 const char *storage
= node
;
1205 while (*storage
&& *storage
!= '/')
1208 if (*storage
!= '/' || ((storage
- node
) < 1))
1213 if (strchr(storage
, '/') != NULL
)
1216 if (strlen(storage
) < 1)
1219 filename
= g_strdup_printf(RRDDIR
"/%s", key
);
1221 if (!g_file_test(filename
, G_FILE_TEST_EXISTS
)) {
1223 mkdir(RRDDIR
"/pve2-storage", 0755);
1225 char *dir
= g_path_get_dirname(filename
);
1229 int argcount
= sizeof(rrd_def_storage
)/sizeof(void*) - 1;
1230 create_rrd_file(filename
, argcount
, rrd_def_storage
);
1237 const char *dp
= skip
? rrd_skip_data(data
, skip
) : data
;
1239 const char *update_args
[] = { dp
, NULL
};
1243 if ((status
= rrdc_update(filename
, 1, update_args
)) != 0) {
1244 cfs_message("RRDC update error %s: %d", filename
, status
);
1247 if (rrd_update_r(filename
, NULL
, 1, update_args
) != 0) {
1248 cfs_message("RRD update error %s: %s", filename
, rrd_get_error());
1254 if (rrd_update_r(filename
, NULL
, 1, update_args
) != 0) {
1255 cfs_message("RRD update error %s: %s", filename
, rrd_get_error());
1266 cfs_critical("RRD update error: unknown/wrong key %s", key
);
1276 rrdentry_t
*entry
= (rrdentry_t
*)value
;
1277 uint32_t ctime
= GPOINTER_TO_UINT(user_data
);
1279 int diff
= ctime
- entry
->time
;
1281 /* remove everything older than 5 minutes */
1284 return (diff
> expire
) ? TRUE
: FALSE
;
1287 static char *rrd_dump_buf
= NULL
;
1288 static time_t rrd_dump_last
= 0;
1291 cfs_rrd_dump(GString
*str
)
1295 g_mutex_lock (&mutex
);
1298 if (rrd_dump_buf
&& (ctime
- rrd_dump_last
) < 2) {
1299 g_string_assign(str
, rrd_dump_buf
);
1300 g_mutex_unlock (&mutex
);
1304 /* remove old data */
1305 g_hash_table_foreach_remove(cfs_status
.rrdhash
, rrd_entry_is_old
,
1306 GUINT_TO_POINTER(ctime
));
1308 g_string_set_size(str
, 0);
1310 GHashTableIter iter
;
1311 gpointer key
, value
;
1313 g_hash_table_iter_init (&iter
, cfs_status
.rrdhash
);
1315 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
1316 rrdentry_t
*entry
= (rrdentry_t
*)value
;
1317 g_string_append(str
, key
);
1318 g_string_append(str
, ":");
1319 g_string_append(str
, entry
->data
);
1320 g_string_append(str
, "\n");
1323 g_string_append_c(str
, 0); // never return undef
1325 rrd_dump_last
= ctime
;
1327 g_free(rrd_dump_buf
);
1328 rrd_dump_buf
= g_strdup(str
->str
);
1330 g_mutex_unlock (&mutex
);
1336 const char *nodename
,
1340 g_return_val_if_fail(iphash
!= NULL
, FALSE
);
1341 g_return_val_if_fail(nodename
!= NULL
, FALSE
);
1342 g_return_val_if_fail(ip
!= NULL
, FALSE
);
1343 g_return_val_if_fail(len
> 0, FALSE
);
1344 g_return_val_if_fail(len
< 256, FALSE
);
1345 g_return_val_if_fail(ip
[len
-1] == 0, FALSE
);
1347 char *oldip
= (char *)g_hash_table_lookup(iphash
, nodename
);
1349 if (!oldip
|| (strcmp(oldip
, ip
) != 0)) {
1350 cfs_status
.clinfo_version
++;
1351 g_hash_table_replace(iphash
, g_strdup(nodename
), g_strdup(ip
));
1359 GHashTable
*rrdhash
,
1364 g_return_val_if_fail(rrdhash
!= NULL
, FALSE
);
1365 g_return_val_if_fail(key
!= NULL
, FALSE
);
1366 g_return_val_if_fail(data
!= NULL
, FALSE
);
1367 g_return_val_if_fail(len
> 0, FALSE
);
1368 g_return_val_if_fail(len
< 4096, FALSE
);
1369 g_return_val_if_fail(data
[len
-1] == 0, FALSE
);
1372 if ((entry
= (rrdentry_t
*)g_hash_table_lookup(rrdhash
, key
))) {
1373 g_free(entry
->data
);
1374 entry
->data
= g_memdup(data
, len
);
1376 entry
->time
= time(NULL
);
1378 rrdentry_t
*entry
= g_new0(rrdentry_t
, 1);
1380 entry
->key
= g_strdup(key
);
1381 entry
->data
= g_memdup(data
, len
);
1383 entry
->time
= time(NULL
);
1385 g_hash_table_replace(rrdhash
, entry
->key
, entry
);
1388 update_rrd_data(key
, data
, len
);
1394 kvstore_send_update_message(
1400 if (!dfsm_is_initialized(dfsm
))
1403 struct iovec iov
[2];
1406 g_strlcpy(name
, key
, sizeof(name
));
1408 iov
[0].iov_base
= &name
;
1409 iov
[0].iov_len
= sizeof(name
);
1411 iov
[1].iov_base
= (char *)data
;
1412 iov
[1].iov_len
= len
;
1414 if (dfsm_send_message(dfsm
, KVSTORE_MESSAGE_UPDATE
, iov
, 2) == CS_OK
)
1420 static clog_entry_t
*
1421 kvstore_parse_log_message(
1425 g_return_val_if_fail(msg
!= NULL
, NULL
);
1427 if (msg_len
< sizeof(clog_entry_t
)) {
1428 cfs_critical("received short log message (%zu < %zu)", msg_len
, sizeof(clog_entry_t
));
1432 clog_entry_t
*entry
= (clog_entry_t
*)msg
;
1434 uint32_t size
= sizeof(clog_entry_t
) + entry
->node_len
+
1435 entry
->ident_len
+ entry
->tag_len
+ entry
->msg_len
;
1437 if (msg_len
!= size
) {
1438 cfs_critical("received log message with wrong size (%zu != %u)", msg_len
, size
);
1442 char *msgptr
= entry
->data
;
1444 if (*((char *)msgptr
+ entry
->node_len
- 1)) {
1445 cfs_critical("unterminated string in log message");
1448 msgptr
+= entry
->node_len
;
1450 if (*((char *)msgptr
+ entry
->ident_len
- 1)) {
1451 cfs_critical("unterminated string in log message");
1454 msgptr
+= entry
->ident_len
;
1456 if (*((char *)msgptr
+ entry
->tag_len
- 1)) {
1457 cfs_critical("unterminated string in log message");
1460 msgptr
+= entry
->tag_len
;
1462 if (*((char *)msgptr
+ entry
->msg_len
- 1)) {
1463 cfs_critical("unterminated string in log message");
1471 kvstore_parse_update_message(
1475 gconstpointer
*data
,
1478 g_return_val_if_fail(msg
!= NULL
, FALSE
);
1479 g_return_val_if_fail(key
!= NULL
, FALSE
);
1480 g_return_val_if_fail(data
!= NULL
, FALSE
);
1481 g_return_val_if_fail(len
!= NULL
, FALSE
);
1483 if (msg_len
< 256) {
1484 cfs_critical("received short kvstore message (%zu < 256)", msg_len
);
1488 /* test if key is null terminated */
1490 for (i
= 0; i
< 256; i
++)
1491 if (((char *)msg
)[i
] == 0)
1498 *len
= msg_len
- 256;
1500 *data
= (char *) msg
+ 256;
1506 cfs_create_status_msg(
1508 const char *nodename
,
1511 g_return_val_if_fail(str
!= NULL
, -EINVAL
);
1512 g_return_val_if_fail(key
!= NULL
, -EINVAL
);
1516 GHashTable
*kvhash
= NULL
;
1518 g_mutex_lock (&mutex
);
1520 if (!nodename
|| !nodename
[0] || !strcmp(nodename
, cfs
.nodename
)) {
1521 kvhash
= cfs_status
.kvhash
;
1522 } else if (cfs_status
.clinfo
&& cfs_status
.clinfo
->nodes_byname
) {
1523 cfs_clnode_t
*clnode
;
1524 if ((clnode
= g_hash_table_lookup(cfs_status
.clinfo
->nodes_byname
, nodename
)))
1525 kvhash
= clnode
->kvhash
;
1529 if (kvhash
&& (entry
= (kventry_t
*)g_hash_table_lookup(kvhash
, key
))) {
1530 g_string_append_len(str
, entry
->data
, entry
->len
);
1534 g_mutex_unlock (&mutex
);
1545 g_return_val_if_fail(key
!= NULL
, FALSE
);
1546 g_return_val_if_fail(data
!= NULL
, FALSE
);
1547 g_return_val_if_fail(cfs_status
.kvhash
!= NULL
, FALSE
);
1549 if (len
> CFS_MAX_STATUS_SIZE
)
1552 g_mutex_lock (&mutex
);
1556 if (strncmp(key
, "rrd/", 4) == 0) {
1557 res
= rrdentry_hash_set(cfs_status
.rrdhash
, key
+ 4, data
, len
);
1558 } else if (!strcmp(key
, "nodeip")) {
1559 res
= nodeip_hash_set(cfs_status
.iphash
, cfs
.nodename
, data
, len
);
1561 res
= kventry_hash_set(cfs_status
.kvhash
, key
, data
, len
);
1563 g_mutex_unlock (&mutex
);
1565 if (cfs_status
.kvstore
)
1566 kvstore_send_update_message(cfs_status
.kvstore
, key
, data
, len
);
1568 return res
? 0 : -ENOMEM
;
1572 cfs_kvstore_node_set(
1578 g_return_val_if_fail(nodeid
!= 0, FALSE
);
1579 g_return_val_if_fail(key
!= NULL
, FALSE
);
1580 g_return_val_if_fail(data
!= NULL
, FALSE
);
1582 g_mutex_lock (&mutex
);
1584 if (!cfs_status
.clinfo
|| !cfs_status
.clinfo
->nodes_byid
)
1585 goto ret
; /* ignore */
1587 cfs_clnode_t
*clnode
= g_hash_table_lookup(cfs_status
.clinfo
->nodes_byid
, &nodeid
);
1589 goto ret
; /* ignore */
1591 cfs_debug("got node %d status update %s", nodeid
, key
);
1593 if (strncmp(key
, "rrd/", 4) == 0) {
1594 rrdentry_hash_set(cfs_status
.rrdhash
, key
+ 4, data
, len
);
1595 } else if (!strcmp(key
, "nodeip")) {
1596 nodeip_hash_set(cfs_status
.iphash
, clnode
->name
, data
, len
);
1598 if (!clnode
->kvhash
) {
1599 if (!(clnode
->kvhash
= kventry_hash_new())) {
1600 goto ret
; /*ignore */
1604 kventry_hash_set(clnode
->kvhash
, key
, data
, len
);
1608 g_mutex_unlock (&mutex
);
1614 cfs_kvstore_sync(void)
1616 g_return_val_if_fail(cfs_status
.kvhash
!= NULL
, FALSE
);
1617 g_return_val_if_fail(cfs_status
.kvstore
!= NULL
, FALSE
);
1619 gboolean res
= TRUE
;
1621 g_mutex_lock (&mutex
);
1623 GHashTable
*ht
= cfs_status
.kvhash
;
1624 GHashTableIter iter
;
1625 gpointer key
, value
;
1627 g_hash_table_iter_init (&iter
, ht
);
1629 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
1630 kventry_t
*entry
= (kventry_t
*)value
;
1631 kvstore_send_update_message(cfs_status
.kvstore
, entry
->key
, entry
->data
, entry
->len
);
1634 g_mutex_unlock (&mutex
);
1651 g_return_val_if_fail(dfsm
!= NULL
, -1);
1652 g_return_val_if_fail(msg
!= NULL
, -1);
1653 g_return_val_if_fail(res_ptr
!= NULL
, -1);
1655 /* ignore message for ourself */
1656 if (dfsm_nodeid_is_local(dfsm
, nodeid
, pid
))
1659 if (msg_type
== KVSTORE_MESSAGE_UPDATE
) {
1663 if (kvstore_parse_update_message(msg
, msg_len
, &key
, &data
, &len
)) {
1664 cfs_kvstore_node_set(nodeid
, key
, data
, len
);
1666 cfs_critical("cant parse update message");
1668 } else if (msg_type
== KVSTORE_MESSAGE_LOG
) {
1669 cfs_message("received log"); // fixme: remove
1670 const clog_entry_t
*entry
;
1671 if ((entry
= kvstore_parse_log_message(msg
, msg_len
))) {
1672 clusterlog_insert(cfs_status
.clusterlog
, entry
);
1674 cfs_critical("cant parse log message");
1677 cfs_critical("received unknown message type %d\n", msg_type
);
1694 const struct cpg_address
*member_list
,
1695 size_t member_list_entries
)
1697 g_return_if_fail(dfsm
!= NULL
);
1698 g_return_if_fail(member_list
!= NULL
);
1700 cfs_debug("enter %s", __func__
);
1702 g_mutex_lock (&mutex
);
1704 cfs_clinfo_t
*clinfo
= cfs_status
.clinfo
;
1706 if (clinfo
&& clinfo
->nodes_byid
) {
1708 GHashTable
*ht
= clinfo
->nodes_byid
;
1709 GHashTableIter iter
;
1710 gpointer key
, value
;
1712 g_hash_table_iter_init (&iter
, ht
);
1714 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
1715 cfs_clnode_t
*node
= (cfs_clnode_t
*)value
;
1716 node
->online
= FALSE
;
1719 for (int i
= 0; i
< member_list_entries
; i
++) {
1721 if ((node
= g_hash_table_lookup(clinfo
->nodes_byid
, &member_list
[i
].nodeid
))) {
1722 node
->online
= TRUE
;
1726 cfs_status
.clinfo_version
++;
1729 g_mutex_unlock (&mutex
);
1736 unsigned int *res_len
)
1738 g_return_val_if_fail(dfsm
!= NULL
, NULL
);
1740 gpointer msg
= clusterlog_get_state(cfs_status
.clusterlog
, res_len
);
1746 dfsm_process_update(
1749 dfsm_sync_info_t
*syncinfo
,
1755 cfs_critical("%s: received unexpected update message", __func__
);
1761 dfsm_process_state_update(
1764 dfsm_sync_info_t
*syncinfo
)
1766 g_return_val_if_fail(dfsm
!= NULL
, -1);
1767 g_return_val_if_fail(syncinfo
!= NULL
, -1);
1769 clog_base_t
*clog
[syncinfo
->node_count
];
1771 int local_index
= -1;
1772 for (int i
= 0; i
< syncinfo
->node_count
; i
++) {
1773 dfsm_node_info_t
*ni
= &syncinfo
->nodes
[i
];
1776 if (syncinfo
->local
== ni
)
1779 clog_base_t
*base
= (clog_base_t
*)ni
->state
;
1780 if (ni
->state_len
> 8 && ni
->state_len
== clog_size(base
)) {
1781 clog
[i
] = ni
->state
;
1783 cfs_critical("received log with wrong size %u", ni
->state_len
);
1788 if (!clusterlog_merge(cfs_status
.clusterlog
, clog
, syncinfo
->node_count
, local_index
)) {
1789 cfs_critical("unable to merge log files");
1801 dfsm_sync_info_t
*syncinfo
)
1803 g_return_val_if_fail(dfsm
!= NULL
, -1);
1804 g_return_val_if_fail(syncinfo
!= NULL
, -1);
1810 dfsm_synced(dfsm_t
*dfsm
)
1812 g_return_if_fail(dfsm
!= NULL
);
1814 char *ip
= (char *)g_hash_table_lookup(cfs_status
.iphash
, cfs
.nodename
);
1818 cfs_status_set("nodeip", ip
, strlen(ip
) + 1);
1825 dfsm_sync_info_t
*syncinfo
)
1830 static dfsm_callbacks_t kvstore_dfsm_callbacks
= {
1831 .dfsm_deliver_fn
= dfsm_deliver
,
1832 .dfsm_confchg_fn
= dfsm_confchg
,
1834 .dfsm_get_state_fn
= dfsm_get_state
,
1835 .dfsm_process_state_update_fn
= dfsm_process_state_update
,
1836 .dfsm_process_update_fn
= dfsm_process_update
,
1837 .dfsm_commit_fn
= dfsm_commit
,
1838 .dfsm_cleanup_fn
= dfsm_cleanup
,
1839 .dfsm_synced_fn
= dfsm_synced
,
1843 cfs_status_dfsm_new(void)
1845 g_mutex_lock (&mutex
);
1847 cfs_status
.kvstore
= dfsm_new(NULL
, KVSTORE_CPG_GROUP_NAME
, G_LOG_DOMAIN
,
1848 0, &kvstore_dfsm_callbacks
);
1849 g_mutex_unlock (&mutex
);
1851 return cfs_status
.kvstore
;
1855 cfs_is_quorate(void)
1857 g_mutex_lock (&mutex
);
1858 gboolean res
= cfs_status
.quorate
;
1859 g_mutex_unlock (&mutex
);
1869 g_mutex_lock (&mutex
);
1871 uint32_t prev_quorate
= cfs_status
.quorate
;
1872 cfs_status
.quorate
= quorate
;
1874 if (!prev_quorate
&& cfs_status
.quorate
) {
1876 cfs_message("node has quorum");
1879 if (prev_quorate
&& !cfs_status
.quorate
) {
1881 cfs_message("node lost quorum");
1884 g_mutex_unlock (&mutex
);