Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/crm/crmd/cib.c b/crm/crmd/cib.c
index 02bc798600..237961a27d 100644
--- a/crm/crmd/cib.c
+++ b/crm/crmd/cib.c
@@ -1,351 +1,350 @@
/*
* 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 <sys/param.h>
#include <crm/crm.h>
#include <crmd_fsa.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h> /* for access */
#include <clplumbing/cl_signal.h>
#include <clplumbing/realtime.h>
#include <sys/types.h> /* for calls to open */
#include <sys/stat.h> /* for calls to open */
#include <fcntl.h> /* for calls to open */
#include <pwd.h> /* for getpwuid */
#include <grp.h> /* for initgroups */
#include <sys/time.h> /* for getrlimit */
#include <sys/resource.h>/* for getrlimit */
#include <errno.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crmd_messages.h>
#include <crmd_callbacks.h>
#include <crm/cib.h>
#include <crmd.h>
#include <crm/dmalloc_wrapper.h>
struct crm_subsystem_s *cib_subsystem = NULL;
typedef struct cib_callback_blob_s
{
void (*callback)(
const HA_Message*, int, int, crm_data_t*, void*);
void *user_data;
gboolean only_success;
} cib_callback_blob_t;
void crmd_cib_op_callback(
const HA_Message *msg, int call_id, int rc, crm_data_t *output);
int cib_retries = 0;
GHashTable *cib_callback_table = NULL;
/* A_CIB_STOP, A_CIB_START, A_CIB_RESTART, */
enum crmd_fsa_input
do_cib_control(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)
{
enum crmd_fsa_input result = I_NULL;
struct crm_subsystem_s *this_subsys = cib_subsystem;
long long stop_actions = A_CIB_STOP;
long long start_actions = A_CIB_START;
if(action & stop_actions) {
if(fsa_cib_conn != NULL
&& fsa_cib_conn->state != cib_disconnected) {
fsa_cib_conn->cmds->signoff(fsa_cib_conn);
}
}
if(action & start_actions) {
if(cib_callback_table == NULL) {
cib_callback_table = g_hash_table_new_full(
g_direct_hash, g_direct_equal,
NULL, g_hash_destroy_str);
}
if(cur_state != S_STOPPING) {
if(fsa_cib_conn == NULL) {
fsa_cib_conn = cib_new();
}
if(cib_ok != fsa_cib_conn->cmds->signon(
fsa_cib_conn, CRM_SYSTEM_CRMD, cib_command)){
crm_debug("Could not connect to the CIB service");
} else if(cib_ok != fsa_cib_conn->cmds->set_op_callback(
fsa_cib_conn, crmd_cib_op_callback)) {
crm_err("Could not set op callback");
} else if(fsa_cib_conn->cmds->set_connection_dnotify(
fsa_cib_conn,
crmd_cib_connection_destroy)!=cib_ok){
crm_err("Could not set dnotify callback");
} else {
set_bit_inplace(
fsa_input_register, R_CIB_CONNECTED);
}
if(is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) {
cib_retries++;
crm_warn("Could complete CIB registration %d"
" times... pause and retry",
cib_retries);
if(cib_retries < 30) {
crm_timer_start(wait_timer);
crmd_fsa_stall();
} else {
crm_err("Could not complete CIB"
" registration %d times..."
" hard error", cib_retries);
register_fsa_error(
C_FSA_INTERNAL, I_ERROR, NULL);
}
} else {
cib_retries = 0;
}
} else {
crm_info("Ignoring request to start %s after shutdown",
this_subsys->name);
}
}
return result;
}
/* A_CIB_INVOKE, A_CIB_BUMPGEN, A_UPDATE_NODESTATUS */
enum crmd_fsa_input
do_cib_invoke(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)
{
HA_Message *answer = NULL;
enum crmd_fsa_input result = I_NULL;
ha_msg_input_t *cib_msg = fsa_typed_data(fsa_dt_ha_msg);
const char *sys_from = cl_get_string(cib_msg->msg, F_CRM_SYS_FROM);
if(fsa_cib_conn->state == cib_disconnected) {
if(cur_state != S_STOPPING) {
crm_err("CIB is disconnected");
crm_log_message_adv(LOG_WARNING, "CIB Input", cib_msg->msg);
return I_NULL;
}
crm_info("CIB is disconnected");
crm_log_message_adv(LOG_DEBUG, "CIB Input", cib_msg->msg);
return I_NULL;
}
if(action & A_CIB_INVOKE) {
if(safe_str_eq(sys_from, CRM_SYSTEM_CRMD)) {
action = A_CIB_INVOKE_LOCAL;
} else if(safe_str_eq(sys_from, CRM_SYSTEM_DC)) {
action = A_CIB_INVOKE_LOCAL;
}
}
if(action & A_CIB_INVOKE || action & A_CIB_INVOKE_LOCAL) {
int call_options = 0;
enum cib_errors rc = cib_ok;
crm_data_t *cib_frag = NULL;
const char *section = NULL;
const char *op = cl_get_string(cib_msg->msg, F_CRM_TASK);
section = cl_get_string(cib_msg->msg, F_CIB_SECTION);
ha_msg_value_int(cib_msg->msg, F_CIB_CALLOPTS, &call_options);
crm_log_message(LOG_MSG, cib_msg->msg);
crm_xml_devel(cib_msg->xml, "[CIB update]");
if(op == NULL) {
crm_err("Invalid CIB Message");
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
return I_NULL;
}
cib_frag = NULL;
rc = fsa_cib_conn->cmds->variant_op(
fsa_cib_conn, op, NULL, section,
cib_msg->xml, &cib_frag, call_options);
if(rc < cib_ok || (action & A_CIB_INVOKE)) {
answer = create_reply(cib_msg->msg, cib_frag);
ha_msg_add(answer,XML_ATTR_RESULT,cib_error2string(rc));
}
if(action & A_CIB_INVOKE) {
if(relay_message(answer, TRUE) == FALSE) {
crm_err("Confused what to do with cib result");
crm_log_message(LOG_ERR, answer);
crm_msg_del(answer);
result = I_ERROR;
}
} else if(rc < cib_ok) {
ha_msg_input_t *input = NULL;
crm_err("Internal CRM/CIB command from %s() failed: %s",
msg_data->origin, cib_error2string(rc));
crm_log_message_adv(LOG_WARNING, "CIB Input", cib_msg->msg);
crm_log_message_adv(LOG_WARNING, "CIB Reply", answer);
input = new_ha_msg_input(answer);
register_fsa_input(C_FSA_INTERNAL, I_ERROR, input);
crm_msg_del(answer);
delete_ha_msg_input(input);
}
return result;
} else {
crm_err("Unexpected action %s in %s",
fsa_action2string(action), __FUNCTION__);
}
return I_NULL;
}
/* frees fragment as part of delete_ha_msg_input() */
void
update_local_cib_adv(
crm_data_t *msg_data, gboolean do_now, const char *raised_from)
{
HA_Message *msg = NULL;
ha_msg_input_t *fsa_input = NULL;
- int call_options = 0;
-/* int call_options = cib_sync_call; */
+ int call_options = cib_quorum_override;
CRM_DEV_ASSERT(msg_data != NULL);
crm_malloc(fsa_input, sizeof(ha_msg_input_t));
msg = create_request(CRM_OP_CIB_UPDATE, msg_data, NULL,
CRM_SYSTEM_CIB, CRM_SYSTEM_CRMD, NULL);
ha_msg_add(msg, F_CIB_SECTION,
crm_element_value(msg_data, XML_ATTR_SECTION));
ha_msg_add_int(msg, F_CIB_CALLOPTS, call_options);
ha_msg_add(msg, "call_origin", raised_from);
fsa_input->msg = msg;
fsa_input->xml = msg_data;
if(AM_I_DC && crm_assert_failed) {
/* register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); */
}
if(do_now == FALSE) {
crm_devel("Registering event with FSA");
register_fsa_input_adv(C_FSA_INTERNAL, I_CIB_OP, fsa_input, 0,
FALSE, raised_from);
} else {
fsa_data_t *op_data = NULL;
crm_devel("Invoking CIB handler directly");
crm_malloc(op_data, sizeof(fsa_data_t));
op_data->fsa_cause = C_FSA_INTERNAL;
op_data->fsa_input = I_CIB_OP;
op_data->origin = raised_from;
op_data->data = fsa_input;
op_data->data_type = fsa_dt_ha_msg;
do_cib_invoke(A_CIB_INVOKE_LOCAL, C_FSA_INTERNAL, fsa_state,
I_CIB_OP, op_data);
crm_free(op_data);
crm_devel("CIB handler completed");
}
crm_devel("deleting input");
#if 0
delete_ha_msg_input(fsa_input);
#else
crm_msg_del(fsa_input->msg);
crm_free(fsa_input);
/* BUG: it should be possible to free this but for some reason I cant */
/* free_xml(fsa_input->xml); */
#endif
crm_devel("deleted input");
}
gboolean
add_cib_op_callback(
int call_id, gboolean only_success, void *user_data,
void (*callback)(const HA_Message*, int, int, crm_data_t*,void*))
{
cib_callback_blob_t *blob = NULL;
if(call_id < 0) {
crm_warn("CIB call failed: %s", cib_error2string(call_id));
if(only_success == FALSE) {
callback(NULL, call_id, call_id, NULL, user_data);
}
return FALSE;
}
crm_malloc(blob, sizeof(cib_callback_blob_t));
blob->only_success = only_success;
blob->user_data = user_data;
blob->callback = callback;
g_hash_table_insert(
cib_callback_table, GINT_TO_POINTER(call_id), blob);
return TRUE;
}
void
crmd_cib_op_callback(
const HA_Message *msg, int call_id, int rc, crm_data_t *output)
{
cib_callback_blob_t *blob = g_hash_table_lookup(
cib_callback_table, GINT_TO_POINTER(call_id));
if(blob != NULL && (rc == cib_ok || blob->only_success == FALSE)) {
blob->callback(msg, call_id, rc, output, blob->user_data);
g_hash_table_remove(
cib_callback_table, GINT_TO_POINTER(call_id));
} else if(rc != cib_ok) {
if(blob != NULL) {
g_hash_table_remove(
cib_callback_table, GINT_TO_POINTER(call_id));
}
crm_err("CIB update failed: %s", cib_error2string(rc));
crm_log_message_adv(LOG_WARNING, "Failed CIB Update", msg);
return;
}
}
diff --git a/crm/crmd/election.c b/crm/crmd/election.c
index 3208327eb3..7b81ed49ab 100644
--- a/crm/crmd/election.c
+++ b/crm/crmd/election.c
@@ -1,435 +1,435 @@
/*
* 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/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/crm.h>
#include <crmd_fsa.h>
#include <crmd_messages.h>
#include <crmd_callbacks.h>
#include <clplumbing/Gmain_timeout.h>
#include <crm/dmalloc_wrapper.h>
uint highest_born_on = -1;
void ghash_count_vote(gpointer key, gpointer value, gpointer user_data);
void revision_check_callback(const HA_Message *msg, int call_id, int rc,
crm_data_t *output, void *user_data);
/* A_ELECTION_VOTE */
enum crmd_fsa_input
do_election_vote(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)
{
gboolean not_voting = FALSE;
HA_Message *vote = NULL;
/* dont vote if we're in one of these states or wanting to shut down */
switch(cur_state) {
case S_RECOVERY:
case S_STOPPING:
case S_TERMINATE:
crm_warn("Not voting in election, we're in state %s",
fsa_state2string(cur_state));
not_voting = TRUE;
break;
default:
break;
}
if(not_voting == FALSE) {
if(is_set(fsa_input_register, R_STARTING)) {
not_voting = TRUE;
}
}
if(not_voting) {
fsa_cib_conn->cmds->set_slave(fsa_cib_conn, cib_scope_local);
if(AM_I_DC) {
register_fsa_input(C_FSA_INTERNAL, I_RELEASE_DC, NULL);
} else {
register_fsa_input(C_FSA_INTERNAL, I_PENDING, NULL);
}
return I_NULL;
}
vote = create_request(
CRM_OP_VOTE, NULL, NULL,
CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
if(is_set(fsa_input_register, R_SHUTDOWN)) {
crm_warn("Not voting in election, we're shutting down");
cl_msg_remove(vote, F_CRM_VERSION);
}
send_request(vote, NULL);
crm_timer_start(election_timeout);
return I_NULL;
}
char *dc_hb_msg = NULL;
int beat_num = 0;
gboolean
do_dc_heartbeat(gpointer data)
{
#if 0
fsa_timer_t *timer = (fsa_timer_t *)data;
crm_devel("Sending DC Heartbeat %d", beat_num);
HA_Message *msg = ha_msg_new(5);
ha_msg_add(msg, F_TYPE, T_CRM);
ha_msg_add(msg, F_SUBTYPE, XML_ATTR_REQUEST);
ha_msg_add(msg, F_CRM_SYS_TO, CRM_SYSTEM_CRMD);
ha_msg_add(msg, F_CRM_SYS_FROM, CRM_SYSTEM_DC);
ha_msg_add(msg, F_CRM_TASK, CRM_OP_HBEAT);
ha_msg_add_int(msg, "dc_beat_seq", beat_num);
beat_num++;
if(send_msg_via_ha(fsa_cluster_conn, msg) == FALSE) {
/* this is bad */
crm_timer_stop(timer); /* make it not go off again */
register_fsa_input(C_HEARTBEAT_FAILED, I_SHUTDOWN, NULL);
G_main_set_trigger(fsa_source);
return FALSE;
}
#endif
return TRUE;
}
struct election_data_s
{
const char *winning_uname;
unsigned int winning_bornon;
};
/* A_ELECTION_COUNT */
enum crmd_fsa_input
do_election_count_vote(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)
{
gboolean we_loose = FALSE;
ha_msg_input_t *vote = fsa_typed_data(fsa_dt_ha_msg);
enum crmd_fsa_input election_result = I_NULL;
const char *vote_from = cl_get_string(vote->msg, F_CRM_HOST_FROM);
const char *your_version = cl_get_string(vote->msg, F_CRM_VERSION);
oc_node_t *our_node = NULL, * your_node = NULL;
if(vote_from == NULL || strcmp(vote_from, fsa_our_uname) == 0) {
/* dont count our own vote */
return election_result;
}
if(fsa_membership_copy == NULL) {
/* if the membership copy is NULL we REALLY shouldnt be voting
* the question is how we managed to get here.
*/
crm_err("Membership copy was NULL");
return I_NULL;
} else if(fsa_membership_copy->members != NULL) {
our_node = (oc_node_t*)
g_hash_table_lookup(fsa_membership_copy->members,fsa_our_uname);
your_node = (oc_node_t*)
g_hash_table_lookup(fsa_membership_copy->members,vote_from);
}
if(your_node == NULL) {
crm_debug("Election ignore: The other side doesnt exist in CCM.");
return I_NULL;
/* if your_version == 0, then they're shutting down too */
} else if(is_set(fsa_input_register, R_SHUTDOWN)) {
if(your_version != NULL) {
crm_info("Election fail: we are shutting down");
we_loose = TRUE;
} else {
/* pretend nothing happened, they want to shutdown too*/
crm_info("Election ignore: they are shutting down too");
return I_NULL;
}
} else if(our_node == NULL
|| fsa_membership_copy->last_event == OC_EV_MS_EVICTED) {
crm_info("Election fail: we dont exist in CCM");
we_loose = TRUE;
} else if(your_version == NULL) {
crm_info("Election pass: they are shutting down");
} else if(compare_version(your_version, CRM_VERSION) > 0) {
crm_debug("Election fail: version");
we_loose = TRUE;
} else if(compare_version(your_version, CRM_VERSION) < 0) {
crm_debug("Election pass: version");
} else if(your_node->node_born_on < our_node->node_born_on) {
crm_debug("Election fail: born_on");
we_loose = TRUE;
} else if(your_node->node_born_on > our_node->node_born_on) {
crm_debug("Election pass: born_on");
} else if(strcmp(fsa_our_uname, vote_from) > 0) {
crm_debug("Election fail: uname");
we_loose = TRUE;
/* cant happen...
* } else if(strcmp(fsa_our_uname, vote_from) == 0) {
*
* default...
* } else { // strcmp(fsa_our_uname, vote_from) < 0
* we win
*/
}
if(we_loose) {
crm_timer_stop(election_timeout);
fsa_cib_conn->cmds->set_slave(fsa_cib_conn, cib_scope_local);
crm_debug("Election lost to %s", vote_from);
if(fsa_input_register & R_THE_DC) {
crm_devel("Give up the DC to %s", vote_from);
election_result = I_RELEASE_DC;
} else {
crm_devel("We werent the DC anyway");
election_result = I_PENDING;
}
} else {
if(cur_state == S_PENDING) {
crm_debug("Election ignore: We already lost the election");
return I_NULL;
} else {
crm_info("Election won over %s", vote_from);
election_result = I_ELECTION;
}
}
register_fsa_input(C_FSA_INTERNAL, election_result, NULL);
return I_NULL;
}
/* A_ELECT_TIMER_START, A_ELECTION_TIMEOUT */
/* we won */
enum crmd_fsa_input
do_election_timer_ctrl(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)
{
return I_NULL;
}
/* A_DC_TAKEOVER */
enum crmd_fsa_input
do_dc_takeover(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)
{
crm_data_t *cib = createEmptyCib();
crm_data_t *update = NULL;
crm_data_t *output = NULL;
int rc = cib_ok;
crm_trace("################## Taking over the DC ##################");
set_bit_inplace(fsa_input_register, R_THE_DC);
crm_verbose("Am I the DC? %s", AM_I_DC?XML_BOOLEAN_YES:XML_BOOLEAN_NO);
crm_free(fsa_our_dc);
fsa_our_dc = crm_strdup(fsa_our_uname);
set_bit_inplace(fsa_input_register, R_JOIN_OK);
set_bit_inplace(fsa_input_register, R_INVOKE_PE);
clear_bit_inplace(fsa_input_register, R_CIB_DONE);
clear_bit_inplace(fsa_input_register, R_HAVE_CIB);
if(dc_heartbeat->source_id == (guint)-1
|| dc_heartbeat->source_id == (guint)-2) {
crm_devel("Starting DC Heartbeat timer");
dc_heartbeat->source_id = Gmain_timeout_add_full(
G_PRIORITY_HIGH, dc_heartbeat->period_ms,
dc_heartbeat->callback, dc_heartbeat, NULL);
} else {
crm_devel("DC Heartbeat timer already active");
}
/* fsa_cib_conn->cmds->set_slave_all(fsa_cib_conn, cib_none); */
fsa_cib_conn->cmds->set_master(fsa_cib_conn, cib_none);
set_uuid(fsa_cluster_conn, cib, XML_ATTR_DC_UUID, fsa_our_uname);
crm_devel("Update %s in the CIB to our uuid: %s",
XML_ATTR_DC_UUID, crm_element_value(cib, XML_ATTR_DC_UUID));
update = create_cib_fragment(cib, NULL);
free_xml(cib);
rc = fsa_cib_conn->cmds->modify(
- fsa_cib_conn, NULL, update, &output, cib_none);
+ fsa_cib_conn, NULL, update, &output, cib_quorum_override);
if(rc == cib_revision_unsupported) {
crm_err("Feature revision not permitted");
/* go into a stall state */
register_fsa_error(C_FSA_INTERNAL, I_HALT, NULL);
return I_NULL;
} else if(rc < cib_ok) {
crm_err("DC UUID update failed: %s", cib_error2string(rc));
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
}
rc = fsa_cib_conn->cmds->query(
fsa_cib_conn, NULL, NULL, cib_scope_local);
if(FALSE == add_cib_op_callback(
rc, TRUE, NULL, revision_check_callback)) {
crm_err("Retrieval of generation failed");
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
}
free_xml(update);
crm_devel("Requesting an initial dump of CRMD client_status");
fsa_cluster_conn->llc_ops->client_status(
fsa_cluster_conn, NULL, CRM_SYSTEM_CRMD, -1);
return I_NULL;
}
void
revision_check_callback(const HA_Message *msg, int call_id, int rc,
crm_data_t *output, void *user_data)
{
int revision_i = -1;
const char *revision = NULL;
crm_data_t *generation = find_xml_node(output, XML_TAG_CIB, TRUE);
crm_devel("Checking our feature revision is allowed: %d",
cib_feature_revision);
revision = crm_element_value(generation, XML_ATTR_CIB_REVISION);
revision_i = atoi(revision?revision:"0");
if(revision_i > cib_feature_revision) {
crm_err("Feature revision not permitted");
/* go into a stall state */
register_fsa_error_adv(
C_FSA_INTERNAL, I_HALT, NULL, NULL, __FUNCTION__);
}
}
/* A_DC_RELEASE */
enum crmd_fsa_input
do_dc_release(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)
{
enum crmd_fsa_input result = I_NULL;
crm_trace("################## Releasing the DC ##################");
crm_timer_stop(dc_heartbeat);
if(action & A_DC_RELEASE) {
clear_bit_inplace(fsa_input_register, R_THE_DC);
/* get a new CIB from the new DC */
clear_bit_inplace(fsa_input_register, R_HAVE_CIB);
} else if (action & A_DC_RELEASED) {
fsa_cib_conn->cmds->set_slave(fsa_cib_conn, cib_scope_local);
if(cur_state == S_STOPPING) {
register_fsa_input(C_FSA_INTERNAL, I_RELEASE_SUCCESS, NULL);
}
#if 0
else if( are there errors ) {
/* we cant stay up if not healthy */
/* or perhaps I_ERROR and go to S_RECOVER? */
result = I_SHUTDOWN;
}
#endif
else {
register_fsa_input(C_FSA_INTERNAL, I_RELEASE_SUCCESS, NULL);
}
} else {
crm_err("Warning, do_dc_release invoked for action %s",
fsa_action2string(action));
}
crm_verbose("Am I still the DC? %s", AM_I_DC?XML_BOOLEAN_YES:XML_BOOLEAN_NO);
return result;
}
void
ghash_count_vote(gpointer key, gpointer value, gpointer user_data)
{
struct election_data_s *election_data =
(struct election_data_s *)user_data;
oc_node_t *cur_node = (oc_node_t*)value;
const char *node_uname = (const char*)key;
if(election_data->winning_bornon > cur_node->node_born_on) {
election_data->winning_uname = node_uname;
election_data->winning_bornon = cur_node->node_born_on;
} else if(election_data->winning_bornon == cur_node->node_born_on
&& (election_data->winning_uname == NULL
|| strcmp(election_data->winning_uname, node_uname) > 0)) {
election_data->winning_uname = node_uname;
election_data->winning_bornon = cur_node->node_born_on;
}
}
diff --git a/crm/crmd/join_dc.c b/crm/crmd/join_dc.c
index 8227055ef9..4d1bd7b353 100644
--- a/crm/crmd/join_dc.c
+++ b/crm/crmd/join_dc.c
@@ -1,587 +1,591 @@
/*
* 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;
char *max_epoche = NULL;
char *max_generation_from = NULL;
crm_data_t *max_generation_xml = 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);
void finalize_sync_callback(const HA_Message *msg, int call_id, int rc,
crm_data_t *output, void *user_data);
void finialize_query_callback(const HA_Message *msg, int call_id, int rc,
crm_data_t *output, void *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 */
#if 0
crm_data_t *cib_copy = get_cib_copy(fsa_cib_conn);
crm_data_t *tmp1 = get_object_root(XML_CIB_TAG_STATUS, cib_copy);
crm_data_t *tmp2 = NULL;
#endif
crm_data_t *fragment = create_cib_fragment(NULL, NULL);
crm_data_t *update = find_xml_node(fragment, XML_TAG_CIB, TRUE);
initialize_join(TRUE);
/* catch any nodes that are active in the CIB but not in the CCM list*/
update = get_object_root(XML_CIB_TAG_STATUS, update);
CRM_DEV_ASSERT(update != NULL);
#if 0
/* dont do this for now... involves too much blocking and I cant
* think of a sensible way to do it asyncronously
*/
xml_child_iter(
tmp1, node_entry, XML_CIB_TAG_STATE,
const char *node_id = crm_element_value(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);
add_node_copy(update, tmp2);
free_xml(tmp2);
);
free_xml(cib_copy);
#endif
/* now process the CCM data */
do_update_cib_nodes(fragment, TRUE);
/* free_xml(fragment); */
/* BUG! This should be able to be freed.
* I cant find any reason why it shouldnt be able to be,
* but libxml still corrupts memory
*/
#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((ssize_t)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)
{
oc_node_t member;
gpointer a_node = NULL;
ha_msg_input_t *welcome = fsa_typed_data(fsa_dt_ha_msg);
const char *join_to = NULL;
if(welcome == NULL) {
crm_err("Attempt to send welcome message "
"without a message to reply to!");
return I_NULL;
}
join_to = cl_get_string(welcome->msg, F_CRM_HOST_FROM);
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_info("Re-offering membership to %s...", join_to);
}
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)
{
crm_data_t *generation = NULL;
gboolean is_a_member = FALSE;
const char *ack_nack = CRMD_JOINSTATE_MEMBER;
ha_msg_input_t *join_ack = fsa_typed_data(fsa_dt_ha_msg);
const char *join_from = cl_get_string(join_ack->msg,F_CRM_HOST_FROM);
const char *ref = cl_get_string(join_ack->msg,XML_ATTR_REFERENCE);
const char *op = cl_get_string(join_ack->msg, F_CRM_TASK);
gpointer join_node =
g_hash_table_lookup(fsa_membership_copy->members, join_from);
if(safe_str_neq(op, CRM_OP_WELCOME)) {
crm_warn("Ignoring op=%s message", op);
return I_NULL;
}
crm_devel("Processing req from %s", join_from);
if(join_node != NULL) {
is_a_member = TRUE;
}
generation = join_ack->xml;
if(max_generation_xml == NULL) {
max_generation_xml = copy_xml_node_recursive(generation);
max_generation_from = crm_strdup(join_from);
} else if(cib_compare_generation(max_generation_xml, generation) < 0) {
clear_bit_inplace(fsa_input_register, R_HAVE_CIB);
crm_devel("%s has a better generation number than the current max",
join_from);
crm_xml_devel(max_generation_xml, "Max generation");
crm_xml_devel(generation, "Their generation");
crm_free(max_generation_from);
free_xml(max_generation_xml);
max_generation_from = crm_strdup(join_from);
max_generation_xml = copy_xml_node_recursive(join_ack->xml);
}
crm_devel("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);
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
} 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((ssize_t)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)
{
enum cib_errors rc = cib_ok;
if(max_generation_from == NULL
|| safe_str_eq(max_generation_from, fsa_our_uname)){
set_bit_inplace(fsa_input_register, R_HAVE_CIB);
}
if(is_set(fsa_input_register, R_HAVE_CIB) == FALSE) {
/* ask for the agreed best CIB */
crm_info("Asking %s for its copy of the CIB",
crm_str(max_generation_from));
fsa_cib_conn->call_timeout = 10;
rc = fsa_cib_conn->cmds->query_from(
fsa_cib_conn, max_generation_from, NULL, NULL, 0);
fsa_cib_conn->call_timeout = 0; /* back to the default */
add_cib_op_callback(rc, FALSE, crm_strdup(max_generation_from),
finalize_sync_callback);
return I_NULL;
}
crm_devel("Bumping the epoche and syncing to %d clients",
g_hash_table_size(join_requests));
- fsa_cib_conn->cmds->bump_epoch(fsa_cib_conn, cib_scope_local);
- rc = fsa_cib_conn->cmds->sync(fsa_cib_conn, NULL, cib_none);
+ fsa_cib_conn->cmds->bump_epoch(
+ fsa_cib_conn, cib_scope_local|cib_quorum_override);
+ rc = fsa_cib_conn->cmds->sync(fsa_cib_conn, NULL, cib_quorum_override);
add_cib_op_callback(rc, FALSE, NULL, finalize_sync_callback);
return I_NULL;
}
void
finialize_query_callback(const HA_Message *msg, int call_id, int rc,
crm_data_t *output, void *user_data)
{
/* static int lpc = 0; */
crm_data_t *foreign_cib = NULL;
char *remote_host = user_data;
if(AM_I_DC == FALSE) {
crm_debug("this call is no longer relevant");
crm_free(remote_host);
return;
}
if(rc == cib_ok) {
crm_data_t *update = NULL;
crm_data_t *cib = createEmptyCib();
set_uuid(fsa_cluster_conn, cib,
XML_ATTR_DC_UUID, fsa_our_uname);
crm_devel("Update %s in the CIB to our uuid: %s",
XML_ATTR_DC_UUID,
crm_element_value(cib, XML_ATTR_DC_UUID));
update = create_cib_fragment(cib, NULL);
free_xml(cib);
update_local_cib(update);
}
if(rc == cib_remote_timeout) {
crm_err("Sync from %s resulted in an error: %s."
" Use what we have...",
remote_host, cib_error2string(rc));
#if 0
/* restart the whole join process */
register_fsa_error_adv(C_FSA_INTERNAL, I_ELECTION_DC,
NULL, NULL, __FUNCTION__);
#else
rc = cib_ok;
#endif
} else if(rc < cib_ok) {
crm_err("Sync from %s resulted in an error: %s",
remote_host, cib_error2string(rc));
register_fsa_error_adv(
C_FSA_INTERNAL, I_ERROR, NULL, NULL, __FUNCTION__);
} else {
foreign_cib = find_xml_node(output, XML_TAG_CIB, TRUE);
CRM_DEV_ASSERT(foreign_cib != NULL);
if(!crm_assert_failed) {
rc = fsa_cib_conn->cmds->replace(
- fsa_cib_conn, NULL, foreign_cib, NULL, cib_none);
+ fsa_cib_conn, NULL, foreign_cib, NULL,
+ cib_quorum_override);
}
}
if(rc >= 0) {
crm_devel("Bumping the epoche and syncing to %d clients",
g_hash_table_size(join_requests));
- fsa_cib_conn->cmds->bump_epoch(fsa_cib_conn, cib_scope_local);
- rc = fsa_cib_conn->cmds->sync(fsa_cib_conn, NULL, cib_none);
+ fsa_cib_conn->cmds->bump_epoch(
+ fsa_cib_conn, cib_scope_local|cib_quorum_override);
+ rc = fsa_cib_conn->cmds->sync(
+ fsa_cib_conn, NULL, cib_quorum_override);
add_cib_op_callback(rc, FALSE, NULL, finalize_sync_callback);
}
crm_free(remote_host);
return;
}
void
finalize_sync_callback(const HA_Message *msg, int call_id, int rc,
crm_data_t *output, void *user_data)
{
CRM_DEV_ASSERT(cib_not_master != rc);
if(rc != cib_ok) {
register_fsa_error_adv(C_FSA_INTERNAL, I_FAIL,
NULL, NULL, __FUNCTION__);
return;
}
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);
}
/* 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" */
crm_data_t *update = NULL;
ha_msg_input_t *join_ack = fsa_typed_data(fsa_dt_ha_msg);
const char *join_from = cl_get_string(join_ack->msg, F_CRM_HOST_FROM);
const char *op = cl_get_string(join_ack->msg, F_CRM_TASK);
const char *type = cl_get_string(join_ack->msg, F_SUBTYPE);
const char *join_state = NULL;
if(safe_str_neq(op, CRM_OP_JOINACK)) {
crm_warn("Ignoring op=%s message", op);
return I_NULL;
} else if(safe_str_eq(type, XML_ATTR_REQUEST)) {
crm_verbose("Ignoring request");
crm_log_message(LOG_VERBOSE, join_ack->msg);
return I_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);
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
} 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));
/* the updates will actually occur in reverse order because of
* the LIFO nature of the fsa input queue
*/
/* update CIB with the current LRM status from the node */
update_local_cib(copy_xml_node_recursive(join_ack->xml));
/* update node entry in the status section */
crm_info("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);
update_local_cib(create_cib_fragment(update, NULL));
if(num_join_invites <= (ssize_t)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)
{
const char *join_to = NULL;
const char *join_state = NULL;
HA_Message *acknak = NULL;
if(key == NULL || value == NULL) {
return;
}
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);
/* send the ack/nack to the node */
acknak = create_request(
CRM_OP_JOINACK, NULL, join_to,
CRM_SYSTEM_CRMD, CRM_SYSTEM_DC, NULL);
/* set the ack/nack */
if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) {
crm_info("ACK'ing join request from %s, state %s",
join_to, join_state);
num_join_invites++;
ha_msg_add(acknak, CRM_OP_JOINACK, XML_BOOLEAN_TRUE);
} else {
crm_warn("NACK'ing join request from %s, state %s",
join_to, join_state);
ha_msg_add(acknak, CRM_OP_JOINACK, XML_BOOLEAN_FALSE);
}
send_msg_via_ha(fsa_cluster_conn, acknak);
}
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) {
if(max_generation_from != NULL) {
crm_free(max_generation_from);
max_generation_from = NULL;
}
if(max_generation_xml != NULL) {
free_xml(max_generation_xml);
max_generation_xml = 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);
}
void
join_send_offer(gpointer key, gpointer value, gpointer user_data)
{
const char *join_to = NULL;
void *a_node = NULL;
const oc_node_t *member = (const oc_node_t*)value;
if(member != NULL) {
join_to = member->node_uname;
}
if(join_to == NULL) {
crm_err("No recipient for welcome message");
} else {
HA_Message *offer = create_request(
CRM_OP_WELCOME, NULL, join_to,
CRM_SYSTEM_CRMD, CRM_SYSTEM_DC, NULL);
/* send the welcome */
crm_info("Sending %s to %s", CRM_OP_WELCOME, join_to);
send_msg_via_ha(fsa_cluster_conn, offer);
a_node = g_hash_table_lookup(join_requests, join_to);
if(a_node == NULL) {
g_hash_table_insert(join_offers, crm_strdup(join_to),
crm_strdup(CRMD_JOINSTATE_PENDING));
}
}
}
diff --git a/crm/crmd/lrm.c b/crm/crmd/lrm.c
index a7da0fb344..cf07cc7ce5 100644
--- a/crm/crmd/lrm.c
+++ b/crm/crmd/lrm.c
@@ -1,946 +1,947 @@
/*
* 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 <sys/param.h>
#include <crm/crm.h>
#include <crmd_fsa.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h> /* for access */
#include <clplumbing/cl_signal.h>
#include <errno.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crmd.h>
#include <crmd_messages.h>
#include <crmd_callbacks.h>
#include <lrm/raexec.h>
#include <crm/dmalloc_wrapper.h>
gboolean stop_all_resources(void);
gboolean build_suppported_RAs(
crm_data_t *metadata_list, crm_data_t *xml_agent_list);
gboolean build_active_RAs(crm_data_t *rsc_list);
void do_update_resource(lrm_rsc_t *rsc, lrm_op_t *op);
enum crmd_fsa_input do_lrm_rsc_op(
lrm_rsc_t *rsc, char *rid, const char *operation, crm_data_t *msg);
enum crmd_fsa_input do_fake_lrm_op(gpointer data);
void stop_recurring_action(
gpointer key, gpointer value, gpointer user_data);
gboolean remove_recurring_action(
gpointer key, gpointer value, gpointer user_data);
GHashTable *xml2list(crm_data_t *parent);
GHashTable *monitors = NULL;
int num_lrm_register_fails = 0;
int max_lrm_register_fails = 30;
const char *rsc_path[] =
{
/* XML_GRAPH_TAG_RSC_OP, */
XML_CIB_TAG_RESOURCE,
"instance_attributes",
"rsc_parameters"
};
enum crmd_rscstate {
crmd_rscstate_NULL,
crmd_rscstate_START,
crmd_rscstate_START_PENDING,
crmd_rscstate_START_OK,
crmd_rscstate_START_FAIL,
crmd_rscstate_STOP,
crmd_rscstate_STOP_PENDING,
crmd_rscstate_STOP_OK,
crmd_rscstate_STOP_FAIL,
crmd_rscstate_MON,
crmd_rscstate_MON_PENDING,
crmd_rscstate_MON_OK,
crmd_rscstate_MON_FAIL,
crmd_rscstate_GENERIC_PENDING,
crmd_rscstate_GENERIC_OK,
crmd_rscstate_GENERIC_FAIL
};
void free_lrm_op(lrm_op_t *op);
const char *crmd_rscstate2string(enum crmd_rscstate state);
const char *
crmd_rscstate2string(enum crmd_rscstate state)
{
switch(state) {
case crmd_rscstate_NULL:
return NULL;
case crmd_rscstate_START:
return CRMD_RSCSTATE_START;
case crmd_rscstate_START_PENDING:
return CRMD_RSCSTATE_START_PENDING;
case crmd_rscstate_START_OK:
return CRMD_RSCSTATE_START_OK;
case crmd_rscstate_START_FAIL:
return CRMD_RSCSTATE_START_FAIL;
case crmd_rscstate_STOP:
return CRMD_RSCSTATE_STOP;
case crmd_rscstate_STOP_PENDING:
return CRMD_RSCSTATE_STOP_PENDING;
case crmd_rscstate_STOP_OK:
return CRMD_RSCSTATE_STOP_OK;
case crmd_rscstate_STOP_FAIL:
return CRMD_RSCSTATE_STOP_FAIL;
case crmd_rscstate_MON:
return CRMD_RSCSTATE_MON;
case crmd_rscstate_MON_PENDING:
return CRMD_RSCSTATE_MON_PENDING;
case crmd_rscstate_MON_OK:
return CRMD_RSCSTATE_MON_OK;
case crmd_rscstate_MON_FAIL:
return CRMD_RSCSTATE_MON_FAIL;
case crmd_rscstate_GENERIC_PENDING:
return CRMD_RSCSTATE_GENERIC_PENDING;
case crmd_rscstate_GENERIC_OK:
return CRMD_RSCSTATE_GENERIC_OK;
case crmd_rscstate_GENERIC_FAIL:
return CRMD_RSCSTATE_GENERIC_FAIL;
}
return "<unknown>";
}
/* A_LRM_CONNECT */
enum crmd_fsa_input
do_lrm_control(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)
{
int ret = HA_OK;
if(action & A_LRM_DISCONNECT) {
if(fsa_lrm_conn) {
fsa_lrm_conn->lrm_ops->signoff(fsa_lrm_conn);
}
/* TODO: Clean up the hashtable */
}
if(action & A_LRM_CONNECT) {
crm_trace("LRM: connect...");
ret = HA_OK;
monitors = g_hash_table_new_full(
g_direct_hash,g_direct_equal,NULL,g_hash_destroy_str);
fsa_lrm_conn = ll_lrm_new(XML_CIB_TAG_LRM);
if(NULL == fsa_lrm_conn) {
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
ret = HA_FAIL;
}
if(ret == HA_OK) {
crm_trace("LRM: sigon...");
ret = fsa_lrm_conn->lrm_ops->signon(
fsa_lrm_conn, CRM_SYSTEM_CRMD);
}
if(ret != HA_OK) {
if(++num_lrm_register_fails < max_lrm_register_fails) {
crm_warn("Failed to sign on to the LRM %d"
" (%d max) times",
num_lrm_register_fails,
max_lrm_register_fails);
crm_timer_start(wait_timer);
crmd_fsa_stall();
return I_NULL;
}
}
if(ret == HA_OK) {
crm_trace("LRM: set_lrm_callback...");
ret = fsa_lrm_conn->lrm_ops->set_lrm_callback(
fsa_lrm_conn, lrm_op_callback);
if(ret != HA_OK) {
crm_err("Failed to set LRM callbacks");
}
}
if(ret != HA_OK) {
crm_err("Failed to sign on to the LRM %d"
" (max) times", num_lrm_register_fails);
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
return I_NULL;
}
/* TODO: create a destroy handler that causes
* some recovery to happen
*/
G_main_add_fd(G_PRIORITY_LOW,
fsa_lrm_conn->lrm_ops->inputfd(fsa_lrm_conn),
FALSE,
lrm_dispatch, fsa_lrm_conn,
default_ipc_connection_destroy);
set_bit_inplace(fsa_input_register, R_LRM_CONNECTED);
}
if(action & ~(A_LRM_CONNECT|A_LRM_DISCONNECT)) {
crm_err("Unexpected action %s in %s",
fsa_action2string(action), __FUNCTION__);
}
return I_NULL;
}
gboolean
build_suppported_RAs(crm_data_t *metadata_list, crm_data_t *xml_agent_list)
{
GList *types = NULL;
GList *classes = NULL;
const char *version = NULL;
crm_data_t *xml_agent = NULL;
/* return TRUE; */
if(fsa_lrm_conn == NULL) {
return FALSE;
}
classes = fsa_lrm_conn->lrm_ops->get_rsc_class_supported(fsa_lrm_conn);
slist_iter(
class, char, classes, lpc,
types = fsa_lrm_conn->lrm_ops->get_rsc_type_supported(
fsa_lrm_conn, class);
slist_iter(
type, char, types, llpc,
version = "1";
xml_agent = create_xml_node(
xml_agent_list, XML_LRM_TAG_AGENT);
set_xml_property_copy(
xml_agent, XML_AGENT_ATTR_CLASS, class);
set_xml_property_copy(xml_agent, XML_ATTR_TYPE, type);
set_xml_property_copy(
xml_agent, XML_ATTR_VERSION, version);
)
g_list_free(types);
);
g_list_free(classes);
return TRUE;
}
gboolean
stop_all_resources(void)
{
GList *op_list = NULL;
GList *lrm_list = NULL;
state_flag_t cur_state = 0;
const char *this_op = NULL;
if(fsa_lrm_conn == NULL) {
return TRUE;
}
lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn);
slist_iter(
rid, char, lrm_list, lpc,
lrm_rsc_t *the_rsc =
fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid);
crm_info("Processing lrm_rsc_t entry %s", rid);
if(the_rsc == NULL) {
crm_err("NULL resource returned from the LRM");
continue;
}
op_list = the_rsc->ops->get_cur_state(the_rsc, &cur_state);
crm_verbose("\tcurrent state:%s",
cur_state==LRM_RSC_IDLE?"Idle":"Busy");
slist_iter(
op, lrm_op_t, op_list, llpc,
this_op = op->op_type;
crm_debug("Processing op %s for %s (status=%d, rc=%d)",
op->op_type, the_rsc->id,
op->op_status, op->rc);
if(safe_str_neq(this_op, CRMD_RSCSTATE_STOP)){
do_lrm_rsc_op(the_rsc, the_rsc->id,
CRMD_RSCSTATE_STOP, NULL);
}
break;
);
);
return TRUE;
}
gboolean
build_active_RAs(crm_data_t *rsc_list)
{
GList *op_list = NULL;
GList *lrm_list = NULL;
gboolean found_op = FALSE;
state_flag_t cur_state = 0;
const char *this_op = NULL;
char *tmp = NULL;
if(fsa_lrm_conn == NULL) {
return FALSE;
}
lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn);
slist_iter(
rid, char, lrm_list, lpc,
/* GHashTable* params; */
lrm_rsc_t *the_rsc =
fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid);
crm_data_t *xml_rsc = create_xml_node(
rsc_list, XML_LRM_TAG_RESOURCE);
crm_info("Processing lrm_rsc_t entry %s", rid);
if(the_rsc == NULL) {
crm_err("NULL resource returned from the LRM");
continue;
}
set_xml_property_copy(xml_rsc, XML_ATTR_ID, the_rsc->id);
set_xml_property_copy(
xml_rsc, XML_LRM_ATTR_TARGET, fsa_our_uname);
op_list = the_rsc->ops->get_cur_state(the_rsc, &cur_state);
crm_verbose("\tcurrent state:%s",
cur_state==LRM_RSC_IDLE?"Idle":"Busy");
slist_iter(
op, lrm_op_t, op_list, llpc,
this_op = op->op_type;
crm_info("Processing op %s for %s (status=%d, rc=%d)",
op->op_type, the_rsc->id, op->op_status, op->rc);
if(op->rc != 0
|| safe_str_neq(this_op, CRMD_RSCSTATE_MON)){
set_xml_property_copy(
xml_rsc,
XML_LRM_ATTR_RSCSTATE,
op->user_data);
set_xml_property_copy(
xml_rsc, XML_LRM_ATTR_LASTOP, this_op);
tmp = crm_itoa(op->rc);
set_xml_property_copy(
xml_rsc, XML_LRM_ATTR_RC, tmp);
crm_free(tmp);
tmp = crm_itoa(op->op_status);
set_xml_property_copy(
xml_rsc, XML_LRM_ATTR_OPSTATUS, tmp);
crm_free(tmp);
/* we only want the last one */
found_op = TRUE;
break;
} else {
set_xml_property_copy(
xml_rsc,
XML_LRM_ATTR_RSCSTATE,
CRMD_RSCSTATE_START_OK);
set_xml_property_copy(
xml_rsc,
XML_LRM_ATTR_LASTOP,
CRMD_RSCSTATE_START);
tmp = crm_itoa(op->rc);
set_xml_property_copy(
xml_rsc, XML_LRM_ATTR_RC, tmp);
crm_free(tmp);
set_xml_property_copy(
xml_rsc, XML_LRM_ATTR_OPSTATUS, "0");
/* we only want the last one */
found_op = TRUE;
break;
}
);
if(found_op == FALSE) {
crm_err("Could not properly determin last op"
" for %s from %d entries", the_rsc->id,
g_list_length(op_list));
}
g_list_free(op_list);
);
g_list_free(lrm_list);
return TRUE;
}
crm_data_t*
do_lrm_query(gboolean is_replace)
{
crm_data_t *xml_result= NULL;
crm_data_t *xml_state = create_xml_node(NULL, XML_CIB_TAG_STATE);
crm_data_t *xml_data = create_xml_node(xml_state, XML_CIB_TAG_LRM);
crm_data_t *rsc_list = create_xml_node(xml_data,XML_LRM_TAG_RESOURCES);
#if 0
/* Build a list of supported agents and metadata */
crm_data_t *xml_agent_list = create_xml_node(xml_data, XML_LRM_TAG_AGENTS);
crm_data_t *xml_metadata_list = create_xml_node(xml_data, "metatdata");
build_suppported_RAs(xml_metadata_list, xml_agent_list);
#endif
/* Build a list of active (not always running) resources */
build_active_RAs(rsc_list);
if(is_replace) {
set_xml_property_copy(
xml_state, XML_CIB_ATTR_REPLACE, XML_CIB_TAG_LRM);
}
set_uuid(fsa_cluster_conn, xml_state, XML_ATTR_UUID, fsa_our_uname);
set_xml_property_copy(xml_state, XML_ATTR_UNAME, fsa_our_uname);
xml_result = create_cib_fragment(xml_state, NULL);
crm_xml_devel(xml_state, "Current state of the LRM");
return xml_result;
}
/* A_LRM_INVOKE */
enum crmd_fsa_input
do_lrm_invoke(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)
{
const char *crm_op = NULL;
const char *operation = NULL;
enum crmd_fsa_input next_input = I_NULL;
ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg);
crm_op = cl_get_string(input->msg, F_CRM_TASK);
operation = get_xml_attr_nested(
input->xml, rsc_path, DIMOF(rsc_path) -3,
XML_LRM_ATTR_TASK, FALSE);
if(crm_op != NULL && safe_str_eq(crm_op, "lrm_query")) {
crm_data_t *data = do_lrm_query(FALSE);
HA_Message *reply = create_reply(input->msg, data);
if(relay_message(reply, TRUE) == FALSE) {
crm_err("Unable to route reply");
crm_log_message(LOG_ERR, reply);
crm_msg_del(reply);
}
free_xml(data);
} else if(operation != NULL) {
char rid[64];
const char *id_from_cib = NULL;
lrm_rsc_t *rsc = NULL;
id_from_cib = get_xml_attr_nested(
input->xml, rsc_path, DIMOF(rsc_path) -2,
XML_ATTR_ID, TRUE);
if(id_from_cib == NULL) {
crm_err("No value for %s in message at level %d.",
XML_ATTR_ID, DIMOF(rsc_path) -2);
return I_NULL;
}
/* only the first 16 chars are used by the LRM */
strncpy(rid, id_from_cib, 64);
rid[63] = 0;
rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid);
next_input = do_lrm_rsc_op(rsc, rid, operation, input->xml);
} else {
crm_err("Operation was neither a lrm_query, nor a rsc op. %s",
crm_str(crm_op));
next_input = I_ERROR;
}
return next_input;
}
enum crmd_fsa_input
do_lrm_rsc_op(
lrm_rsc_t *rsc, char *rid, const char *operation, crm_data_t *msg)
{
lrm_op_t* op = NULL;
int call_id = 0;
fsa_data_t *msg_data = NULL;
const char *type = NULL;
const char *class = NULL;
const char *provider = NULL;
GHashTable *params = NULL;
if(rsc != NULL) {
class = rsc->class;
type = rsc->type;
} else if(msg != NULL) {
class = get_xml_attr_nested(
msg, rsc_path, DIMOF(rsc_path) -2,
XML_AGENT_ATTR_CLASS, TRUE);
type = get_xml_attr_nested(
msg, rsc_path, DIMOF(rsc_path) -2,
XML_ATTR_TYPE, TRUE);
provider = get_xml_attr_nested(
msg, rsc_path, DIMOF(rsc_path) -2,
XML_AGENT_ATTR_PROVIDER, FALSE);
}
if(rsc == NULL) {
/* check if its already there */
CRM_DEV_ASSERT(rid != NULL);
rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid);
}
if(rsc == NULL) {
/* add it to the list */
crm_verbose("adding rsc %s before operation", rid);
if(msg != NULL) {
params = xml2list(msg);
} else {
CRM_DEV_ASSERT(safe_str_eq(CRMD_RSCSTATE_STOP, operation));
}
fsa_lrm_conn->lrm_ops->add_rsc(
fsa_lrm_conn, rid, class, type, provider, params);
rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid);
}
if(rsc == NULL) {
crm_err("Could not add resource %s to LRM", rid);
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
}
/* stop the monitor before stopping the resource */
if(safe_str_eq(operation, CRMD_RSCSTATE_STOP)) {
g_hash_table_foreach(monitors, stop_recurring_action, rsc);
g_hash_table_foreach_remove(
monitors, remove_recurring_action, rsc);
}
/* now do the op */
crm_info("Performing op %s on %s", operation, rid);
crm_malloc(op, sizeof(lrm_op_t));
op->op_type = crm_strdup(operation);
op->user_data = NULL;
if(params == NULL) {
if(msg != NULL) {
params = xml2list(msg);
} else {
CRM_DEV_ASSERT(safe_str_eq(
CRMD_RSCSTATE_STOP, operation));
}
}
op->params = params;
op->interval = crm_get_msec(g_hash_table_lookup(op->params,"interval"));
op->timeout = crm_get_msec(g_hash_table_lookup(op->params, "timeout"));
/* sanity */
if(op->interval < 0) {
op->interval = 0;
}
if(op->timeout < 0) {
op->timeout = 0;
}
if(safe_str_eq(operation, CRMD_RSCSTATE_MON)) {
op->target_rc = CHANGED;
} else {
op->target_rc = EVERYTIME;
}
if(safe_str_eq(CRMD_RSCSTATE_START, operation)) {
op->user_data = crm_strdup(CRMD_RSCSTATE_START_OK);
} else if(safe_str_eq(CRMD_RSCSTATE_STOP, operation)) {
op->user_data = crm_strdup(CRMD_RSCSTATE_STOP_OK);
} else if(safe_str_eq(CRMD_RSCSTATE_MON, operation)) {
op->user_data = crm_strdup(CRMD_RSCSTATE_MON_OK);
} else {
crm_warn("Using status \"complete\" for op \"%s\""
"... this is still in the experimental stage.",
operation);
op->user_data = crm_strdup(CRMD_RSCSTATE_GENERIC_OK);
}
op->user_data_len = 1+strlen(op->user_data);
call_id = rsc->ops->perform_op(rsc, op);
if(call_id <= 0) {
crm_err("Operation %s on %s failed: %d",
operation, rid, call_id);
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
} else if(call_id > 0 && op->interval > 0) {
crm_debug("Adding recurring %s op for %s", operation, rsc->id);
g_hash_table_insert(
monitors, GINT_TO_POINTER(call_id), crm_strdup(rsc->id));
}
free_lrm_op(op);
return I_NULL;
}
void
stop_recurring_action(gpointer key, gpointer value, gpointer user_data)
{
int call_id = 0;
lrm_rsc_t *rsc = user_data;
if(safe_str_eq(value, rsc->id)) {
call_id = GPOINTER_TO_INT(key);
if(call_id > 0) {
crm_debug("Stopping recurring op %d for %s",
call_id, rsc->id);
rsc->ops->cancel_op(rsc, call_id);
} else {
crm_err("Invalid call_id %d for %s", call_id, rsc->id);
/* TODO: we probably need to look up the LRM to find it */
}
}
}
gboolean
remove_recurring_action(gpointer key, gpointer value, gpointer user_data)
{
lrm_rsc_t *rsc = user_data;
if(safe_str_eq(value, rsc->id)) {
return TRUE;
}
return FALSE;
}
void
free_lrm_op(lrm_op_t *op)
{
crm_free(op->user_data);
crm_free(op->op_type);
crm_free(op);
}
GHashTable *
xml2list(crm_data_t *parent)
{
crm_data_t *nvpair_list = NULL;
GHashTable *nvpair_hash = g_hash_table_new(g_str_hash, g_str_equal);
CRM_DEV_ASSERT(parent != NULL);
if(parent != NULL) {
nvpair_list = find_xml_node(parent, XML_TAG_ATTRS, FALSE);
if(nvpair_list == NULL) {
crm_debug("No attributes in %s",
crm_element_name(parent));
crm_xml_verbose(parent, "No attributes for resource op");
}
}
xml_child_iter(
nvpair_list, node_iter, XML_CIB_TAG_NVPAIR,
const char *key = crm_element_value(
node_iter, XML_NVPAIR_ATTR_NAME);
const char *value = crm_element_value(
node_iter, XML_NVPAIR_ATTR_VALUE);
crm_verbose("Added %s=%s", key, value);
g_hash_table_insert(
nvpair_hash,crm_strdup(key), crm_strdup(value));
);
return nvpair_hash;
}
void
do_update_resource(lrm_rsc_t *rsc, lrm_op_t* op)
{
/*
<status>
<nodes_status id=uname>
<lrm>
<lrm_resources>
<lrm_resource id=>
</...>
*/
crm_data_t *update, *iter;
char *tmp = NULL;
crm_data_t *fragment;
int len = 0;
char *fail_state = NULL;
int rc = cib_ok;
if(op == NULL || rsc == NULL) {
crm_err("Either resouce or op was not specified");
return;
}
crm_info("Updating resouce %s after op %s", rsc->id, op->op_type);
update = create_xml_node(NULL, XML_CIB_TAG_STATE);
set_uuid(fsa_cluster_conn, update, XML_ATTR_UUID, fsa_our_uname);
set_xml_property_copy(update, XML_ATTR_UNAME, fsa_our_uname);
iter = create_xml_node(update, XML_CIB_TAG_LRM);
iter = create_xml_node(iter, XML_LRM_TAG_RESOURCES);
iter = create_xml_node(iter, XML_LRM_TAG_RESOURCE);
set_xml_property_copy(iter, XML_ATTR_ID, rsc->id);
set_xml_property_copy(iter, XML_LRM_ATTR_LASTOP, op->op_type);
len = strlen(op->op_type);
len += strlen("_failed_");
crm_malloc(fail_state, sizeof(char)*len);
if(fail_state != NULL) {
sprintf(fail_state, "%s_failed", op->op_type);
}
switch(op->op_status) {
case LRM_OP_CANCELLED:
break;
case LRM_OP_ERROR:
case LRM_OP_TIMEOUT:
case LRM_OP_NOTSUPPORTED:
crm_debug("Resource action %s/%s failed: %d",
rsc->id, op->op_type, op->op_status);
set_xml_property_copy(
iter, XML_LRM_ATTR_RSCSTATE, fail_state);
break;
case LRM_OP_DONE:
set_xml_property_copy(
iter, XML_LRM_ATTR_RSCSTATE,
op->user_data);
break;
}
crm_free(fail_state);
tmp = crm_itoa(op->rc);
set_xml_property_copy(iter, XML_LRM_ATTR_RC, tmp);
crm_free(tmp);
tmp = crm_itoa(op->op_status);
set_xml_property_copy(iter, XML_LRM_ATTR_OPSTATUS, tmp);
crm_free(tmp);
set_xml_property_copy(iter, XML_LRM_ATTR_TARGET, fsa_our_uname);
fragment = create_cib_fragment(update, NULL);
/* make it an asyncronous call and be done with it
*
* Best case:
* the resource state will be discovered during
* the next signup or election.
*
* Bad case:
* we are shutting down and there is no DC at the time,
* but then why were we shutting down then anyway?
* (probably because of an internal error)
*
* Worst case:
* we get shot for having resources "running" when the really weren't
*
* the alternative however means blocking here for too long, which
* isnt acceptable
*/
rc = fsa_cib_conn->cmds->modify(
- fsa_cib_conn, XML_CIB_TAG_STATUS, fragment, NULL, cib_none);
+ fsa_cib_conn, XML_CIB_TAG_STATUS, fragment, NULL,
+ cib_quorum_override);
if(rc > 0) {
/* the return code is a call number, not an error code */
crm_devel("Sent resource state update message: %d", rc);
} else {
crm_err("Resource state update failed: %s",
cib_error2string(rc));
CRM_DEV_ASSERT(rc == cib_ok);
}
free_xml(fragment);
free_xml(update);
}
enum crmd_fsa_input
do_lrm_event(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input cur_input,
fsa_data_t *msg_data)
{
lrm_op_t* op = NULL;
lrm_rsc_t* rsc = NULL;
if(msg_data->fsa_cause != C_LRM_OP_CALLBACK) {
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
}
op = fsa_typed_data(fsa_dt_lrm);
CRM_DEV_ASSERT(op != NULL);
CRM_DEV_ASSERT(op != NULL && op->rsc != NULL);
if(op == NULL || op->rsc == NULL) {
return I_NULL;
}
rsc = op->rsc;
if(op->op_status == LRM_OP_DONE && op->rc != EXECRA_OK) {
crm_warn("Mapping operation %d status with a rc=%d"
" to status %d",
op->op_status, op->rc, LRM_OP_ERROR);
op->op_status = LRM_OP_ERROR;
}
switch(op->op_status) {
case LRM_OP_ERROR:
crm_err("LRM operation %s on %s::%s(%s):%s failed: %s",
op->op_type,
crm_str(rsc->class),
crm_str(rsc->type),
crm_str(rsc->provider),
crm_str(rsc->id),
execra_code2string(op->rc));
crm_debug("Result: %s", op->output);
break;
case LRM_OP_CANCELLED:
crm_warn("LRM operation %s on %s::%s(%s):%s: cancelled",
op->op_type,
crm_str(rsc->class),
crm_str(rsc->type),
crm_str(rsc->provider),
crm_str(rsc->id));
return I_NULL;
break;
case LRM_OP_TIMEOUT:
crm_err("LRM operation %s on %s::%s(%s):%s: timed out",
op->op_type,
crm_str(rsc->class),
crm_str(rsc->type),
crm_str(rsc->provider),
crm_str(rsc->id));
break;
case LRM_OP_NOTSUPPORTED:
crm_err("LRM operation %s on %s::%s(%s):%s: not supported",
op->op_type,
crm_str(rsc->class),
crm_str(rsc->type),
crm_str(rsc->provider),
crm_str(rsc->id));
break;
case LRM_OP_DONE:
crm_debug("LRM operation %s on %s::%s(%s):%s: complete",
op->op_type,
crm_str(rsc->class),
crm_str(rsc->type),
crm_str(rsc->provider),
crm_str(rsc->id));
break;
}
do_update_resource(rsc, op);
return I_NULL;
}
diff --git a/crm/crmd/messages.c b/crm/crmd/messages.c
index 21358502b2..ad20411ac7 100644
--- a/crm/crmd/messages.c
+++ b/crm/crmd/messages.c
@@ -1,1193 +1,1194 @@
/*
* 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 <sys/param.h>
#include <crm/crm.h>
#include <string.h>
#include <crmd_fsa.h>
#include <hb_api.h>
#include <lrm/lrm_api.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <crm/cib.h>
#include <crmd.h>
#include <crmd_messages.h>
#include <crm/dmalloc_wrapper.h>
GListPtr fsa_message_queue = NULL;
extern void crm_shutdown(int nsig);
enum crmd_fsa_input handle_request(ha_msg_input_t *stored_msg);
enum crmd_fsa_input handle_response(ha_msg_input_t *stored_msg);
enum crmd_fsa_input handle_shutdown_request(HA_Message *stored_msg);
ha_msg_input_t *copy_ha_msg_input(ha_msg_input_t *orig);
gboolean ipc_queue_helper(gpointer key, gpointer value, gpointer user_data);
#ifdef MSG_LOG
# define ROUTER_RESULT(x) \
do_crm_log(LOG_DEV, __FUNCTION__, DEVEL_DIR"/router.log", x); \
crm_log_message_adv(LOG_MSG, DEVEL_DIR"/router.log", relay_message); \
crm_devel(x); \
crm_log_message(LOG_MSG, relay_message);
#else
# define ROUTER_RESULT(x) crm_devel("Router result: %s", x); \
crm_log_message(LOG_MSG, relay_message);
#endif
/* debug only, can wrap all it likes */
int last_data_id = 0;
void
register_fsa_error_adv(
enum crmd_fsa_cause cause, enum crmd_fsa_input input,
fsa_data_t *cur_data, void *new_data, const char *raised_from)
{
/* save the current actions */
register_fsa_input_adv(cur_data?cur_data->fsa_cause:C_FSA_INTERNAL,
I_NULL, cur_data?cur_data->data:NULL,
fsa_actions, FALSE, __FUNCTION__);
/* reset the action list */
fsa_actions = A_NOTHING;
/* register the error */
register_fsa_input_adv(
cause, input, new_data, A_NOTHING, FALSE, raised_from);
}
static gboolean last_was_vote = FALSE;
void
register_fsa_input_adv(
enum crmd_fsa_cause cause, enum crmd_fsa_input input,
void *data, long long with_actions,
gboolean after, const char *raised_from)
{
unsigned old_len = g_list_length(fsa_message_queue);
fsa_data_t *fsa_data = NULL;
crm_verbose("%s raised FSA input %s (cause=%s) %s data",
raised_from,fsa_input2string(input),
fsa_cause2string(cause), data?"with":"without");
if(input == I_WAIT_FOR_EVENT) {
do_fsa_stall = TRUE;
set_bit_inplace(fsa_actions, with_actions);
with_actions = A_NOTHING;
crm_debug("Stalling the FSA pending further input");
}
if(old_len == 0) {
last_was_vote = FALSE;
}
if(input == I_NULL && with_actions == A_NOTHING /* && data == NULL */){
/* no point doing anything */
return;
} else if(data == NULL) {
last_was_vote = FALSE;
} else if(last_was_vote && cause == C_HA_MESSAGE && input == I_ROUTER) {
const char *op = cl_get_string(
((ha_msg_input_t*)data)->msg, F_CRM_TASK);
if(safe_str_eq(op, CRM_OP_VOTE)) {
/* It is always safe to treat N successive votes as
* a single one
*
* If all the discarded votes are more "loosing" than
* the first then the result is accurate
* (win or loose).
*
* If any of the discarded votes are less "loosing"
* than the first then we will cast our vote and the
* eventual winner will vote us down again (which
* even in the case that N=2, is no worse than if we
* had not disarded the vote).
*/
crm_verbose("Vote compression: %d", old_len);
return;
}
} else if (cause == C_HA_MESSAGE && input == I_ROUTER) {
const char *op = cl_get_string(
((ha_msg_input_t*)data)->msg, F_CRM_TASK);
if(safe_str_eq(op, CRM_OP_VOTE)) {
last_was_vote = TRUE;
crm_devel("Added vote: %d", old_len);
}
} else {
last_was_vote = FALSE;
}
crm_malloc(fsa_data, sizeof(fsa_data_t));
fsa_data->id = ++last_data_id;
fsa_data->fsa_input = input;
fsa_data->fsa_cause = cause;
fsa_data->origin = raised_from;
fsa_data->data = NULL;
fsa_data->data_type = fsa_dt_none;
fsa_data->actions = with_actions;
if(with_actions != A_NOTHING) {
crm_devel("Adding actions %.16llx to input", with_actions);
}
if(data != NULL) {
switch(cause) {
case C_FSA_INTERNAL:
case C_CRMD_STATUS_CALLBACK:
case C_IPC_MESSAGE:
case C_HA_MESSAGE:
crm_devel("Copying %s data from %s as a HA msg",
fsa_cause2string(cause),
raised_from);
fsa_data->data = copy_ha_msg_input(data);
fsa_data->data_type = fsa_dt_ha_msg;
break;
case C_LRM_OP_CALLBACK:
crm_devel("Copying %s data from %s as lrm_op_t",
fsa_cause2string(cause),
raised_from);
fsa_data->data = copy_lrm_op((lrm_op_t*)data);
fsa_data->data_type = fsa_dt_lrm;
break;
case C_CCM_CALLBACK:
crm_devel("Copying %s data from %s as CCM data",
fsa_cause2string(cause),
raised_from);
fsa_data->data = copy_ccm_data(data);
fsa_data->data_type = fsa_dt_ccm;
break;
case C_SUBSYSTEM_CONNECT:
case C_LRM_MONITOR_CALLBACK:
case C_TIMER_POPPED:
case C_SHUTDOWN:
case C_HEARTBEAT_FAILED:
case C_HA_DISCONNECT:
case C_ILLEGAL:
case C_UNKNOWN:
case C_STARTUP:
crm_err("Copying %s data (from %s)"
" not yet implemented",
fsa_cause2string(cause), raised_from);
exit(1);
break;
}
crm_trace("%s data copied",
fsa_cause2string(fsa_data->fsa_cause));
}
/* make sure to free it properly later */
if(after) {
crm_trace("Appending input");
fsa_message_queue = g_list_append(fsa_message_queue, fsa_data);
} else {
crm_trace("Prepending input");
fsa_message_queue = g_list_prepend(fsa_message_queue, fsa_data);
}
crm_verbose("Queue len: %d -> %d", old_len,
g_list_length(fsa_message_queue));
fsa_dump_queue(LOG_DEV);
if(old_len == g_list_length(fsa_message_queue)){
crm_err("Couldnt add message to the queue");
}
}
void
fsa_dump_queue(int log_level)
{
if(log_level < (int)crm_log_level) {
return;
}
slist_iter(
data, fsa_data_t, fsa_message_queue, lpc,
do_crm_log(log_level, __FUNCTION__, NULL,
"queue[%d(%d)]: input %s raised by %s()\t(cause=%s)",
lpc, data->id, fsa_input2string(data->fsa_input),
data->origin, fsa_cause2string(data->fsa_cause));
);
}
ha_msg_input_t *
copy_ha_msg_input(ha_msg_input_t *orig)
{
ha_msg_input_t *input_copy = NULL;
crm_malloc(input_copy, sizeof(ha_msg_input_t));
if(orig != NULL) {
crm_trace("Copy msg");
input_copy->msg = ha_msg_copy(orig->msg);
if(orig->xml != NULL) {
crm_trace("Copy xml");
input_copy->xml = copy_xml_node_recursive(orig->xml);
}
} else {
crm_devel("No message to copy");
}
return input_copy;
}
void
delete_fsa_input(fsa_data_t *fsa_data)
{
lrm_op_t *op = NULL;
crm_data_t *foo = NULL;
struct crmd_ccm_data_s *ccm_input = NULL;
if(fsa_data == NULL) {
return;
}
crm_trace("About to free %s data",
fsa_cause2string(fsa_data->fsa_cause));
if(fsa_data->data != NULL) {
switch(fsa_data->data_type) {
case fsa_dt_ha_msg:
delete_ha_msg_input(fsa_data->data);
break;
case fsa_dt_xml:
foo = fsa_data->data;
free_xml(foo);
break;
case fsa_dt_lrm:
op = (lrm_op_t*)fsa_data->data;
crm_free(op->rsc->id);
crm_free(op->rsc->type);
crm_free(op->rsc->class);
crm_free(op->rsc->provider);
crm_free(op->rsc);
crm_free(op->user_data);
crm_free(op->output);
crm_free(op->rsc_id);
crm_free(op->app_name);
crm_free(op);
break;
case fsa_dt_ccm:
ccm_input = (struct crmd_ccm_data_s *)
fsa_data->data;
crm_free(ccm_input->oc);
crm_free(ccm_input);
break;
case fsa_dt_none:
if(fsa_data->data != NULL) {
crm_err("Dont know how to free %s data from %s",
fsa_cause2string(fsa_data->fsa_cause),
fsa_data->origin);
exit(1);
}
break;
}
crm_trace("%s data freed",
fsa_cause2string(fsa_data->fsa_cause));
}
crm_free(fsa_data);
}
/* returns the next message */
fsa_data_t *
get_message(void)
{
fsa_data_t* message = g_list_nth_data(fsa_message_queue, 0);
fsa_message_queue = g_list_remove(fsa_message_queue, message);
return message;
}
/* returns the current head of the FIFO queue */
gboolean
is_message(void)
{
return (g_list_length(fsa_message_queue) > 0);
}
void *
fsa_typed_data_adv(
fsa_data_t *fsa_data, enum fsa_data_type a_type, const char *caller)
{
void *ret_val = NULL;
if(fsa_data == NULL) {
do_crm_log(LOG_ERR, caller, NULL, "No FSA data available");
} else if(fsa_data->data == NULL) {
do_crm_log(LOG_ERR, caller, NULL, "No message data available");
} else if(fsa_data->data_type != a_type) {
do_crm_log(LOG_CRIT, caller, NULL,
"Message data was the wrong type! %d vs. requested=%d."
" Origin: %s",
fsa_data->data_type, a_type, fsa_data->origin);
CRM_ASSERT(fsa_data->data_type == a_type);
} else {
ret_val = fsa_data->data;
}
return ret_val;
}
/* A_MSG_ROUTE */
enum crmd_fsa_input
do_msg_route(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)
{
enum crmd_fsa_input result = I_NULL;
ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg);
gboolean routed = FALSE;
if(msg_data->fsa_cause != C_IPC_MESSAGE
&& msg_data->fsa_cause != C_HA_MESSAGE) {
/* dont try and route these */
crm_warn("Can only process HA and IPC messages");
return I_NULL;
}
/* try passing the buck first */
crm_trace("Attempting to route message");
routed = relay_message(input->msg, cause==C_IPC_MESSAGE);
if(routed == FALSE) {
crm_trace("Message wasn't routed... try handling locally");
/* calculate defer */
result = handle_message(input);
switch(result) {
case I_NULL:
break;
case I_DC_HEARTBEAT:
break;
case I_CIB_OP:
break;
/* what else should go here? */
default:
crm_trace("Defering local processing of message");
register_fsa_input_later(
cause, result, msg_data->data);
result = I_NULL;
break;
}
if(result == I_NULL) {
crm_trace("Message processed");
} else {
register_fsa_input(cause, result, msg_data->data);
}
} else {
crm_trace("Message routed...");
input->msg = NULL;
}
return I_NULL;
}
/*
* This method frees msg
*/
gboolean
send_request(HA_Message *msg, char **msg_reference)
{
gboolean was_sent = FALSE;
/* crm_xml_devel(request, "Final request..."); */
if(msg_reference != NULL) {
*msg_reference = crm_strdup(
cl_get_string(msg, XML_ATTR_REFERENCE));
}
was_sent = relay_message(msg, TRUE);
if(was_sent == FALSE) {
ha_msg_input_t *fsa_input = new_ha_msg_input(msg);
register_fsa_input(C_IPC_MESSAGE, I_ROUTER, fsa_input);
delete_ha_msg_input(fsa_input);
crm_msg_del(msg);
}
return was_sent;
}
/* unless more processing is required, relay_message is freed */
gboolean
relay_message(HA_Message *relay_message, gboolean originated_locally)
{
int is_for_dc = 0;
int is_for_dcib = 0;
int is_for_crm = 0;
int is_for_cib = 0;
int is_local = 0;
gboolean processing_complete = FALSE;
const char *host_to = cl_get_string(relay_message, F_CRM_HOST_TO);
const char *sys_to = cl_get_string(relay_message, F_CRM_SYS_TO);
const char *sys_from= cl_get_string(relay_message, F_CRM_SYS_FROM);
const char *type = cl_get_string(relay_message, F_TYPE);
const char *msg_error = NULL;
crm_devel("Routing message %s",
cl_get_string(relay_message, XML_ATTR_REFERENCE));
if(relay_message == NULL) {
msg_error = "Cannot route empty message";
} else if(safe_str_eq(CRM_OP_HELLO,
cl_get_string(relay_message, F_CRM_TASK))){
/* quietly ignore */
processing_complete = TRUE;
} else if(safe_str_neq(type, T_CRM)) {
msg_error = "Bad message type";
} else if(sys_to == NULL) {
msg_error = "Bad message destination: no subsystem";
}
if(msg_error != NULL) {
processing_complete = TRUE;
crm_err("%s", msg_error);
crm_log_message(LOG_WARNING, relay_message);
}
if(processing_complete) {
crm_msg_del(relay_message);
return TRUE;
}
processing_complete = TRUE;
is_for_dc = (strcmp(CRM_SYSTEM_DC, sys_to) == 0);
is_for_dcib = (strcmp(CRM_SYSTEM_DCIB, sys_to) == 0);
is_for_cib = (strcmp(CRM_SYSTEM_CIB, sys_to) == 0);
is_for_crm = (strcmp(CRM_SYSTEM_CRMD, sys_to) == 0);
is_local = 0;
if(host_to == NULL || strlen(host_to) == 0) {
if(is_for_dc) {
is_local = 0;
} else if(is_for_crm && originated_locally) {
is_local = 0;
} else {
is_local = 1;
}
} else if(strcmp(fsa_our_uname, host_to) == 0) {
is_local=1;
}
if(is_for_dc || is_for_dcib) {
if(AM_I_DC) {
ROUTER_RESULT("Message result: DC/CRMd process");
processing_complete = FALSE; /* more to be done by caller */
} else if(originated_locally
&& safe_str_neq(sys_from, CRM_SYSTEM_PENGINE)
&& safe_str_neq(sys_from, CRM_SYSTEM_TENGINE)) {
/* Neither the TE or PE should be sending messages
* to DC's on other nodes
*
* By definition, if we are no longer the DC, then
* the PE or TE's data should be discarded
*/
ROUTER_RESULT("Message result: External relay to DC");
send_msg_via_ha(fsa_cluster_conn, relay_message);
} else {
/* discard */
ROUTER_RESULT("Message result: Discard, not DC");
crm_msg_del(relay_message);
}
} else if(is_local && (is_for_crm || is_for_cib)) {
ROUTER_RESULT("Message result: CRMd process");
processing_complete = FALSE; /* more to be done by caller */
} else if(is_local) {
ROUTER_RESULT("Message result: Local relay");
send_msg_via_ipc(relay_message, sys_to);
} else {
ROUTER_RESULT("Message result: External relay");
send_msg_via_ha(fsa_cluster_conn, relay_message);
}
return processing_complete;
}
gboolean
crmd_authorize_message(ha_msg_input_t *client_msg, crmd_client_t *curr_client)
{
/* check the best case first */
const char *sys_from = cl_get_string(client_msg->msg, F_CRM_SYS_FROM);
char *uuid = NULL;
char *client_name = NULL;
char *major_version = NULL;
char *minor_version = NULL;
const char *filtered_from;
gpointer table_key = NULL;
gboolean auth_result = FALSE;
struct crm_subsystem_s *the_subsystem = NULL;
gboolean can_reply = FALSE; /* no-one has registered with this id */
const char *op = cl_get_string(client_msg->msg, F_CRM_TASK);
if (safe_str_neq(CRM_OP_HELLO, op)) {
if(sys_from == NULL) {
crm_warn("Message [%s] was had no value for %s... discarding",
cl_get_string(client_msg->msg, XML_ATTR_REFERENCE),
F_CRM_SYS_FROM);
return FALSE;
}
filtered_from = sys_from;
/* The CIB can have two names on the DC */
if(strcmp(sys_from, CRM_SYSTEM_DCIB) == 0)
filtered_from = CRM_SYSTEM_CIB;
if (g_hash_table_lookup (ipc_clients, filtered_from) != NULL) {
can_reply = TRUE; /* reply can be routed */
}
crm_verbose("Message reply can%s be routed from %s.",
can_reply?"":" not", sys_from);
if(can_reply == FALSE) {
crm_warn("Message [%s] not authorized",
cl_get_string(client_msg->msg, XML_ATTR_REFERENCE));
}
#if 0
if(ha_msg_value(msg, XML_ATTR_REFERENCE) == NULL) {
ha_msg_add(new_input->msg, XML_ATTR_REFERENCE, seq);
}
#endif
register_fsa_input(C_IPC_MESSAGE, I_ROUTER, client_msg);
return can_reply;
}
crm_devel("received client join msg");
crm_log_message(LOG_MSG, client_msg->msg);
auth_result = process_hello_message(
client_msg->xml, &uuid, &client_name,
&major_version, &minor_version);
if (auth_result == TRUE) {
if(client_name == NULL || uuid == NULL) {
crm_err("Bad client details (client_name=%s, uuid=%s)",
crm_str(client_name), crm_str(uuid));
auth_result = FALSE;
}
}
if (auth_result == TRUE) {
/* check version */
int mav = atoi(major_version);
int miv = atoi(minor_version);
crm_devel("Checking client version number");
if (mav < 0 || miv < 0) {
crm_err("Client version (%d:%d) is not acceptable",
mav, miv);
auth_result = FALSE;
}
crm_free(major_version);
crm_free(minor_version);
}
if (auth_result == TRUE) {
/* if we already have one of those clients
* only applies to te, pe etc. not admin clients
*/
if (strcmp(CRM_SYSTEM_PENGINE, client_name) == 0) {
the_subsystem = pe_subsystem;
} else if (strcmp(CRM_SYSTEM_TENGINE, client_name) == 0) {
the_subsystem = te_subsystem;
}
if (the_subsystem != NULL) {
/* do we already have one? */
crm_devel("Checking if %s is required/already connected",
client_name);
if(is_set(fsa_input_register,
the_subsystem->flag_connected)) {
auth_result = FALSE;
crm_warn("Bit\t%.16llx set in %.16llx",
the_subsystem->flag_connected,
fsa_input_register);
crm_err("Client %s is already connected",
client_name);
} else if(FALSE == is_set(fsa_input_register,
the_subsystem->flag_required)) {
auth_result = FALSE;
crm_warn("Bit\t%.16llx not set in %.16llx",
the_subsystem->flag_connected,
fsa_input_register);
crm_warn("Client %s joined but we dont need it",
client_name);
} else {
the_subsystem->ipc =
curr_client->client_channel;
}
} else {
table_key = (gpointer)
generate_hash_key(client_name, uuid);
}
}
if (auth_result == TRUE) {
if(table_key == NULL) {
table_key = (gpointer)crm_strdup(client_name);
}
crm_verbose("Accepted client %s", crm_str(table_key));
curr_client->table_key = table_key;
curr_client->sub_sys = crm_strdup(client_name);
curr_client->uuid = crm_strdup(uuid);
g_hash_table_insert (ipc_clients,
table_key,
curr_client->client_channel);
send_hello_message(curr_client->client_channel,
"n/a", CRM_SYSTEM_CRMD,
"0", "1");
crm_devel("Updated client list with %s", crm_str(table_key));
if(the_subsystem != NULL) {
set_bit_inplace(
fsa_input_register, the_subsystem->flag_connected);
}
G_main_set_trigger(fsa_source);
} else {
crm_warn("Rejected client logon request");
curr_client->client_channel->ch_status = IPC_DISC_PENDING;
}
if(uuid != NULL) crm_free(uuid);
if(minor_version != NULL) crm_free(minor_version);
if(major_version != NULL) crm_free(major_version);
if(client_name != NULL) crm_free(client_name);
/* hello messages should never be processed further */
return FALSE;
}
enum crmd_fsa_input
handle_message(ha_msg_input_t *stored_msg)
{
enum crmd_fsa_input next_input = I_NULL;
const char *type = NULL;
if(stored_msg == NULL || stored_msg->msg == NULL) {
crm_err("No message to handle");
return I_NULL;
}
type = cl_get_string(stored_msg->msg, F_CRM_MSG_TYPE);
if(safe_str_eq(type, XML_ATTR_REQUEST)) {
next_input = handle_request(stored_msg);
} else if(safe_str_eq(type, XML_ATTR_RESPONSE)) {
next_input = handle_response(stored_msg);
} else {
crm_err("Unknown message type: %s", type);
}
/* crm_verbose("%s: Next input is %s", __FUNCTION__, */
/* fsa_input2string(next_input)); */
return next_input;
}
enum crmd_fsa_input
handle_request(ha_msg_input_t *stored_msg)
{
HA_Message *msg = NULL;
enum crmd_fsa_input next_input = I_NULL;
const char *op = cl_get_string(stored_msg->msg, F_CRM_TASK);
const char *sys_to = cl_get_string(stored_msg->msg, F_CRM_SYS_TO);
const char *host_from = cl_get_string(stored_msg->msg, F_CRM_HOST_FROM);
crm_verbose("Received %s in state %s", op, fsa_state2string(fsa_state));
if(op == NULL) {
crm_err("Bad message");
crm_log_message(LOG_ERR, stored_msg->msg);
/*========== common actions ==========*/
} else if(strcmp(op, CRM_OP_NOOP) == 0) {
crm_debug("no-op");
} else if(strcmp(op, CRM_OP_VOTE) == 0) {
/* count the vote and decide what to do after that */
register_fsa_input_w_actions(
C_HA_MESSAGE, I_NULL, stored_msg, A_ELECTION_COUNT);
/* Sometimes we _must_ go into S_ELECTION */
if(fsa_state == S_HALT) {
crm_debug("Forcing an election from S_HALT");
next_input = I_ELECTION;
#if 0
} else if(AM_I_DC) {
/* This is the old way of doing things but what is gained? */
next_input = I_ELECTION;
#endif
}
} else if(strcmp(op, CRM_OP_LOCAL_SHUTDOWN) == 0) {
crm_shutdown(SIGTERM);
/*next_input = I_SHUTDOWN; */
next_input = I_NULL;
} else if(strcmp(op, CRM_OP_PING) == 0) {
/* eventually do some stuff to figure out
* if we /are/ ok
*/
crm_data_t *ping = createPingAnswerFragment(sys_to, "ok");
set_xml_property_copy(ping, "crmd_state",
fsa_state2string(fsa_state));
msg = create_reply(stored_msg->msg, ping);
if(relay_message(msg, TRUE) == FALSE) {
crm_msg_del(msg);
}
/* probably better to do this via signals on the
* local node
*/
} else if(strcmp(op, CRM_OP_DEBUG_UP) == 0) {
int level = get_crm_log_level();
set_crm_log_level(level+1);
crm_info("Debug set to %d (was %d)",
get_crm_log_level(), level);
} else if(strcmp(op, CRM_OP_DEBUG_DOWN) == 0) {
int level = get_crm_log_level();
set_crm_log_level(level-1);
crm_info("Debug set to %d (was %d)",
get_crm_log_level(), level);
} else if(strcmp(op, CRM_OP_WELCOME) == 0) {
next_input = I_JOIN_OFFER;
} else if(strcmp(op, CRM_OP_JOINACK) == 0) {
next_input = I_JOIN_RESULT;
/* this functionality should only be enabled if this is a development build */
} else if(CRM_DEV_BUILD && strcmp(op, CRM_OP_DIE) == 0/*constant condition*/) {
crm_warn("Test-only code: Killing the CRM without mercy");
crm_warn("Inhibiting respawns");
exit(100);
/*========== (NOT_DC)-Only Actions ==========*/
} else if(AM_I_DC == FALSE){
gboolean dc_match = safe_str_eq(host_from, fsa_our_dc);
if(dc_match || fsa_our_dc == NULL) {
if(strcmp(op, CRM_OP_HBEAT) == 0) {
crm_devel("Received DC heartbeat from %s",
host_from);
next_input = I_DC_HEARTBEAT;
} else if(fsa_our_dc == NULL) {
crm_warn("CRMd discarding request: %s"
" (DC: %s, from: %s)",
op, crm_str(fsa_our_dc), host_from);
crm_warn("Ignored Request");
crm_log_message(LOG_WARNING, stored_msg->msg);
} else if(strcmp(op, CRM_OP_SHUTDOWN) == 0) {
next_input = I_TERMINATE;
} else {
crm_err("CRMd didnt expect request: %s", op);
crm_log_message(LOG_ERR, stored_msg->msg);
}
} else {
crm_warn("Discarding %s op from %s", op, host_from);
}
/*========== DC-Only Actions ==========*/
} else if(AM_I_DC){
if(strcmp(op, CRM_OP_TEABORT) == 0) {
if(fsa_state != S_INTEGRATION) {
next_input = I_PE_CALC;
} else {
crm_devel("Ignoring %s in state %s."
" Waiting for the integration to"
" complete first.",
op, fsa_state2string(fsa_state));
}
} else if(strcmp(op, CRM_OP_TECOMPLETE) == 0) {
/* if(fsa_state == S_TRANSITION_ENGINE) { */
next_input = I_TE_SUCCESS;
/* } else { */
/* crm_warn("Op %s is only valid in state %s..." */
/* "We are in (%s)", */
/* op, */
/* fsa_state2string(S_TRANSITION_ENGINE), */
/* fsa_state2string(fsa_state)); */
/* } */
} else if(strcmp(op, CRM_OP_ANNOUNCE) == 0) {
next_input = I_NODE_JOIN;
} else if(strcmp(op, CRM_OP_SHUTDOWN) == 0) {
gboolean dc_match = safe_str_eq(host_from, fsa_our_dc);
if(dc_match) {
crm_err("We didnt ask to be shut down yet our"
" TE is telling us too."
" Better get out now!");
next_input = I_TERMINATE;
} else if(is_set(fsa_input_register, R_SHUTDOWN)) {
crm_err("We asked to be shut down, "
" are still the DC, yet another node"
" is askin us to shutdown!");
next_input = I_TERMINATE;
} else if(fsa_state != S_STOPPING) {
crm_warn("Another node is asking us to shutdown"
" but we think we're ok.");
next_input = I_ELECTION;
}
} else if(strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) {
/* a slave wants to shut down */
/* create cib fragment and add to message */
next_input = handle_shutdown_request(stored_msg->msg);
} else {
crm_err("Unexpected request (%s) sent to the DC", op);
crm_log_message(LOG_ERR, stored_msg->msg);
}
}
return next_input;
}
enum crmd_fsa_input
handle_response(ha_msg_input_t *stored_msg)
{
enum crmd_fsa_input next_input = I_NULL;
const char *op = cl_get_string(stored_msg->msg, F_CRM_TASK);
const char *sys_from = cl_get_string(stored_msg->msg, F_CRM_SYS_FROM);
const char *msg_ref = cl_get_string(stored_msg->msg, XML_ATTR_REFERENCE);
crm_verbose("Received %s %s in state %s",
op, XML_ATTR_RESPONSE, fsa_state2string(fsa_state));
if(op == NULL) {
crm_err("Bad message");
crm_log_message(LOG_ERR, stored_msg->msg);
} else if(AM_I_DC && strcmp(op, CRM_OP_WELCOME) == 0) {
next_input = I_JOIN_REQUEST;
} else if(AM_I_DC && strcmp(op, CRM_OP_JOINACK) == 0) {
next_input = I_JOIN_RESULT;
} else if(AM_I_DC && strcmp(op, CRM_OP_PECALC) == 0) {
if(safe_str_eq(msg_ref, fsa_pe_ref)) {
next_input = I_PE_SUCCESS;
} else {
crm_verbose("Skipping superceeded reply from %s",
sys_from);
}
} else if(strcmp(op, CRM_OP_VOTE) == 0
|| strcmp(op, CRM_OP_HBEAT) == 0
|| strcmp(op, CRM_OP_WELCOME) == 0
|| strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0
|| strcmp(op, CRM_OP_SHUTDOWN) == 0
|| strcmp(op, CRM_OP_ANNOUNCE) == 0) {
next_input = I_NULL;
} else if(strcmp(op, CRM_OP_CIB_CREATE) == 0
|| strcmp(op, CRM_OP_CIB_UPDATE) == 0
|| strcmp(op, CRM_OP_CIB_DELETE) == 0
|| strcmp(op, CRM_OP_CIB_REPLACE) == 0
|| strcmp(op, CRM_OP_CIB_ERASE) == 0) {
/* perhaps we should do somethign with these replies,
* especially check that the actions passed
*/
} else {
crm_err("Unexpected response (op=%s) sent to the %s",
op, AM_I_DC?"DC":"CRMd");
next_input = I_NULL;
}
return next_input;
}
enum crmd_fsa_input
handle_shutdown_request(HA_Message *stored_msg)
{
/* handle here to avoid potential version issues
* where the shutdown message/proceedure may have
* been changed in later versions.
*
* This way the DC is always in control of the shutdown
*/
crm_data_t *frag = NULL;
time_t now = time(NULL);
char *now_s = crm_itoa((int)now);
crm_data_t *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE);
const char *host_from= cl_get_string(stored_msg, F_CRM_HOST_FROM);
crm_info("Creating shutdown request for %s",host_from);
crm_log_message(LOG_MSG, stored_msg);
set_uuid(fsa_cluster_conn, node_state, XML_ATTR_UUID, host_from);
set_xml_property_copy(node_state, XML_ATTR_UNAME, host_from);
set_xml_property_copy(node_state, XML_CIB_ATTR_SHUTDOWN, now_s);
set_xml_property_copy(
node_state, XML_CIB_ATTR_EXPSTATE, CRMD_STATE_INACTIVE);
frag = create_cib_fragment(node_state, NULL);
/* cleanup intermediate steps */
free_xml(node_state);
crm_free(now_s);
fsa_cib_conn->cmds->modify(
- fsa_cib_conn, XML_CIB_TAG_STATUS, frag, NULL, cib_none);
+ fsa_cib_conn, XML_CIB_TAG_STATUS, frag, NULL,
+ cib_quorum_override);
free_xml(frag);
/* will be picked up by the TE as long as its running */
if(! is_set(fsa_input_register, R_TE_CONNECTED) ) {
register_fsa_input(C_HA_MESSAGE, I_PE_CALC, NULL);
}
return I_NULL;
}
/* frees msg upon completion */
gboolean
send_msg_via_ha(ll_cluster_t *hb_fd, HA_Message *msg)
{
int log_level = LOG_DEV;
gboolean broadcast = FALSE;
gboolean all_is_good = TRUE;
const char *op = cl_get_string(msg, F_CRM_TASK);
const char *sys_to = cl_get_string(msg, F_CRM_SYS_TO);
const char *host_to = cl_get_string(msg, F_CRM_HOST_TO);
if (msg == NULL) {
crm_err("Attempt to send NULL Message via HA failed.");
all_is_good = FALSE;
} else {
crm_trace("Relaying message to (%s) via HA", host_to);
}
if (all_is_good) {
if (sys_to == NULL || strlen(sys_to) == 0) {
crm_err("You did not specify a destination sub-system"
" for this message.");
all_is_good = FALSE;
}
}
/* There are a number of messages may not need to be ordered.
* At a later point perhaps we should detect them and send them
* as unordered messages.
*/
if (all_is_good) {
if (host_to == NULL
|| strlen(host_to) == 0
|| safe_str_eq(sys_to, CRM_SYSTEM_DC)) {
broadcast = TRUE;
all_is_good = send_ha_message(hb_fd, msg, NULL);
} else {
all_is_good = send_ha_message(hb_fd, msg, host_to);
}
}
if(all_is_good == FALSE) {
log_level = LOG_ERR;
}
if(log_level == LOG_ERR
|| (safe_str_neq(op, CRM_OP_HBEAT))) {
do_crm_log(log_level, __FUNCTION__, NULL,
"Sending %sHA message (ref=%s) to %s@%s %s.",
broadcast?"broadcast ":"directed ",
cl_get_string(msg, XML_ATTR_REFERENCE),
crm_str(sys_to), host_to==NULL?"<all>":host_to,
all_is_good?"succeeded":"failed");
}
crm_msg_del(msg);
return all_is_good;
}
/* msg is deleted by the time this returns */
gboolean
send_msg_via_ipc(HA_Message *msg, const char *sys)
{
gboolean send_ok = TRUE;
IPC_Channel *client_channel;
enum crmd_fsa_input next_input;
crm_trace("relaying msg to sub_sys=%s via IPC", sys);
client_channel =
(IPC_Channel*)g_hash_table_lookup(ipc_clients, sys);
if(cl_get_string(msg, F_CRM_HOST_FROM) == NULL) {
ha_msg_add(msg, F_CRM_HOST_FROM, fsa_our_uname);
}
if (client_channel != NULL) {
crm_devel("Sending message via channel %s.", sys);
send_ok = send_ipc_message(client_channel, msg);
msg = NULL; /* so the crm_msg_del() below doesnt fail */
} else if(sys != NULL && strcmp(sys, CRM_SYSTEM_CIB) == 0) {
crm_err("Sub-system (%s) has been incorporated into the CRMd.",
sys);
crm_err("Change the way we handle this CIB message");
crm_log_message(LOG_ERR, msg);
send_ok = FALSE;
} else if(sys != NULL && strcmp(sys, CRM_SYSTEM_LRMD) == 0) {
fsa_data_t *fsa_data = NULL;
ha_msg_input_t *msg_copy = new_ha_msg_input(msg);
crm_malloc(fsa_data, sizeof(fsa_data_t));
fsa_data->fsa_input = I_MESSAGE;
fsa_data->fsa_cause = C_IPC_MESSAGE;
fsa_data->data = msg_copy;
fsa_data->origin = __FUNCTION__;
fsa_data->data_type = fsa_dt_ha_msg;
#ifdef FSA_TRACE
crm_verbose("Invoking action %s (%.16llx)",
fsa_action2string(A_LRM_INVOKE),
A_LRM_INVOKE);
#endif
next_input = do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE,
fsa_state, I_MESSAGE, fsa_data);
delete_ha_msg_input(msg_copy);
crm_free(fsa_data);
/* todo: feed this back in for anything != I_NULL */
#ifdef FSA_TRACE
crm_verbose("Result of action %s was %s",
fsa_action2string(A_LRM_INVOKE),
fsa_input2string(next_input));
#endif
} else {
crm_err("Unknown Sub-system (%s)... discarding message.", sys);
send_ok = FALSE;
}
crm_msg_del(msg);
return send_ok;
}
void
msg_queue_helper(void)
{
IPC_Channel *ipc = NULL;
if(fsa_cluster_conn != NULL) {
ipc = fsa_cluster_conn->llc_ops->ipcchan(
fsa_cluster_conn);
}
if(ipc != NULL) {
ipc->ops->is_message_pending(ipc);
}
/* g_hash_table_foreach_remove(ipc_clients, ipc_queue_helper, NULL); */
}
gboolean
ipc_queue_helper(gpointer key, gpointer value, gpointer user_data)
{
crmd_client_t *ipc_client = value;
if(ipc_client->client_channel != NULL) {
ipc_client->client_channel->ops->is_message_pending(ipc_client->client_channel);
}
return FALSE;
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 10, 1:34 AM (20 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2009530
Default Alt Text
(95 KB)

Event Timeline