Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4624470
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/crm/crmd/join_dc.c b/crm/crmd/join_dc.c
index ee837c92ca..ca195d6a8f 100644
--- a/crm/crmd/join_dc.c
+++ b/crm/crmd/join_dc.c
@@ -1,525 +1,529 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#include <heartbeat.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crmd_fsa.h>
#include <crmd_messages.h>
#include <crm/dmalloc_wrapper.h>
int num_join_invites = 0;
GHashTable *join_offers = NULL;
GHashTable *join_requests = NULL;
GHashTable *confirmed_nodes = NULL;
xmlNodePtr our_generation = NULL;
const char *max_generation_from = NULL;
void initialize_join(gboolean before);
void finalize_join_for(gpointer key, gpointer value, gpointer user_data);
void join_send_offer(gpointer key, gpointer value, gpointer user_data);
/* A_DC_JOIN_OFFER_ALL */
enum crmd_fsa_input
do_dc_join_offer_all(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
/* reset everyones status back to down or in_ccm in the CIB */
xmlNodePtr update = NULL;
xmlNodePtr cib_copy = get_cib_copy(fsa_cib_conn);
xmlNodePtr tmp1 = get_object_root(XML_CIB_TAG_STATUS, cib_copy);
xmlNodePtr tmp2 = NULL;
/* catch any nodes that are active in the CIB but not in the CCM list*/
xml_child_iter(
tmp1, node_entry, XML_CIB_TAG_STATE,
const char *node_id = xmlGetProp(node_entry, XML_ATTR_UNAME);
gpointer a_node = g_hash_table_lookup(
fsa_membership_copy->members, node_id);
if(a_node != NULL || (safe_str_eq(fsa_our_uname, node_id))) {
/* handled by do_update_cib_node() */
continue;
}
tmp2 = create_node_state(
node_id, node_id, NULL,
XML_BOOLEAN_NO, NULL, CRMD_JOINSTATE_PENDING, NULL);
if(update == NULL) {
update = tmp2;
} else {
update = xmlAddSibling(update, tmp2);
}
);
/* now process the CCM data */
free_xml(do_update_cib_nodes(update, TRUE));
free_xml(cib_copy);
#if 0
/* Avoid ordered message delays caused when the CRMd proc
* isnt running yet (ie. send as a broadcast msg which are never
* sent ordered.
*/
send_request(NULL, NULL, CRM_OP_WELCOME,
NULL, CRM_SYSTEM_CRMD, NULL);
#else
crm_debug("Offering membership to %d clients",
fsa_membership_copy->members_size);
g_hash_table_foreach(fsa_membership_copy->members,
join_send_offer, NULL);
#endif
/* No point hanging around in S_INTEGRATION if we're the only ones here! */
if(g_hash_table_size(join_requests)
>= fsa_membership_copy->members_size) {
crm_info("Not expecting any join acks");
register_fsa_input(C_FSA_INTERNAL, I_INTEGRATED, NULL);
return I_NULL;
}
/* dont waste time by invoking the pe yet; */
crm_debug("Still waiting on %d outstanding join acks",
fsa_membership_copy->members_size
- g_hash_table_size(join_requests));
return I_NULL;
}
/* A_DC_JOIN_OFFER_ONE */
enum crmd_fsa_input
do_dc_join_offer_one(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
gpointer a_node = NULL;
xmlNodePtr welcome = NULL;
const char *join_to = NULL;
if(msg_data->data == NULL) {
crm_err("Attempt to send welcome message "
"without a message to reply to!");
return I_NULL;
}
welcome = (xmlNodePtr)msg_data->data;
join_to = xmlGetProp(welcome, XML_ATTR_HOSTFROM);
a_node = g_hash_table_lookup(join_requests, join_to);
if(a_node != NULL
&& (cur_state == S_INTEGRATION || cur_state == S_FINALIZE_JOIN)) {
/* note: it _is_ possible that a node will have been
* sick or starting up when the original offer was made.
* however, it will either re-announce itself in due course
* _or_ we can re-store the original offer on the client.
*/
crm_warn("Already offered membership to %s... discarding",
join_to);
/* Make sure we end up in the correct state again */
if(g_hash_table_size(join_requests)
>= fsa_membership_copy->members_size) {
crm_info("False alarm, returning to %s",
fsa_state2string(S_FINALIZE_JOIN));
register_fsa_input(C_FSA_INTERNAL, I_INTEGRATED, NULL);
return I_NULL;
}
crm_debug("Still waiting on %d outstanding join acks",
fsa_membership_copy->members_size
- g_hash_table_size(join_requests));
} else {
oc_node_t member;
crm_debug("Processing annouce request from %s in state %s",
join_to, fsa_state2string(cur_state));
member.node_uname = crm_strdup(join_to);
join_send_offer(NULL, &member, NULL);
crm_free(member.node_uname);
/* this was a genuine join request, cancel any existing
* transition and invoke the PE
*/
register_fsa_input_w_actions(
msg_data->fsa_cause, I_NULL, NULL, A_TE_CANCEL);
}
return I_NULL;
}
/* A_DC_JOIN_PROCESS_REQ */
enum crmd_fsa_input
do_dc_join_req(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
xmlNodePtr generation;
xmlNodePtr join_ack = (xmlNodePtr)msg_data->data;
const char *ack_nack = CRMD_JOINSTATE_MEMBER;
gboolean is_a_member = FALSE;
const char *join_from = xmlGetProp(join_ack, XML_ATTR_HOSTFROM);
const char *ref = xmlGetProp(join_ack, XML_ATTR_REFERENCE);
gpointer join_node =
g_hash_table_lookup(fsa_membership_copy->members, join_from);
crm_debug("Processing req from %s", join_from);
if(join_node != NULL) {
is_a_member = TRUE;
}
generation = find_xml_node(join_ack, "generation_tuple");
if(cib_compare_generation(our_generation, generation) < 0) {
clear_bit_inplace(fsa_input_register, R_HAVE_CIB);
crm_debug("%s has a better generation number than us",
join_from);
crm_xml_debug(our_generation, "Our generation");
crm_xml_debug(generation, "Their generation");
max_generation_from = join_from;
}
crm_debug("Welcoming node %s after ACK (ref %s)", join_from, ref);
if(is_a_member == FALSE) {
/* nack them now so they are not counted towards the
* expected responses
*/
char *local_from = crm_strdup(join_from);
char *local_down = crm_strdup(CRMD_JOINSTATE_DOWN);
crm_err("Node %s is not known to us (ref %s)", join_from, ref);
finalize_join_for(local_from, local_down, NULL);
crm_free(local_from);
crm_free(local_down);
return I_FAIL;
} else if(/* some reason */ 0) {
/* NACK this client */
ack_nack = CRMD_JOINSTATE_DOWN;
}
/* add them to our list of CRMD_STATE_ACTIVE nodes
TODO: check its not already there
*/
g_hash_table_insert(
join_requests, crm_strdup(join_from), crm_strdup(ack_nack));
if(g_hash_table_size(join_requests)
>= fsa_membership_copy->members_size) {
crm_info("That was the last outstanding join ack");
register_fsa_input(C_FSA_INTERNAL, I_INTEGRATED, NULL);
return I_NULL;
}
/* dont waste time by invoking the PE yet; */
crm_debug("Still waiting on %d (of %d) outstanding join acks",
fsa_membership_copy->members_size
- g_hash_table_size(join_requests),
fsa_membership_copy->members_size);
return I_NULL;
}
/* A_DC_JOIN_FINALIZE */
enum crmd_fsa_input
do_dc_join_finalize(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
if(max_generation_from == NULL) {
crm_warn("There is no CIB to get..."
" how did R_HAVE_CIB get unset?");
set_bit_inplace(fsa_input_register, R_HAVE_CIB);
}
if(! is_set(fsa_input_register, R_HAVE_CIB)) {
/* ask for the agreed best CIB */
enum cib_errors rc = cib_ok;
crm_info("Asking %s for its copy of the CIB",
crm_str(max_generation_from));
rc = fsa_cib_conn->cmds->sync_from(
fsa_cib_conn, max_generation_from, NULL, cib_sync_call);
if(rc != cib_ok) {
return I_FAIL;
}
}
fsa_cib_conn->cmds->bump_epoch(
- fsa_cib_conn, cib_scope_local|cib_sync_call|cib_discard_reply);
+ fsa_cib_conn, cib_scope_local|cib_sync_call);
fsa_cib_conn->cmds->sync(fsa_cib_conn, NULL, cib_sync_call);
num_join_invites = 0;
crm_debug("Notifying %d clients of join results",
g_hash_table_size(join_requests));
g_hash_table_foreach(join_requests, finalize_join_for, NULL);
if(num_join_invites <= g_hash_table_size(confirmed_nodes)) {
crm_info("Not expecting any join confirmations");
register_fsa_input(C_FSA_INTERNAL, I_FINALIZED, NULL);
return I_NULL;
}
/* dont waste time by invoking the PE yet; */
crm_debug("Still waiting on %d outstanding join confirmations",
num_join_invites - g_hash_table_size(confirmed_nodes));
return I_NULL;
}
/* A_DC_JOIN_PROCESS_ACK */
enum crmd_fsa_input
do_dc_join_ack(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
/* now update them to "member" */
xmlNodePtr tmp1 = NULL, update = NULL;
xmlNodePtr join_ack = (xmlNodePtr)msg_data->data;
const char *join_from = xmlGetProp(join_ack, XML_ATTR_HOSTFROM);
const char *join_state = NULL;
crm_debug("Processing ack from %s", join_from);
join_state = (const char *)
g_hash_table_lookup(join_requests, join_from);
if(join_state == NULL) {
crm_err("Join not in progress: ignoring join from %s",
join_from);
return I_FAIL;
} else if(safe_str_neq(join_state, CRMD_JOINSTATE_MEMBER)) {
crm_err("Node %s wasnt invited to join the cluster",join_from);
return I_NULL;
}
g_hash_table_insert(confirmed_nodes, crm_strdup(join_from),
crm_strdup(CRMD_JOINSTATE_MEMBER));
/* update node entry in the status section */
crm_debug("Updating node state to %s for %s", join_state, join_from);
update = create_node_state(
join_from, join_from,
ACTIVESTATUS, NULL, ONLINESTATUS, join_state, join_state);
set_xml_property_copy(update,XML_CIB_ATTR_EXPSTATE, CRMD_STATE_ACTIVE);
tmp1 = create_cib_fragment(update, NULL);
update_local_cib(tmp1, TRUE);
free_xml(tmp1);
+ /* update CIB with the current LRM status from the node */
+ tmp1 = find_xml_node(join_ack, XML_TAG_FRAGMENT);
+ update_local_cib(tmp1, TRUE);
+
if(num_join_invites <= g_hash_table_size(confirmed_nodes)) {
crm_info("That was the last outstanding join confirmation");
register_fsa_input_later(C_FSA_INTERNAL, I_FINALIZED, NULL);
return I_NULL;
}
/* dont waste time by invoking the pe yet; */
crm_debug("Still waiting on %d outstanding join confirmations",
num_join_invites - g_hash_table_size(confirmed_nodes));
return I_NULL;
}
void
finalize_join_for(gpointer key, gpointer value, gpointer user_data)
{
xmlNodePtr tmp1 = NULL;
xmlNodePtr tmp2 = NULL;
xmlNodePtr cib_copy = NULL;
xmlNodePtr options = NULL;
const char *join_to = NULL;
const char *join_state = NULL;
if(key == NULL || value == NULL) {
return;
}
options = create_xml_node(NULL, XML_TAG_OPTIONS);
join_to = (const char *)key;
join_state = (const char *)value;
/* make sure the node exists in the config section */
create_node_entry(join_to, join_to, CRMD_JOINSTATE_MEMBER);
/* perhaps we shouldnt special case this... */
if(safe_str_eq(join_to, fsa_our_uname)) {
/* mark ourselves confirmed */
g_hash_table_insert(confirmed_nodes, crm_strdup(fsa_our_uname),
crm_strdup(CRMD_JOINSTATE_MEMBER));
/* make sure our cluster state is set correctly */
tmp1 = create_node_state(
join_to, join_to, ACTIVESTATUS,
NULL, ONLINESTATUS, join_state, join_state);
if(tmp1 != NULL) {
tmp2 = create_cib_fragment(tmp1, NULL);
update_local_cib(tmp2, TRUE);
free_xml(tmp2);
free_xml(tmp1);
} else {
crm_err("Could not create our node state");
/* TODO: raise an error input */
}
/* update our LRM data */
tmp1 = do_lrm_query(TRUE);
if(tmp1 != NULL) {
update_local_cib(tmp1, TRUE);
free_xml(tmp1);
} else {
crm_err("Could not determin current LRM state");
/* TODO: raise an error input */
}
num_join_invites++;
crm_info("Completed local cluster membership");
return;
}
/* create the ack/nack */
if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) {
num_join_invites++;
set_xml_property_copy(
options, CRM_OP_JOINACK, XML_BOOLEAN_TRUE);
} else {
crm_info("NACK'ing join request from %s, state %s",
join_to, join_state);
set_xml_property_copy(
options, CRM_OP_JOINACK, XML_BOOLEAN_FALSE);
}
/* send the CIB to the node */
cib_copy = get_cib_copy(fsa_cib_conn);
send_request(NULL, cib_copy, CRM_OP_CIB_REPLACE,
join_to, CRM_SYSTEM_CRMD, NULL);
free_xml(cib_copy);
/* send the ack/nack to the node */
send_request(options, NULL, CRM_OP_JOINACK,
join_to, CRM_SYSTEM_CRMD, NULL);
}
void
initialize_join(gboolean before)
{
/* clear out/reset a bunch of stuff */
if(join_offers != NULL) {
g_hash_table_destroy(join_offers);
}
if(join_requests != NULL) {
g_hash_table_destroy(join_requests);
}
if(confirmed_nodes != NULL) {
g_hash_table_destroy(confirmed_nodes);
}
if(before) {
free_xml(our_generation);
our_generation = cib_get_generation(fsa_cib_conn);
max_generation_from = NULL;
set_bit_inplace(fsa_input_register, R_HAVE_CIB);
clear_bit_inplace(fsa_input_register, R_CIB_ASKED);
}
join_offers = g_hash_table_new(&g_str_hash, &g_str_equal);
join_requests = g_hash_table_new(&g_str_hash, &g_str_equal);
confirmed_nodes = g_hash_table_new(&g_str_hash, &g_str_equal);
/* mark ourselves joined */
g_hash_table_insert(join_requests, crm_strdup(fsa_our_uname),
crm_strdup(CRMD_JOINSTATE_MEMBER));
}
void
join_send_offer(gpointer key, gpointer value, gpointer user_data)
{
const char *join_to = NULL;
const oc_node_t *member = (const oc_node_t*)value;
crm_debug("Sending %s offer", CRM_OP_WELCOME);
if(member != NULL) {
join_to = member->node_uname;
}
if(join_to == NULL) {
crm_err("No recipient for welcome message");
} else if(safe_str_eq(join_to, fsa_our_uname)) {
crm_debug("Skipping %s msg for ourselves (%s)",
CRM_OP_WELCOME, join_to);
} else {
/* send the welcome */
crm_debug("Sending %s to %s", CRM_OP_WELCOME, join_to);
send_request(NULL, NULL, CRM_OP_WELCOME,
join_to, CRM_SYSTEM_CRMD, NULL);
g_hash_table_insert(join_offers, crm_strdup(join_to),
crm_strdup(CRMD_JOINSTATE_PENDING));
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Jul 8, 6:25 PM (7 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2002636
Default Alt Text
(15 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment