Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F1841551
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
51 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/crmd/membership.c b/crmd/membership.c
index 391b004bc5..d2fe25f01a 100644
--- a/crmd/membership.c
+++ b/crmd/membership.c
@@ -1,300 +1,307 @@
/*
* 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* put these first so that uuid_t is defined without conflicts */
#include <crm_internal.h>
#include <string.h>
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/cluster/internal.h>
#include <crmd_messages.h>
#include <crmd_fsa.h>
#include <fsa_proto.h>
#include <crmd_callbacks.h>
#include <tengine.h>
#include <membership.h>
gboolean membership_flux_hack = FALSE;
void post_cache_update(int instance);
int last_peer_update = 0;
extern GHashTable *voted;
struct update_data_s {
const char *caller;
xmlNode *parent;
int flags;
};
extern gboolean check_join_state(enum crmd_fsa_state cur_state, const char *source);
static void
check_dead_member(const char *uname, GHashTable * members)
{
CRM_CHECK(uname != NULL, return);
if (members != NULL && g_hash_table_lookup(members, uname) != NULL) {
crm_err("%s didnt really leave the membership!", uname);
return;
}
erase_node_from_join(uname);
if (voted != NULL) {
g_hash_table_remove(voted, uname);
}
if (safe_str_eq(fsa_our_uname, uname)) {
crm_err("We're not part of the cluster anymore");
register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL);
} else if (AM_I_DC == FALSE && safe_str_eq(uname, fsa_our_dc)) {
crm_warn("Our DC node (%s) left the cluster", uname);
register_fsa_input(C_FSA_INTERNAL, I_ELECTION, NULL);
} else if (fsa_state == S_INTEGRATION || fsa_state == S_FINALIZE_JOIN) {
check_join_state(fsa_state, __FUNCTION__);
}
}
static void
reap_dead_nodes(gpointer key, gpointer value, gpointer user_data)
{
crm_node_t *node = value;
if (crm_is_peer_active(node) == FALSE) {
check_dead_member(node->uname, NULL);
fail_incompletable_actions(transition_graph, node->uuid);
}
}
gboolean ever_had_quorum = FALSE;
void
post_cache_update(int instance)
{
xmlNode *no_op = NULL;
crm_peer_seq = instance;
crm_debug("Updated cache after membership event %d.", instance);
g_hash_table_foreach(crm_peer_cache, reap_dead_nodes, NULL);
set_bit(fsa_input_register, R_MEMBERSHIP);
if (AM_I_DC) {
populate_cib_nodes(node_update_quick|node_update_cluster|node_update_peer|node_update_expected, __FUNCTION__);
}
/*
* If we lost nodes, we should re-check the election status
* Safe to call outside of an election
*/
register_fsa_action(A_ELECTION_CHECK);
/* Membership changed, remind everyone we're here.
* This will aid detection of duplicate DCs
*/
no_op = create_request(CRM_OP_NOOP, NULL, NULL, CRM_SYSTEM_CRMD,
AM_I_DC ? CRM_SYSTEM_DC : CRM_SYSTEM_CRMD, NULL);
send_cluster_message(NULL, crm_msg_crmd, no_op, FALSE);
free_xml(no_op);
}
static void
crmd_node_update_complete(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
{
fsa_data_t *msg_data = NULL;
last_peer_update = 0;
if (rc == pcmk_ok) {
crm_trace("Node update %d complete", call_id);
} else {
crm_err("Node update %d failed", call_id);
crm_log_xml_debug(msg, "failed");
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
}
}
xmlNode *
do_update_node_cib(crm_node_t *node, int flags, xmlNode *parent, const char *source)
{
const char *value = NULL;
xmlNode *node_state = create_xml_node(parent, XML_CIB_TAG_STATE);
set_uuid(node_state, XML_ATTR_UUID, node->uname);
+
+ if(crm_element_value(node_state, XML_ATTR_UUID) == NULL) {
+ crm_info("Node update for %s cancelled: no id", node->uname);
+ free_xml(node_state);
+ return NULL;
+ }
+
crm_xml_add(node_state, XML_ATTR_UNAME, node->uname);
if(flags & node_update_cluster) {
if (safe_str_eq(node->state, CRM_NODE_ACTIVE)) {
value = XML_BOOLEAN_YES;
} else if(node->state) {
value = XML_BOOLEAN_NO;
} else {
value = NULL;
}
crm_xml_add(node_state, XML_NODE_IN_CLUSTER, value);
}
if(flags & node_update_peer) {
value = OFFLINESTATUS;
if (node->processes & proc_flags) {
value = ONLINESTATUS;
}
crm_xml_add(node_state, XML_NODE_IS_PEER, value);
}
if(flags & node_update_join) {
const char *peer_member = g_hash_table_lookup(confirmed_nodes, node->uname);
if (peer_member != NULL) {
value = CRMD_JOINSTATE_MEMBER;
} else {
value = CRMD_JOINSTATE_DOWN;
}
crm_xml_add(node_state, XML_NODE_JOIN_STATE, value);
}
if(flags & node_update_expected) {
crm_xml_add(node_state, XML_NODE_EXPECTED, node->expected);
}
crm_xml_add(node_state, XML_ATTR_ORIGIN, source);
return node_state;
}
static void
ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data)
{
crm_node_t *node = value;
struct update_data_s *data = (struct update_data_s *)user_data;
do_update_node_cib(node, data->flags, data->parent, data->caller);
}
static void
create_cib_node_definition(gpointer key, gpointer value, gpointer user_data)
{
crm_node_t *node = value;
xmlNode *cib_nodes = user_data;
xmlNode *cib_new_node = NULL;
crm_trace("Creating node entry for %s/%s", node->uname, node->uuid);
cib_new_node = create_xml_node(cib_nodes, XML_CIB_TAG_NODE);
crm_xml_add(cib_new_node, XML_ATTR_ID, node->uuid);
crm_xml_add(cib_new_node, XML_ATTR_UNAME, node->uname);
}
void
populate_cib_nodes(enum node_update_flags flags, const char *source)
{
int call_id = 0;
gboolean from_hashtable = TRUE;
int call_options = cib_scope_local | cib_quorum_override;
xmlNode *node_list = create_xml_node(NULL, XML_CIB_TAG_NODES);
#if SUPPORT_HEARTBEAT
if (is_not_set(flags, node_update_quick) && is_heartbeat_cluster()) {
from_hashtable = heartbeat_initialize_nodelist(fsa_cluster_conn, FALSE, node_list);
}
#endif
#if SUPPORT_COROSYNC
if (is_not_set(flags, node_update_quick) && is_corosync_cluster()) {
from_hashtable = corosync_initialize_nodelist(NULL, FALSE, node_list);
}
#endif
if(from_hashtable) {
/* if(uname_is_uuid()) { */
/* g_hash_table_foreach(crm_peer_id_cache, create_cib_node_definition, node_list); */
/* } else { */
g_hash_table_foreach(crm_peer_cache, create_cib_node_definition, node_list);
/* } */
}
crm_trace("Populating <nodes> section from %s", from_hashtable?"hashtable":"cluster");
fsa_cib_update(XML_CIB_TAG_NODES, node_list, call_options, call_id, NULL);
add_cib_op_callback(fsa_cib_conn, call_id, FALSE, NULL, default_cib_update_callback);
free_xml(node_list);
if (crm_peer_cache != NULL && AM_I_DC) {
/*
* There is no need to update the local CIB with our values if
* we've not seen valid membership data
*/
struct update_data_s update_data;
node_list = create_xml_node(NULL, XML_CIB_TAG_STATUS);
update_data.caller = source;
update_data.parent = node_list;
update_data.flags = flags;
g_hash_table_foreach(crm_peer_cache, ghash_update_cib_node, &update_data);
fsa_cib_update(XML_CIB_TAG_STATUS, node_list, call_options, call_id, NULL);
add_cib_op_callback(fsa_cib_conn, call_id, FALSE, NULL, crmd_node_update_complete);
last_peer_update = call_id;
free_xml(node_list);
}
}
static void
cib_quorum_update_complete(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
{
fsa_data_t *msg_data = NULL;
if (rc == pcmk_ok) {
crm_trace("Quorum update %d complete", call_id);
} else {
crm_err("Quorum update %d failed", call_id);
crm_log_xml_debug(msg, "failed");
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
}
}
void
crm_update_quorum(gboolean quorum, gboolean force_update)
{
ever_had_quorum |= quorum;
if (AM_I_DC && (force_update || fsa_has_quorum != quorum)) {
int call_id = 0;
xmlNode *update = NULL;
int call_options = cib_scope_local | cib_quorum_override;
update = create_xml_node(NULL, XML_TAG_CIB);
crm_xml_add_int(update, XML_ATTR_HAVE_QUORUM, quorum);
set_uuid(update, XML_ATTR_DC_UUID, fsa_our_uname);
fsa_cib_update(XML_TAG_CIB, update, call_options, call_id, NULL);
crm_debug("Updating quorum status to %s (call=%d)", quorum ? "true" : "false", call_id);
add_cib_op_callback(fsa_cib_conn, call_id, FALSE, NULL, cib_quorum_update_complete);
free_xml(update);
}
fsa_has_quorum = quorum;
}
diff --git a/crmd/te_actions.c b/crmd/te_actions.c
index ea709c4a7a..7d1a0e57de 100644
--- a/crmd/te_actions.c
+++ b/crmd/te_actions.c
@@ -1,517 +1,528 @@
/*
* 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <crm_internal.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <tengine.h>
#include <crmd_fsa.h>
#include <crmd_messages.h>
#include <crm/cluster.h>
char *te_uuid = NULL;
void send_rsc_command(crm_action_t * action);
static void
te_start_action_timer(crm_graph_t * graph, crm_action_t * action)
{
action->timer = calloc(1, sizeof(crm_action_timer_t));
action->timer->timeout = action->timeout;
action->timer->reason = timeout_action;
action->timer->action = action;
action->timer->source_id = g_timeout_add(action->timer->timeout + graph->network_delay,
action_timer_callback, (void *)action->timer);
CRM_ASSERT(action->timer->source_id != 0);
}
static gboolean
te_pseudo_action(crm_graph_t * graph, crm_action_t * pseudo)
{
crm_debug("Pseudo action %d fired and confirmed", pseudo->id);
pseudo->confirmed = TRUE;
update_graph(graph, pseudo);
trigger_graph();
return TRUE;
}
void
send_stonith_update(crm_action_t * action, const char *target, const char *uuid)
{
int rc = pcmk_ok;
crm_node_t *peer = NULL;
/* zero out the node-status & remove all LRM status info */
- xmlNode *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE);
+ xmlNode *node_state = NULL;
CRM_CHECK(target != NULL, return);
CRM_CHECK(uuid != NULL, return);
+ if(get_node_uuid(0, target) == NULL) {
+ set_node_uuid(target, uuid);
+ }
+
/* Make sure the membership and join caches are accurate */
peer = crm_get_peer(0, target);
+ if(peer->uuid == NULL) {
+ crm_info("Recording uuid '%s' for node '%s'", uuid, target);
+ peer->uuid = strdup(uuid);
+ }
crm_update_peer_proc(__FUNCTION__, peer, crm_proc_none, NULL);
crm_update_peer_state(__FUNCTION__, peer, CRM_NODE_LOST, 0);
crm_update_peer_expected(__FUNCTION__, peer, CRMD_JOINSTATE_DOWN);
erase_node_from_join(target);
node_state = do_update_node_cib(peer, node_update_cluster|node_update_peer|node_update_join|node_update_expected, NULL, __FUNCTION__);
+ /* Force our known ID */
+ crm_xml_add(node_state, XML_ATTR_UUID, uuid);
+
rc = fsa_cib_conn->cmds->update(fsa_cib_conn, XML_CIB_TAG_STATUS, node_state,
cib_quorum_override | cib_scope_local | cib_can_create);
/* Delay processing the trigger until the update completes */
crm_debug("Sending fencing update %d for %s", rc, target);
add_cib_op_callback(fsa_cib_conn, rc, FALSE, strdup(target), cib_fencing_updated);
/* Make sure it sticks */
/* fsa_cib_conn->cmds->bump_epoch(fsa_cib_conn, cib_quorum_override|cib_scope_local); */
erase_status_tag(target, XML_CIB_TAG_LRM, cib_scope_local);
erase_status_tag(target, XML_TAG_TRANSIENT_NODEATTRS, cib_scope_local);
free_xml(node_state);
return;
}
static gboolean
te_fence_node(crm_graph_t * graph, crm_action_t * action)
{
int rc = 0;
const char *id = NULL;
const char *uuid = NULL;
const char *target = NULL;
const char *type = NULL;
gboolean invalid_action = FALSE;
enum stonith_call_options options = st_opt_none;
id = ID(action->xml);
target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID);
type = crm_meta_value(action->params, "stonith_action");
CRM_CHECK(id != NULL, invalid_action = TRUE);
CRM_CHECK(uuid != NULL, invalid_action = TRUE);
CRM_CHECK(type != NULL, invalid_action = TRUE);
CRM_CHECK(target != NULL, invalid_action = TRUE);
if (invalid_action) {
crm_log_xml_warn(action->xml, "BadAction");
return FALSE;
}
crm_notice("Executing %s fencing operation (%s) on %s (timeout=%d)",
type, id, target, transition_graph->stonith_timeout);
/* Passing NULL means block until we can connect... */
te_connect_stonith(NULL);
if (confirmed_nodes && g_hash_table_size(confirmed_nodes) == 1) {
options |= st_opt_allow_suicide;
}
rc = stonith_api->cmds->fence(stonith_api, options, target, type,
transition_graph->stonith_timeout / 1000);
stonith_api->cmds->register_callback(
stonith_api, rc, transition_graph->stonith_timeout / 1000,
FALSE, generate_transition_key(transition_graph->id, action->id, 0, te_uuid),
"tengine_stonith_callback", tengine_stonith_callback);
return TRUE;
}
static int
get_target_rc(crm_action_t * action)
{
const char *target_rc_s = crm_meta_value(action->params, XML_ATTR_TE_TARGET_RC);
if (target_rc_s != NULL) {
return crm_parse_int(target_rc_s, "0");
}
return 0;
}
static gboolean
te_crm_command(crm_graph_t * graph, crm_action_t * action)
{
char *counter = NULL;
xmlNode *cmd = NULL;
gboolean is_local = FALSE;
const char *id = NULL;
const char *task = NULL;
const char *value = NULL;
const char *on_node = NULL;
gboolean rc = TRUE;
gboolean no_wait = FALSE;
id = ID(action->xml);
task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
CRM_CHECK(on_node != NULL && strlen(on_node) != 0,
crm_err( "Corrupted command (id=%s) %s: no node",
crm_str(id), crm_str(task));
return FALSE);
crm_info( "Executing crm-event (%s): %s on %s%s%s",
crm_str(id), crm_str(task), on_node,
is_local ? " (local)" : "", no_wait ? " - no waiting" : "");
if (safe_str_eq(on_node, fsa_our_uname)) {
is_local = TRUE;
}
value = crm_meta_value(action->params, XML_ATTR_TE_NOWAIT);
if (crm_is_true(value)) {
no_wait = TRUE;
}
if (is_local && safe_str_eq(task, CRM_OP_SHUTDOWN)) {
/* defer until everything else completes */
crm_info( "crm-event (%s) is a local shutdown", crm_str(id));
graph->completion_action = tg_shutdown;
graph->abort_reason = "local shutdown";
action->confirmed = TRUE;
update_graph(graph, action);
trigger_graph();
return TRUE;
} else if(safe_str_eq(task, CRM_OP_SHUTDOWN)) {
crm_node_t *peer = crm_get_peer(0, on_node);
crm_update_peer_expected(__FUNCTION__, peer, CRMD_JOINSTATE_DOWN);
}
cmd = create_request(task, action->xml, on_node, CRM_SYSTEM_CRMD, CRM_SYSTEM_TENGINE, NULL);
counter =
generate_transition_key(transition_graph->id, action->id, get_target_rc(action), te_uuid);
crm_xml_add(cmd, XML_ATTR_TRANSITION_KEY, counter);
rc = send_cluster_message(on_node, crm_msg_crmd, cmd, TRUE);
free(counter);
free_xml(cmd);
if (rc == FALSE) {
crm_err("Action %d failed: send", action->id);
return FALSE;
} else if (no_wait) {
action->confirmed = TRUE;
update_graph(graph, action);
trigger_graph();
} else {
if (action->timeout <= 0) {
crm_err("Action %d: %s on %s had an invalid timeout (%dms). Using %dms instead",
action->id, task, on_node, action->timeout, graph->network_delay);
action->timeout = graph->network_delay;
}
te_start_action_timer(graph, action);
}
return TRUE;
}
gboolean
cib_action_update(crm_action_t * action, int status, int op_rc)
{
lrmd_event_data_t *op = NULL;
xmlNode *state = NULL;
xmlNode *rsc = NULL;
xmlNode *xml_op = NULL;
xmlNode *action_rsc = NULL;
int rc = pcmk_ok;
const char *name = NULL;
const char *value = NULL;
const char *rsc_id = NULL;
const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
const char *task_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
const char *target_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID);
int call_options = cib_quorum_override | cib_scope_local;
int target_rc = get_target_rc(action);
if (status == PCMK_LRM_OP_PENDING) {
crm_debug("%s %d: Recording pending operation %s on %s",
crm_element_name(action->xml), action->id, task_uuid, target);
} else {
crm_warn("%s %d: %s on %s timed out",
crm_element_name(action->xml), action->id, task_uuid, target);
}
action_rsc = find_xml_node(action->xml, XML_CIB_TAG_RESOURCE, TRUE);
if (action_rsc == NULL) {
return FALSE;
}
rsc_id = ID(action_rsc);
CRM_CHECK(rsc_id != NULL, crm_log_xml_err(action->xml, "Bad:action");
return FALSE);
/*
update the CIB
<node_state id="hadev">
<lrm>
<lrm_resources>
<lrm_resource id="rsc2" last_op="start" op_code="0" target="hadev"/>
*/
state = create_xml_node(NULL, XML_CIB_TAG_STATE);
crm_xml_add(state, XML_ATTR_UUID, target_uuid);
crm_xml_add(state, XML_ATTR_UNAME, target);
rsc = create_xml_node(state, XML_CIB_TAG_LRM);
crm_xml_add(rsc, XML_ATTR_ID, target_uuid);
rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCES);
rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCE);
crm_xml_add(rsc, XML_ATTR_ID, rsc_id);
name = XML_ATTR_TYPE;
value = crm_element_value(action_rsc, name);
crm_xml_add(rsc, name, value);
name = XML_AGENT_ATTR_CLASS;
value = crm_element_value(action_rsc, name);
crm_xml_add(rsc, name, value);
name = XML_AGENT_ATTR_PROVIDER;
value = crm_element_value(action_rsc, name);
crm_xml_add(rsc, name, value);
op = convert_graph_action(NULL, action, status, op_rc);
op->call_id = -1;
op->user_data = generate_transition_key(transition_graph->id, action->id, target_rc, te_uuid);
xml_op = create_operation_update(rsc, op, CRM_FEATURE_SET, target_rc, __FUNCTION__, LOG_INFO);
lrmd_free_event(op);
crm_trace("Updating CIB with \"%s\" (%s): %s %s on %s",
status < 0 ? "new action" : XML_ATTR_TIMEOUT,
crm_element_name(action->xml), crm_str(task), rsc_id, target);
crm_log_xml_trace(xml_op, "Op");
rc = fsa_cib_conn->cmds->update(fsa_cib_conn, XML_CIB_TAG_STATUS, state, call_options);
crm_trace("Updating CIB with %s action %d: %s on %s (call_id=%d)",
services_lrm_status_str(status), action->id, task_uuid, target, rc);
add_cib_op_callback(fsa_cib_conn, rc, FALSE, NULL, cib_action_updated);
free_xml(state);
action->sent_update = TRUE;
if (rc < pcmk_ok) {
return FALSE;
}
return TRUE;
}
static gboolean
te_rsc_command(crm_graph_t * graph, crm_action_t * action)
{
/* never overwrite stop actions in the CIB with
* anything other than completed results
*
* Writing pending stops makes it look like the
* resource is running again
*/
xmlNode *cmd = NULL;
xmlNode *rsc_op = NULL;
gboolean rc = TRUE;
gboolean no_wait = FALSE;
gboolean is_local = FALSE;
char *counter = NULL;
const char *task = NULL;
const char *value = NULL;
const char *on_node = NULL;
const char *task_uuid = NULL;
CRM_ASSERT(action != NULL);
CRM_ASSERT(action->xml != NULL);
action->executed = FALSE;
on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
CRM_CHECK(on_node != NULL && strlen(on_node) != 0,
crm_err( "Corrupted command(id=%s) %s: no node",
ID(action->xml), crm_str(task));
return FALSE);
rsc_op = action->xml;
task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
task_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
on_node = crm_element_value(rsc_op, XML_LRM_ATTR_TARGET);
counter =
generate_transition_key(transition_graph->id, action->id, get_target_rc(action), te_uuid);
crm_xml_add(rsc_op, XML_ATTR_TRANSITION_KEY, counter);
if (safe_str_eq(on_node, fsa_our_uname)) {
is_local = TRUE;
}
value = crm_meta_value(action->params, XML_ATTR_TE_NOWAIT);
if (crm_is_true(value)) {
no_wait = TRUE;
}
crm_info("Initiating action %d: %s %s on %s%s%s",
action->id, task, task_uuid, on_node,
is_local ? " (local)" : "", no_wait ? " - no waiting" : "");
cmd = create_request(CRM_OP_INVOKE_LRM, rsc_op, on_node,
CRM_SYSTEM_LRMD, CRM_SYSTEM_TENGINE, NULL);
if (is_local) {
/* shortcut local resource commands */
ha_msg_input_t data = {
.msg = cmd,
.xml = rsc_op,
};
fsa_data_t msg = {
.id = 0,
.data = &data,
.data_type = fsa_dt_ha_msg,
.fsa_input = I_NULL,
.fsa_cause = C_FSA_INTERNAL,
.actions = A_LRM_INVOKE,
.origin = __FUNCTION__,
};
do_lrm_invoke(A_LRM_INVOKE, C_FSA_INTERNAL, fsa_state, I_NULL, &msg);
} else {
rc = send_cluster_message(on_node, crm_msg_lrmd, cmd, TRUE);
}
free(counter);
free_xml(cmd);
action->executed = TRUE;
if (rc == FALSE) {
crm_err("Action %d failed: send", action->id);
return FALSE;
} else if (no_wait) {
action->confirmed = TRUE;
update_graph(transition_graph, action);
trigger_graph();
} else {
if (action->timeout <= 0) {
crm_err("Action %d: %s %s on %s had an invalid timeout (%dms). Using %dms instead",
action->id, task, task_uuid, on_node, action->timeout, graph->network_delay);
action->timeout = graph->network_delay;
}
te_start_action_timer(graph, action);
}
value = crm_meta_value(action->params, XML_OP_ATTR_PENDING);
if (crm_is_true(value)) {
/* write a "pending" entry to the CIB, inhibit notification */
crm_info("Recording pending op %s in the CIB", task_uuid);
cib_action_update(action, PCMK_LRM_OP_PENDING, PCMK_EXECRA_STATUS_UNKNOWN);
}
return TRUE;
}
crm_graph_functions_t te_graph_fns = {
te_pseudo_action,
te_rsc_command,
te_crm_command,
te_fence_node
};
void
notify_crmd(crm_graph_t * graph)
{
const char *type = "unknown";
enum crmd_fsa_input event = I_NULL;
crm_debug("Processing transition completion in state %s", fsa_state2string(fsa_state));
CRM_CHECK(graph->complete, graph->complete = TRUE);
switch (graph->completion_action) {
case tg_stop:
type = "stop";
/* fall through */
case tg_done:
type = "done";
if (fsa_state == S_TRANSITION_ENGINE) {
event = I_TE_SUCCESS;
}
break;
case tg_restart:
type = "restart";
if (fsa_state == S_TRANSITION_ENGINE) {
if (transition_timer->period_ms > 0) {
crm_timer_stop(transition_timer);
crm_timer_start(transition_timer);
} else if(too_many_st_failures() == FALSE) {
event = I_PE_CALC;
}
} else if (fsa_state == S_POLICY_ENGINE) {
register_fsa_action(A_PE_INVOKE);
}
break;
case tg_shutdown:
type = "shutdown";
if (is_set(fsa_input_register, R_SHUTDOWN)) {
event = I_STOP;
} else {
crm_err("We didn't ask to be shut down, yet our" " PE is telling us too.");
event = I_TERMINATE;
}
}
crm_debug( "Transition %d status: %s - %s",
graph->id, type, crm_str(graph->abort_reason));
graph->abort_reason = NULL;
graph->completion_action = tg_done;
clear_bit(fsa_input_register, R_IN_TRANSITION);
if (event != I_NULL) {
register_fsa_input(C_FSA_INTERNAL, event, NULL);
} else if (fsa_source) {
mainloop_set_trigger(fsa_source);
}
}
diff --git a/include/crm/cluster/internal.h b/include/crm/cluster/internal.h
index 6285836275..0779feada2 100644
--- a/include/crm/cluster/internal.h
+++ b/include/crm/cluster/internal.h
@@ -1,334 +1,335 @@
/*
* 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CRM_CLUSTER_INTERNAL__H
# define CRM_CLUSTER_INTERNAL__H
# include <crm/cluster.h>
# define AIS_IPC_NAME "ais-crm-ipc"
# define AIS_IPC_MESSAGE_SIZE 8192*128
# define CRM_MESSAGE_IPC_ACK 0
typedef struct crm_ais_host_s AIS_Host;
typedef struct crm_ais_msg_s AIS_Message;
enum crm_ais_msg_class {
crm_class_cluster = 0,
crm_class_members = 1,
crm_class_notify = 2,
crm_class_nodeid = 3,
crm_class_rmpeer = 4,
crm_class_quorum = 5,
};
/* order here matters - its used to index into the crm_children array */
enum crm_ais_msg_types {
crm_msg_none = 0,
crm_msg_ais = 1,
crm_msg_lrmd = 2,
crm_msg_cib = 3,
crm_msg_crmd = 4,
crm_msg_attrd = 5,
crm_msg_stonithd = 6,
crm_msg_te = 7,
crm_msg_pe = 8,
crm_msg_stonith_ng = 9,
};
struct crm_ais_host_s {
uint32_t id;
uint32_t pid;
gboolean local;
enum crm_ais_msg_types type;
uint32_t size;
char uname[MAX_NAME];
} __attribute__ ((packed));
struct crm_ais_msg_s {
cs_ipc_header_response_t header __attribute__ ((aligned(8)));
uint32_t id;
gboolean is_compressed;
AIS_Host host;
AIS_Host sender;
uint32_t size;
uint32_t compressed_size;
/* 584 bytes */
char data[0];
} __attribute__ ((packed));
struct crm_ais_nodeid_resp_s {
cs_ipc_header_response_t header __attribute__ ((aligned(8)));
uint32_t id;
uint32_t counter;
char uname[MAX_NAME];
char cname[MAX_NAME];
} __attribute__ ((packed));
struct crm_ais_quorum_resp_s {
cs_ipc_header_response_t header __attribute__ ((aligned(8)));
uint64_t id;
uint32_t votes;
uint32_t expected_votes;
uint32_t quorate;
} __attribute__ ((packed));
static inline enum crm_proc_flag
text2proc(const char *proc)
{
/* We only care about these two so far */
if(proc && strcmp(proc, "cib") == 0) {
return crm_proc_cib;
} else if(proc && strcmp(proc, "crmd") == 0) {
return crm_proc_crmd;
}
return crm_proc_none;
}
static inline const char *
ais_dest(const struct crm_ais_host_s *host)
{
if (host->local) {
return "local";
} else if (host->size > 0) {
return host->uname;
} else {
return "<all>";
}
}
# define ais_data_len(msg) (msg->is_compressed?msg->compressed_size:msg->size)
static inline AIS_Message *
ais_msg_copy(const AIS_Message * source)
{
AIS_Message *target = malloc(sizeof(AIS_Message) + ais_data_len(source));
memcpy(target, source, sizeof(AIS_Message));
memcpy(target->data, source->data, ais_data_len(target));
return target;
}
static inline const char *
ais_error2text(int error)
{
const char *text = "unknown";
# if SUPPORT_COROSYNC
switch (error) {
case CS_OK:
text = "None";
break;
case CS_ERR_LIBRARY:
text = "Library error";
break;
case CS_ERR_VERSION:
text = "Version error";
break;
case CS_ERR_INIT:
text = "Initialization error";
break;
case CS_ERR_TIMEOUT:
text = "Timeout";
break;
case CS_ERR_TRY_AGAIN:
text = "Try again";
break;
case CS_ERR_INVALID_PARAM:
text = "Invalid parameter";
break;
case CS_ERR_NO_MEMORY:
text = "No memory";
break;
case CS_ERR_BAD_HANDLE:
text = "Bad handle";
break;
case CS_ERR_BUSY:
text = "Busy";
break;
case CS_ERR_ACCESS:
text = "Access error";
break;
case CS_ERR_NOT_EXIST:
text = "Doesn't exist";
break;
case CS_ERR_NAME_TOO_LONG:
text = "Name too long";
break;
case CS_ERR_EXIST:
text = "Exists";
break;
case CS_ERR_NO_SPACE:
text = "No space";
break;
case CS_ERR_INTERRUPT:
text = "Interrupt";
break;
case CS_ERR_NAME_NOT_FOUND:
text = "Name not found";
break;
case CS_ERR_NO_RESOURCES:
text = "No resources";
break;
case CS_ERR_NOT_SUPPORTED:
text = "Not supported";
break;
case CS_ERR_BAD_OPERATION:
text = "Bad operation";
break;
case CS_ERR_FAILED_OPERATION:
text = "Failed operation";
break;
case CS_ERR_MESSAGE_ERROR:
text = "Message error";
break;
case CS_ERR_QUEUE_FULL:
text = "Queue full";
break;
case CS_ERR_QUEUE_NOT_AVAILABLE:
text = "Queue not available";
break;
case CS_ERR_BAD_FLAGS:
text = "Bad flags";
break;
case CS_ERR_TOO_BIG:
text = "To big";
break;
case CS_ERR_NO_SECTIONS:
text = "No sections";
break;
}
# endif
return text;
}
static inline const char *
msg_type2text(enum crm_ais_msg_types type)
{
const char *text = "unknown";
switch (type) {
case crm_msg_none:
text = "unknown";
break;
case crm_msg_ais:
text = "ais";
break;
case crm_msg_cib:
text = "cib";
break;
case crm_msg_crmd:
text = "crmd";
break;
case crm_msg_pe:
text = "pengine";
break;
case crm_msg_te:
text = "tengine";
break;
case crm_msg_lrmd:
text = "lrmd";
break;
case crm_msg_attrd:
text = "attrd";
break;
case crm_msg_stonithd:
text = "stonithd";
break;
case crm_msg_stonith_ng:
text = "stonith-ng";
break;
}
return text;
}
enum crm_ais_msg_types text2msg_type(const char *text);
char *get_ais_data(const AIS_Message * msg);
gboolean check_message_sanity(const AIS_Message * msg, const char *data);
# if SUPPORT_HEARTBEAT
extern ll_cluster_t *heartbeat_cluster;
gboolean send_ha_message(ll_cluster_t * hb_conn, xmlNode * msg,
const char *node, gboolean force_ordered);
gboolean ha_msg_dispatch(ll_cluster_t * cluster_conn, gpointer user_data);
gboolean register_heartbeat_conn(ll_cluster_t * hb_cluster, char **uuid, char **uname,
void (*hb_message) (HA_Message * msg, void *private_data),
void (*hb_destroy) (gpointer user_data));
xmlNode *convert_ha_message(xmlNode * parent, HA_Message *msg, const char *field);
gboolean ccm_have_quorum(oc_ed_t event);
const char *ccm_event_name(oc_ed_t event);
crm_node_t *crm_update_ccm_node(const oc_ev_membership_t * oc, int offset, const char *state,
uint64_t seq);
gboolean heartbeat_initialize_nodelist(void *cluster, gboolean force_member, xmlNode *xml_parent);
# endif
# if SUPPORT_COROSYNC
gboolean corosync_initialize_nodelist(void *cluster, gboolean force_member, xmlNode *xml_parent);
gboolean send_ais_message(xmlNode * msg, gboolean local,
const char *node, enum crm_ais_msg_types dest);
enum cluster_type_e find_corosync_variant(void);
void terminate_ais_connection(void);
gboolean init_ais_connection(gboolean(*dispatch) (AIS_Message *, char *, int),
void (*destroy) (gpointer), char **our_uuid, char **our_uname,
int *nodeid);
gboolean init_ais_connection_once(gboolean(*dispatch) (AIS_Message *, char *, int),
void (*destroy) (gpointer), char **our_uuid,
char **our_uname, int *nodeid);
# endif
enum crm_quorum_source {
crm_quorum_cman,
crm_quorum_corosync,
crm_quorum_pacemaker,
};
enum crm_quorum_source get_quorum_source(void);
void crm_update_peer_proc(const char *source, crm_node_t *peer, uint32_t flag, const char *status);
crm_node_t *crm_update_peer(
const char *source, unsigned int id, uint64_t born, uint64_t seen,
int32_t votes, uint32_t children, const char *uuid, const char *uname,
const char *addr, const char *state);
void crm_update_peer_expected(const char *source, crm_node_t *node, const char *expected);
void crm_update_peer_state(const char *source, crm_node_t *node, const char *state, int membership);
gboolean init_cman_connection(
gboolean(*dispatch) (unsigned long long, gboolean), void (*destroy) (gpointer));
gboolean init_quorum_connection(
gboolean(*dispatch) (unsigned long long, gboolean), void (*destroy) (gpointer));
+void set_node_uuid(const char *uname, const char *uuid);
#endif
diff --git a/lib/cluster/cluster.c b/lib/cluster/cluster.c
index 0df4d97c72..4ace407f92 100644
--- a/lib/cluster/cluster.c
+++ b/lib/cluster/cluster.c
@@ -1,517 +1,531 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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 library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <crm_internal.h>
#include <dlfcn.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/common/ipc.h>
#include <crm/cluster/internal.h>
CRM_TRACE_INIT_DATA(cluster);
#if SUPPORT_HEARTBEAT
void *hb_library = NULL;
#endif
static GHashTable *crm_uuid_cache = NULL;
static GHashTable *crm_uname_cache = NULL;
static char *
get_heartbeat_uuid(uint32_t unused, const char *uname)
{
char *uuid_calc = NULL;
#if SUPPORT_HEARTBEAT
cl_uuid_t uuid_raw;
const char *unknown = "00000000-0000-0000-0000-000000000000";
if (heartbeat_cluster == NULL) {
crm_warn("No connection to heartbeat, using uuid=uname");
return NULL;
}
if (heartbeat_cluster->llc_ops->get_uuid_by_name(heartbeat_cluster, uname, &uuid_raw) ==
HA_FAIL) {
crm_err("get_uuid_by_name() call failed for host %s", uname);
free(uuid_calc);
return NULL;
}
uuid_calc = calloc(1, 50);
cl_uuid_unparse(&uuid_raw, uuid_calc);
if (safe_str_eq(uuid_calc, unknown)) {
crm_warn("Could not calculate UUID for %s", uname);
free(uuid_calc);
return NULL;
}
#endif
return uuid_calc;
}
static gboolean
uname_is_uuid(void)
{
static const char *uuid_pref = NULL;
if (uuid_pref == NULL) {
uuid_pref = getenv("PCMK_uname_is_uuid");
}
if (uuid_pref == NULL) {
/* true is legacy mode */
uuid_pref = "false";
}
return crm_is_true(uuid_pref);
}
int
get_corosync_id(int id, const char *uuid)
{
if (id == 0 && !uname_is_uuid() && is_corosync_cluster()) {
id = crm_atoi(uuid, "0");
}
return id;
}
char *
get_corosync_uuid(uint32_t id, const char *uname)
{
if (!uname_is_uuid() && is_corosync_cluster()) {
if (id <= 0) {
/* Try the membership cache... */
crm_node_t *node = g_hash_table_lookup(crm_peer_cache, uname);
if (node != NULL) {
id = node->id;
}
}
if (id > 0) {
return crm_itoa(id);
} else {
crm_warn("Node %s is not yet known by corosync", uname);
}
} else if (uname != NULL) {
return strdup(uname);
}
return NULL;
}
+void
+set_node_uuid(const char *uname, const char *uuid)
+{
+ CRM_CHECK(uuid != NULL, return);
+ CRM_CHECK(uname != NULL, return);
+
+ if (crm_uuid_cache == NULL) {
+ crm_uuid_cache = g_hash_table_new_full(crm_str_hash, g_str_equal,
+ g_hash_destroy_str, g_hash_destroy_str);
+ }
+
+ g_hash_table_insert(crm_uuid_cache, strdup(uname), strdup(uuid));
+}
+
const char *
get_node_uuid(uint32_t id, const char *uname)
{
char *uuid = NULL;
enum cluster_type_e type = get_cluster_type();
if (crm_uuid_cache == NULL) {
crm_uuid_cache = g_hash_table_new_full(crm_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
}
/* avoid blocking heartbeat calls where possible */
if (uname) {
uuid = g_hash_table_lookup(crm_uuid_cache, uname);
}
if (uuid != NULL) {
return uuid;
}
switch (type) {
case pcmk_cluster_corosync:
uuid = get_corosync_uuid(id, uname);
break;
case pcmk_cluster_cman:
case pcmk_cluster_classic_ais:
if (uname) {
uuid = strdup(uname);
}
break;
case pcmk_cluster_heartbeat:
uuid = get_heartbeat_uuid(id, uname);
break;
case pcmk_cluster_unknown:
case pcmk_cluster_invalid:
crm_err("Unsupported cluster type");
break;
}
if (uuid == NULL) {
return NULL;
}
if (uname) {
g_hash_table_insert(crm_uuid_cache, strdup(uname), uuid);
return g_hash_table_lookup(crm_uuid_cache, uname);
}
/* Memory leak! */
CRM_LOG_ASSERT(uuid != NULL);
return uuid;
}
gboolean
crm_cluster_connect(char **our_uname, char **our_uuid, void *dispatch, void *destroy,
#if SUPPORT_HEARTBEAT
ll_cluster_t ** hb_conn
#else
void **hb_conn
#endif
)
{
enum cluster_type_e type = get_cluster_type();
crm_notice("Connecting to cluster infrastructure: %s", name_for_cluster_type(type));
if (hb_conn != NULL) {
*hb_conn = NULL;
}
#if SUPPORT_COROSYNC
if (is_openais_cluster()) {
crm_peer_init();
return init_ais_connection(dispatch, destroy, our_uuid, our_uname, NULL);
}
#endif
#if SUPPORT_HEARTBEAT
if (is_heartbeat_cluster()) {
int rv;
CRM_ASSERT(hb_conn != NULL);
/* coverity[var_deref_op] False positive */
if (*hb_conn == NULL) {
/* No object passed in, create a new one. */
ll_cluster_t *(*new_cluster) (const char *llctype) =
find_library_function(&hb_library, HEARTBEAT_LIBRARY, "ll_cluster_new", 1);
*hb_conn = (*new_cluster) ("heartbeat");
/* dlclose(handle); */
} else {
/* Object passed in. Disconnect first, then reconnect below. */
ll_cluster_t *conn = *hb_conn;
conn->llc_ops->signoff(conn, FALSE);
}
/* make sure we are disconnected first with the old object, if any. */
if (heartbeat_cluster && heartbeat_cluster != *hb_conn) {
heartbeat_cluster->llc_ops->signoff(heartbeat_cluster, FALSE);
}
CRM_ASSERT(*hb_conn != NULL);
heartbeat_cluster = *hb_conn;
rv = register_heartbeat_conn(heartbeat_cluster, our_uuid, our_uname, dispatch, destroy);
if (rv) {
/* we'll benefit from a bigger queue length on heartbeat side.
* Otherwise, if peers send messages faster than we can consume
* them right now, heartbeat messaging layer will kick us out once
* it's (small) default queue fills up :(
* If we fail to adjust the sendq length, that's not yet fatal, though.
*/
if (HA_OK != (*hb_conn)->llc_ops->set_sendq_len(*hb_conn, 1024)) {
crm_warn("Cannot set sendq length: %s", (*hb_conn)->llc_ops->errmsg(*hb_conn));
}
}
return rv;
}
#endif
crm_info("Unsupported cluster stack: %s", getenv("HA_cluster_type"));
return FALSE;
}
gboolean
send_cluster_message(const char *node, enum crm_ais_msg_types service, xmlNode * data,
gboolean ordered)
{
#if SUPPORT_COROSYNC
if (is_openais_cluster()) {
return send_ais_message(data, FALSE, node, service);
}
#endif
#if SUPPORT_HEARTBEAT
if (is_heartbeat_cluster()) {
return send_ha_message(heartbeat_cluster, data, node, ordered);
}
#endif
return FALSE;
}
void
empty_uuid_cache(void)
{
if (crm_uuid_cache != NULL) {
g_hash_table_destroy(crm_uuid_cache);
crm_uuid_cache = NULL;
}
}
void
unget_uuid(const char *uname)
{
if (crm_uuid_cache == NULL) {
return;
}
g_hash_table_remove(crm_uuid_cache, uname);
}
const char *
get_uuid(const char *uname)
{
return get_node_uuid(0, uname);
}
const char *
get_uname(const char *uuid)
{
const char *uname = NULL;
if (crm_uname_cache == NULL) {
crm_uname_cache = g_hash_table_new_full(crm_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
}
CRM_CHECK(uuid != NULL, return NULL);
/* avoid blocking calls where possible */
uname = g_hash_table_lookup(crm_uname_cache, uuid);
if (uname != NULL) {
crm_trace("%s = %s (cached)", uuid, uname);
return uname;
}
#if SUPPORT_COROSYNC
if (is_openais_cluster()) {
if (!uname_is_uuid() && is_corosync_cluster()) {
uint32_t id = crm_int_helper(uuid, NULL);
crm_node_t *node = g_hash_table_lookup(crm_peer_id_cache, GUINT_TO_POINTER(id));
uname = node ? node->uname : NULL;
} else {
uname = uuid;
}
if (uname) {
crm_trace("Storing %s = %s", uuid, uname);
g_hash_table_insert(crm_uname_cache, strdup(uuid), strdup(uname));
}
}
#endif
#if SUPPORT_HEARTBEAT
if (is_heartbeat_cluster()) {
if (heartbeat_cluster != NULL && uuid != NULL) {
cl_uuid_t uuid_raw;
char *hb_uname = NULL;
char *uuid_copy = strdup(uuid);
cl_uuid_parse(uuid_copy, &uuid_raw);
hb_uname = malloc( MAX_NAME);
if (heartbeat_cluster->llc_ops->get_name_by_uuid(heartbeat_cluster, &uuid_raw, hb_uname,
MAX_NAME) == HA_FAIL) {
crm_err("Could not calculate uname for %s", uuid);
free(uuid_copy);
free(hb_uname);
} else {
crm_trace("Storing %s = %s", uuid, uname);
g_hash_table_insert(crm_uname_cache, uuid_copy, hb_uname);
}
}
}
#endif
return g_hash_table_lookup(crm_uname_cache, uuid);
}
void
set_uuid(xmlNode * node, const char *attr, const char *uname)
{
const char *uuid_calc = get_uuid(uname);
crm_xml_add(node, attr, uuid_calc);
return;
}
const char *
name_for_cluster_type(enum cluster_type_e type)
{
switch (type) {
case pcmk_cluster_classic_ais:
return "classic openais (with plugin)";
case pcmk_cluster_cman:
return "cman";
case pcmk_cluster_corosync:
return "corosync";
case pcmk_cluster_heartbeat:
return "heartbeat";
case pcmk_cluster_unknown:
return "unknown";
case pcmk_cluster_invalid:
return "invalid";
}
crm_err("Invalid cluster type: %d", type);
return "invalid";
}
/* Do not expose these two */
int set_cluster_type(enum cluster_type_e type);
static enum cluster_type_e cluster_type = pcmk_cluster_unknown;
int
set_cluster_type(enum cluster_type_e type)
{
if (cluster_type == pcmk_cluster_unknown) {
crm_info("Cluster type set to: %s", name_for_cluster_type(type));
cluster_type = type;
return 0;
} else if (cluster_type == type) {
return 0;
} else if (pcmk_cluster_unknown == type) {
cluster_type = type;
return 0;
}
crm_err("Cluster type already set to %s, ignoring %s",
name_for_cluster_type(cluster_type), name_for_cluster_type(type));
return -1;
}
enum cluster_type_e
get_cluster_type(void)
{
if (cluster_type == pcmk_cluster_unknown) {
const char *cluster = getenv("HA_cluster_type");
cluster_type = pcmk_cluster_invalid;
if (cluster) {
crm_info("Cluster type is: '%s'", cluster);
} else {
#if SUPPORT_COROSYNC
cluster_type = find_corosync_variant();
if (cluster_type == pcmk_cluster_unknown) {
cluster = "heartbeat";
crm_info("Assuming a 'heartbeat' based cluster");
} else {
cluster = name_for_cluster_type(cluster_type);
crm_info("Detected an active '%s' cluster", cluster);
}
#else
cluster = "heartbeat";
#endif
}
if (safe_str_eq(cluster, "heartbeat")) {
#if SUPPORT_HEARTBEAT
cluster_type = pcmk_cluster_heartbeat;
#else
cluster_type = pcmk_cluster_invalid;
#endif
} else if (safe_str_eq(cluster, "openais")
|| safe_str_eq(cluster, "classic openais (with plugin)")) {
#if SUPPORT_COROSYNC
cluster_type = pcmk_cluster_classic_ais;
#else
cluster_type = pcmk_cluster_invalid;
#endif
} else if (safe_str_eq(cluster, "corosync")) {
#if SUPPORT_COROSYNC
cluster_type = pcmk_cluster_corosync;
#else
cluster_type = pcmk_cluster_invalid;
#endif
} else if (safe_str_eq(cluster, "cman")) {
#if SUPPORT_CMAN
cluster_type = pcmk_cluster_cman;
#else
cluster_type = pcmk_cluster_invalid;
#endif
} else {
cluster_type = pcmk_cluster_invalid;
}
if (cluster_type == pcmk_cluster_invalid) {
crm_notice
("This installation of Pacemaker does not support the '%s' cluster infrastructure. Terminating.",
cluster);
exit(100);
}
}
return cluster_type;
}
gboolean
is_cman_cluster(void)
{
return get_cluster_type() == pcmk_cluster_cman;
}
gboolean
is_corosync_cluster(void)
{
return get_cluster_type() == pcmk_cluster_corosync;
}
gboolean
is_classic_ais_cluster(void)
{
return get_cluster_type() == pcmk_cluster_classic_ais;
}
gboolean
is_openais_cluster(void)
{
enum cluster_type_e type = get_cluster_type();
if (type == pcmk_cluster_classic_ais) {
return TRUE;
} else if (type == pcmk_cluster_corosync) {
return TRUE;
} else if (type == pcmk_cluster_cman) {
return TRUE;
}
return FALSE;
}
gboolean
is_heartbeat_cluster(void)
{
return get_cluster_type() == pcmk_cluster_heartbeat;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 23, 5:40 AM (10 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1018264
Default Alt Text
(51 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment