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;
 }