dhodovsk / source-git / pacemaker

Forked from source-git/pacemaker 3 years ago
Clone

Blame daemons/controld/controld_membership.c

rpm-build 3ee90c
/*
rpm-build 3ee90c
 * Copyright 2004-2019 the Pacemaker project contributors
rpm-build 3ee90c
 *
rpm-build 3ee90c
 * The version control history for this file may have further details.
rpm-build 3ee90c
 *
rpm-build 3ee90c
 * This source code is licensed under the GNU General Public License version 2
rpm-build 3ee90c
 * or later (GPLv2+) WITHOUT ANY WARRANTY.
rpm-build 3ee90c
 */
rpm-build 3ee90c
rpm-build 3ee90c
/* put these first so that uuid_t is defined without conflicts */
rpm-build 3ee90c
#include <crm_internal.h>
rpm-build 3ee90c
rpm-build 3ee90c
#include <string.h>
rpm-build 3ee90c
rpm-build 3ee90c
#include <crm/crm.h>
rpm-build 3ee90c
#include <crm/msg_xml.h>
rpm-build 3ee90c
#include <crm/common/xml.h>
rpm-build 3ee90c
#include <crm/cluster/internal.h>
rpm-build 3ee90c
rpm-build 3ee90c
#include <pacemaker-controld.h>
rpm-build 3ee90c
rpm-build 3ee90c
gboolean membership_flux_hack = FALSE;
rpm-build 3ee90c
void post_cache_update(int instance);
rpm-build 3ee90c
rpm-build 3ee90c
int last_peer_update = 0;
rpm-build 3ee90c
guint highest_born_on = -1;
rpm-build 3ee90c
rpm-build 3ee90c
extern gboolean check_join_state(enum crmd_fsa_state cur_state, const char *source);
rpm-build 3ee90c
rpm-build 3ee90c
static void
rpm-build 3ee90c
reap_dead_nodes(gpointer key, gpointer value, gpointer user_data)
rpm-build 3ee90c
{
rpm-build 3ee90c
    crm_node_t *node = value;
rpm-build 3ee90c
rpm-build 3ee90c
    if (crm_is_peer_active(node) == FALSE) {
rpm-build 3ee90c
        crm_update_peer_join(__FUNCTION__, node, crm_join_none);
rpm-build 3ee90c
rpm-build 3ee90c
        if(node && node->uname) {
rpm-build 3ee90c
            if (safe_str_eq(fsa_our_uname, node->uname)) {
rpm-build 3ee90c
                crm_err("We're not part of the cluster anymore");
rpm-build 3ee90c
                register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL);
rpm-build 3ee90c
rpm-build 3ee90c
            } else if (AM_I_DC == FALSE && safe_str_eq(node->uname, fsa_our_dc)) {
rpm-build 3ee90c
                crm_warn("Our DC node (%s) left the cluster", node->uname);
rpm-build 3ee90c
                register_fsa_input(C_FSA_INTERNAL, I_ELECTION, NULL);
rpm-build 3ee90c
            }
rpm-build 3ee90c
        }
rpm-build 3ee90c
rpm-build 3ee90c
        if (fsa_state == S_INTEGRATION || fsa_state == S_FINALIZE_JOIN) {
rpm-build 3ee90c
            check_join_state(fsa_state, __FUNCTION__);
rpm-build 3ee90c
        }
rpm-build 3ee90c
        if(node && node->uuid) {
rpm-build 3ee90c
            fail_incompletable_actions(transition_graph, node->uuid);
rpm-build 3ee90c
        }
rpm-build 3ee90c
    }
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
gboolean ever_had_quorum = FALSE;
rpm-build 3ee90c
rpm-build 3ee90c
void
rpm-build 3ee90c
post_cache_update(int instance)
rpm-build 3ee90c
{
rpm-build 3ee90c
    xmlNode *no_op = NULL;
rpm-build 3ee90c
rpm-build 3ee90c
    crm_peer_seq = instance;
rpm-build 3ee90c
    crm_debug("Updated cache after membership event %d.", instance);
rpm-build 3ee90c
rpm-build 3ee90c
    g_hash_table_foreach(crm_peer_cache, reap_dead_nodes, NULL);
rpm-build 3ee90c
    set_bit(fsa_input_register, R_MEMBERSHIP);
rpm-build 3ee90c
rpm-build 3ee90c
    if (AM_I_DC) {
rpm-build 3ee90c
        populate_cib_nodes(node_update_quick | node_update_cluster | node_update_peer |
rpm-build 3ee90c
                           node_update_expected, __FUNCTION__);
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    /*
rpm-build 3ee90c
     * If we lost nodes, we should re-check the election status
rpm-build 3ee90c
     * Safe to call outside of an election
rpm-build 3ee90c
     */
rpm-build 3ee90c
    register_fsa_action(A_ELECTION_CHECK);
rpm-build 3ee90c
rpm-build 3ee90c
    /* Membership changed, remind everyone we're here.
rpm-build 3ee90c
     * This will aid detection of duplicate DCs
rpm-build 3ee90c
     */
rpm-build 3ee90c
    no_op = create_request(CRM_OP_NOOP, NULL, NULL, CRM_SYSTEM_CRMD,
rpm-build 3ee90c
                           AM_I_DC ? CRM_SYSTEM_DC : CRM_SYSTEM_CRMD, NULL);
rpm-build 3ee90c
    send_cluster_message(NULL, crm_msg_crmd, no_op, FALSE);
rpm-build 3ee90c
    free_xml(no_op);
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
static void
rpm-build 3ee90c
crmd_node_update_complete(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
rpm-build 3ee90c
{
rpm-build 3ee90c
    fsa_data_t *msg_data = NULL;
rpm-build 3ee90c
rpm-build 3ee90c
    last_peer_update = 0;
rpm-build 3ee90c
rpm-build 3ee90c
    if (rc == pcmk_ok) {
rpm-build 3ee90c
        crm_trace("Node update %d complete", call_id);
rpm-build 3ee90c
rpm-build 3ee90c
    } else if(call_id < pcmk_ok) {
rpm-build 3ee90c
        crm_err("Node update failed: %s (%d)", pcmk_strerror(call_id), call_id);
rpm-build 3ee90c
        crm_log_xml_debug(msg, "failed");
rpm-build 3ee90c
        register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
rpm-build 3ee90c
rpm-build 3ee90c
    } else {
rpm-build 3ee90c
        crm_err("Node update %d failed: %s (%d)", call_id, pcmk_strerror(rc), rc);
rpm-build 3ee90c
        crm_log_xml_debug(msg, "failed");
rpm-build 3ee90c
        register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
rpm-build 3ee90c
    }
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
/*!
rpm-build 3ee90c
 * \internal
rpm-build 3ee90c
 * \brief Create an XML node state tag with updates
rpm-build 3ee90c
 *
rpm-build 3ee90c
 * \param[in,out] node    Node whose state will be used for update
rpm-build 3ee90c
 * \param[in]     flags   Bitmask of node_update_flags indicating what to update
rpm-build 3ee90c
 * \param[in,out] parent  XML node to contain update (or NULL)
rpm-build 3ee90c
 * \param[in]     source  Who requested the update (only used for logging)
rpm-build 3ee90c
 *
rpm-build 3ee90c
 * \return Pointer to created node state tag
rpm-build 3ee90c
 */
rpm-build 3ee90c
xmlNode *
rpm-build 3ee90c
create_node_state_update(crm_node_t *node, int flags, xmlNode *parent,
rpm-build 3ee90c
                         const char *source)
rpm-build 3ee90c
{
rpm-build 3ee90c
    const char *value = NULL;
rpm-build 3ee90c
    xmlNode *node_state;
rpm-build 3ee90c
rpm-build 3ee90c
    if (!node->state) {
rpm-build 3ee90c
        crm_info("Node update for %s cancelled: no state, not seen yet", node->uname);
rpm-build 3ee90c
       return NULL;
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    node_state = create_xml_node(parent, XML_CIB_TAG_STATE);
rpm-build 3ee90c
rpm-build 3ee90c
    if (is_set(node->flags, crm_remote_node)) {
rpm-build 3ee90c
        crm_xml_add(node_state, XML_NODE_IS_REMOTE, XML_BOOLEAN_TRUE);
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    set_uuid(node_state, XML_ATTR_UUID, node);
rpm-build 3ee90c
rpm-build 3ee90c
    if (crm_element_value(node_state, XML_ATTR_UUID) == NULL) {
rpm-build 3ee90c
        crm_info("Node update for %s cancelled: no id", node->uname);
rpm-build 3ee90c
        free_xml(node_state);
rpm-build 3ee90c
        return NULL;
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    crm_xml_add(node_state, XML_ATTR_UNAME, node->uname);
rpm-build 3ee90c
rpm-build 3ee90c
    if ((flags & node_update_cluster) && node->state) {
rpm-build 3ee90c
        crm_xml_add_boolean(node_state, XML_NODE_IN_CLUSTER,
rpm-build 3ee90c
                            safe_str_eq(node->state, CRM_NODE_MEMBER));
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    if (!is_set(node->flags, crm_remote_node)) {
rpm-build 3ee90c
        if (flags & node_update_peer) {
rpm-build 3ee90c
            value = OFFLINESTATUS;
rpm-build 3ee90c
            if (is_set(node->processes, crm_get_cluster_proc())) {
rpm-build 3ee90c
                value = ONLINESTATUS;
rpm-build 3ee90c
            }
rpm-build 3ee90c
            crm_xml_add(node_state, XML_NODE_IS_PEER, value);
rpm-build 3ee90c
        }
rpm-build 3ee90c
rpm-build 3ee90c
        if (flags & node_update_join) {
rpm-build 3ee90c
            if (node->join <= crm_join_none) {
rpm-build 3ee90c
                value = CRMD_JOINSTATE_DOWN;
rpm-build 3ee90c
            } else {
rpm-build 3ee90c
                value = CRMD_JOINSTATE_MEMBER;
rpm-build 3ee90c
            }
rpm-build 3ee90c
            crm_xml_add(node_state, XML_NODE_JOIN_STATE, value);
rpm-build 3ee90c
        }
rpm-build 3ee90c
rpm-build 3ee90c
        if (flags & node_update_expected) {
rpm-build 3ee90c
            crm_xml_add(node_state, XML_NODE_EXPECTED, node->expected);
rpm-build 3ee90c
        }
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    crm_xml_add(node_state, XML_ATTR_ORIGIN, source);
rpm-build 3ee90c
rpm-build 3ee90c
    return node_state;
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
static void
rpm-build 3ee90c
remove_conflicting_node_callback(xmlNode * msg, int call_id, int rc,
rpm-build 3ee90c
                                 xmlNode * output, void *user_data)
rpm-build 3ee90c
{
rpm-build 3ee90c
    char *node_uuid = user_data;
rpm-build 3ee90c
rpm-build 3ee90c
    do_crm_log_unlikely(rc == 0 ? LOG_DEBUG : LOG_NOTICE,
rpm-build 3ee90c
                        "Deletion of the unknown conflicting node \"%s\": %s (rc=%d)",
rpm-build 3ee90c
                        node_uuid, pcmk_strerror(rc), rc);
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
static void
rpm-build 3ee90c
search_conflicting_node_callback(xmlNode * msg, int call_id, int rc,
rpm-build 3ee90c
                                 xmlNode * output, void *user_data)
rpm-build 3ee90c
{
rpm-build 3ee90c
    char *new_node_uuid = user_data;
rpm-build 3ee90c
    xmlNode *node_xml = NULL;
rpm-build 3ee90c
rpm-build 3ee90c
    if (rc != pcmk_ok) {
rpm-build 3ee90c
        if (rc != -ENXIO) {
rpm-build 3ee90c
            crm_notice("Searching conflicting nodes for %s failed: %s (%d)",
rpm-build 3ee90c
                       new_node_uuid, pcmk_strerror(rc), rc);
rpm-build 3ee90c
        }
rpm-build 3ee90c
        return;
rpm-build 3ee90c
rpm-build 3ee90c
    } else if (output == NULL) {
rpm-build 3ee90c
        return;
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    if (safe_str_eq(crm_element_name(output), XML_CIB_TAG_NODE)) {
rpm-build 3ee90c
        node_xml = output;
rpm-build 3ee90c
rpm-build 3ee90c
    } else {
rpm-build 3ee90c
        node_xml = __xml_first_child(output);
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    for (; node_xml != NULL; node_xml = __xml_next(node_xml)) {
rpm-build 3ee90c
        const char *node_uuid = NULL;
rpm-build 3ee90c
        const char *node_uname = NULL;
rpm-build 3ee90c
        GHashTableIter iter;
rpm-build 3ee90c
        crm_node_t *node = NULL;
rpm-build 3ee90c
        gboolean known = FALSE;
rpm-build 3ee90c
rpm-build 3ee90c
        if (safe_str_neq(crm_element_name(node_xml), XML_CIB_TAG_NODE)) {
rpm-build 3ee90c
            continue;
rpm-build 3ee90c
        }
rpm-build 3ee90c
rpm-build 3ee90c
        node_uuid = crm_element_value(node_xml, XML_ATTR_ID);
rpm-build 3ee90c
        node_uname = crm_element_value(node_xml, XML_ATTR_UNAME);
rpm-build 3ee90c
rpm-build 3ee90c
        if (node_uuid == NULL || node_uname == NULL) {
rpm-build 3ee90c
            continue;
rpm-build 3ee90c
        }
rpm-build 3ee90c
rpm-build 3ee90c
        g_hash_table_iter_init(&iter, crm_peer_cache);
rpm-build 3ee90c
        while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
rpm-build 3ee90c
            if (node->uuid
rpm-build 3ee90c
                && safe_str_eq(node->uuid, node_uuid)
rpm-build 3ee90c
                && node->uname
rpm-build 3ee90c
                && safe_str_eq(node->uname, node_uname)) {
rpm-build 3ee90c
rpm-build 3ee90c
                known = TRUE;
rpm-build 3ee90c
                break;
rpm-build 3ee90c
            }
rpm-build 3ee90c
        }
rpm-build 3ee90c
rpm-build 3ee90c
        if (known == FALSE) {
rpm-build 3ee90c
            int delete_call_id = 0;
rpm-build 3ee90c
            xmlNode *node_state_xml = NULL;
rpm-build 3ee90c
rpm-build 3ee90c
            crm_notice("Deleting unknown node %s/%s which has conflicting uname with %s",
rpm-build 3ee90c
                       node_uuid, node_uname, new_node_uuid);
rpm-build 3ee90c
rpm-build 3ee90c
            delete_call_id = fsa_cib_conn->cmds->remove(fsa_cib_conn, XML_CIB_TAG_NODES, node_xml,
rpm-build 3ee90c
                                                        cib_scope_local | cib_quorum_override);
rpm-build 3ee90c
            fsa_register_cib_callback(delete_call_id, FALSE, strdup(node_uuid),
rpm-build 3ee90c
                                      remove_conflicting_node_callback);
rpm-build 3ee90c
rpm-build 3ee90c
            node_state_xml = create_xml_node(NULL, XML_CIB_TAG_STATE);
rpm-build 3ee90c
            crm_xml_add(node_state_xml, XML_ATTR_ID, node_uuid);
rpm-build 3ee90c
            crm_xml_add(node_state_xml, XML_ATTR_UNAME, node_uname);
rpm-build 3ee90c
rpm-build 3ee90c
            delete_call_id = fsa_cib_conn->cmds->remove(fsa_cib_conn, XML_CIB_TAG_STATUS, node_state_xml,
rpm-build 3ee90c
                                                        cib_scope_local | cib_quorum_override);
rpm-build 3ee90c
            fsa_register_cib_callback(delete_call_id, FALSE, strdup(node_uuid),
rpm-build 3ee90c
                                      remove_conflicting_node_callback);
rpm-build 3ee90c
            free_xml(node_state_xml);
rpm-build 3ee90c
        }
rpm-build 3ee90c
    }
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
static void
rpm-build 3ee90c
node_list_update_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
rpm-build 3ee90c
{
rpm-build 3ee90c
    fsa_data_t *msg_data = NULL;
rpm-build 3ee90c
rpm-build 3ee90c
    if(call_id < pcmk_ok) {
rpm-build 3ee90c
        crm_err("Node list update failed: %s (%d)", pcmk_strerror(call_id), call_id);
rpm-build 3ee90c
        crm_log_xml_debug(msg, "update:failed");
rpm-build 3ee90c
        register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
rpm-build 3ee90c
rpm-build 3ee90c
    } else if(rc < pcmk_ok) {
rpm-build 3ee90c
        crm_err("Node update %d failed: %s (%d)", call_id, pcmk_strerror(rc), rc);
rpm-build 3ee90c
        crm_log_xml_debug(msg, "update:failed");
rpm-build 3ee90c
        register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
rpm-build 3ee90c
    }
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
#define NODE_PATH_MAX 512
rpm-build 3ee90c
rpm-build 3ee90c
void
rpm-build 3ee90c
populate_cib_nodes(enum node_update_flags flags, const char *source)
rpm-build 3ee90c
{
rpm-build 3ee90c
    int call_id = 0;
rpm-build 3ee90c
    gboolean from_hashtable = TRUE;
rpm-build 3ee90c
    int call_options = cib_scope_local | cib_quorum_override;
rpm-build 3ee90c
    xmlNode *node_list = create_xml_node(NULL, XML_CIB_TAG_NODES);
rpm-build 3ee90c
rpm-build 3ee90c
#if SUPPORT_COROSYNC
rpm-build 3ee90c
    if (is_not_set(flags, node_update_quick) && is_corosync_cluster()) {
rpm-build 3ee90c
        from_hashtable = corosync_initialize_nodelist(NULL, FALSE, node_list);
rpm-build 3ee90c
    }
rpm-build 3ee90c
#endif
rpm-build 3ee90c
rpm-build 3ee90c
    if (from_hashtable) {
rpm-build 3ee90c
        GHashTableIter iter;
rpm-build 3ee90c
        crm_node_t *node = NULL;
rpm-build 3ee90c
rpm-build 3ee90c
        g_hash_table_iter_init(&iter, crm_peer_cache);
rpm-build 3ee90c
        while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
rpm-build 3ee90c
            xmlNode *new_node = NULL;
rpm-build 3ee90c
rpm-build 3ee90c
            crm_trace("Creating node entry for %s/%s", node->uname, node->uuid);
rpm-build 3ee90c
            if(node->uuid && node->uname) {
rpm-build 3ee90c
                char xpath[NODE_PATH_MAX];
rpm-build 3ee90c
rpm-build 3ee90c
                /* We need both to be valid */
rpm-build 3ee90c
                new_node = create_xml_node(node_list, XML_CIB_TAG_NODE);
rpm-build 3ee90c
                crm_xml_add(new_node, XML_ATTR_ID, node->uuid);
rpm-build 3ee90c
                crm_xml_add(new_node, XML_ATTR_UNAME, node->uname);
rpm-build 3ee90c
rpm-build 3ee90c
                /* Search and remove unknown nodes with the conflicting uname from CIB */
rpm-build 3ee90c
                snprintf(xpath, NODE_PATH_MAX,
rpm-build 3ee90c
                         "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_NODES
rpm-build 3ee90c
                         "/" XML_CIB_TAG_NODE "[@uname='%s'][@id!='%s']",
rpm-build 3ee90c
                         node->uname, node->uuid);
rpm-build 3ee90c
rpm-build 3ee90c
                call_id = fsa_cib_conn->cmds->query(fsa_cib_conn, xpath, NULL,
rpm-build 3ee90c
                                                    cib_scope_local | cib_xpath);
rpm-build 3ee90c
                fsa_register_cib_callback(call_id, FALSE, strdup(node->uuid),
rpm-build 3ee90c
                                          search_conflicting_node_callback);
rpm-build 3ee90c
            }
rpm-build 3ee90c
        }
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    crm_trace("Populating <nodes> section from %s", from_hashtable ? "hashtable" : "cluster");
rpm-build 3ee90c
rpm-build 3ee90c
    fsa_cib_update(XML_CIB_TAG_NODES, node_list, call_options, call_id, NULL);
rpm-build 3ee90c
    fsa_register_cib_callback(call_id, FALSE, NULL, node_list_update_callback);
rpm-build 3ee90c
rpm-build 3ee90c
    free_xml(node_list);
rpm-build 3ee90c
rpm-build 3ee90c
    if (call_id >= pcmk_ok && crm_peer_cache != NULL && AM_I_DC) {
rpm-build 3ee90c
        /*
rpm-build 3ee90c
         * There is no need to update the local CIB with our values if
rpm-build 3ee90c
         * we've not seen valid membership data
rpm-build 3ee90c
         */
rpm-build 3ee90c
        GHashTableIter iter;
rpm-build 3ee90c
        crm_node_t *node = NULL;
rpm-build 3ee90c
rpm-build 3ee90c
        node_list = create_xml_node(NULL, XML_CIB_TAG_STATUS);
rpm-build 3ee90c
rpm-build 3ee90c
        g_hash_table_iter_init(&iter, crm_peer_cache);
rpm-build 3ee90c
        while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
rpm-build 3ee90c
            create_node_state_update(node, flags, node_list, source);
rpm-build 3ee90c
        }
rpm-build 3ee90c
rpm-build 3ee90c
        if (crm_remote_peer_cache) {
rpm-build 3ee90c
            g_hash_table_iter_init(&iter, crm_remote_peer_cache);
rpm-build 3ee90c
            while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
rpm-build 3ee90c
                create_node_state_update(node, flags, node_list, source);
rpm-build 3ee90c
            }
rpm-build 3ee90c
        }
rpm-build 3ee90c
rpm-build 3ee90c
        fsa_cib_update(XML_CIB_TAG_STATUS, node_list, call_options, call_id, NULL);
rpm-build 3ee90c
        fsa_register_cib_callback(call_id, FALSE, NULL, crmd_node_update_complete);
rpm-build 3ee90c
        last_peer_update = call_id;
rpm-build 3ee90c
rpm-build 3ee90c
        free_xml(node_list);
rpm-build 3ee90c
    }
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
static void
rpm-build 3ee90c
cib_quorum_update_complete(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
rpm-build 3ee90c
{
rpm-build 3ee90c
    fsa_data_t *msg_data = NULL;
rpm-build 3ee90c
rpm-build 3ee90c
    if (rc == pcmk_ok) {
rpm-build 3ee90c
        crm_trace("Quorum update %d complete", call_id);
rpm-build 3ee90c
rpm-build 3ee90c
    } else {
rpm-build 3ee90c
        crm_err("Quorum update %d failed: %s (%d)", call_id, pcmk_strerror(rc), rc);
rpm-build 3ee90c
        crm_log_xml_debug(msg, "failed");
rpm-build 3ee90c
        register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
rpm-build 3ee90c
    }
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
void
rpm-build 3ee90c
crm_update_quorum(gboolean quorum, gboolean force_update)
rpm-build 3ee90c
{
rpm-build 3ee90c
    ever_had_quorum |= quorum;
rpm-build 3ee90c
rpm-build 3ee90c
    if(ever_had_quorum && quorum == FALSE && no_quorum_suicide_escalation) {
rpm-build 3ee90c
        pcmk_panic(__FUNCTION__);
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    if (AM_I_DC && (force_update || fsa_has_quorum != quorum)) {
rpm-build 3ee90c
        int call_id = 0;
rpm-build 3ee90c
        xmlNode *update = NULL;
rpm-build 3ee90c
        int call_options = cib_scope_local | cib_quorum_override;
rpm-build 3ee90c
rpm-build 3ee90c
        update = create_xml_node(NULL, XML_TAG_CIB);
rpm-build 3ee90c
        crm_xml_add_int(update, XML_ATTR_HAVE_QUORUM, quorum);
rpm-build 3ee90c
        crm_xml_add(update, XML_ATTR_DC_UUID, fsa_our_uuid);
rpm-build 3ee90c
rpm-build 3ee90c
        fsa_cib_update(XML_TAG_CIB, update, call_options, call_id, NULL);
rpm-build 3ee90c
        crm_debug("Updating quorum status to %s (call=%d)", quorum ? "true" : "false", call_id);
rpm-build 3ee90c
        fsa_register_cib_callback(call_id, FALSE, NULL, cib_quorum_update_complete);
rpm-build 3ee90c
        free_xml(update);
rpm-build 3ee90c
rpm-build 3ee90c
        /* Quorum changes usually cause a new transition via other activity:
rpm-build 3ee90c
         * quorum gained via a node joining will abort via the node join,
rpm-build 3ee90c
         * and quorum lost via a node leaving will usually abort via resource
rpm-build 3ee90c
         * activity and/or fencing.
rpm-build 3ee90c
         *
rpm-build 3ee90c
         * However, it is possible that nothing else causes a transition (e.g.
rpm-build 3ee90c
         * someone forces quorum via corosync-cmaptcl, or quorum is lost due to
rpm-build 3ee90c
         * a node in standby shutting down cleanly), so here ensure a new
rpm-build 3ee90c
         * transition is triggered.
rpm-build 3ee90c
         */
rpm-build 3ee90c
        if (quorum) {
rpm-build 3ee90c
            /* If quorum was gained, abort after a short delay, in case multiple
rpm-build 3ee90c
             * nodes are joining around the same time, so the one that brings us
rpm-build 3ee90c
             * to quorum doesn't cause all the remaining ones to be fenced.
rpm-build 3ee90c
             */
rpm-build 3ee90c
            abort_after_delay(INFINITY, tg_restart, "Quorum gained", 5000);
rpm-build 3ee90c
        } else {
rpm-build 3ee90c
            abort_transition(INFINITY, tg_restart, "Quorum lost", NULL);
rpm-build 3ee90c
        }
rpm-build 3ee90c
    }
rpm-build 3ee90c
    fsa_has_quorum = quorum;
rpm-build 3ee90c
}