Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4638870
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
95 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment