diff --git a/.pacemaker.metadata b/.pacemaker.metadata new file mode 100644 index 0000000..5133579 --- /dev/null +++ b/.pacemaker.metadata @@ -0,0 +1 @@ +e718c70b1a234d1864a78c26339706c39f73f1f6 SOURCES/Pacemaker-1.1.10.tar.gz diff --git a/README.md b/README.md deleted file mode 100644 index 0e7897f..0000000 --- a/README.md +++ /dev/null @@ -1,5 +0,0 @@ -The master branch has no content - -Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6 - -If you find this file in a distro specific branch, it means that no content has been checked in yet diff --git a/SOURCES/bz1011618-pcmk-consistently_use_slave_as_the_role_for_unpromoted_master_slave_resources.patch b/SOURCES/bz1011618-pcmk-consistently_use_slave_as_the_role_for_unpromoted_master_slave_resources.patch new file mode 100644 index 0000000..8877f65 --- /dev/null +++ b/SOURCES/bz1011618-pcmk-consistently_use_slave_as_the_role_for_unpromoted_master_slave_resources.patch @@ -0,0 +1,35 @@ +commit 6bb62a4a2b304de64d8ccf0e38ae6dd3c3d5e772 +Author: Andrew Beekhof +Date: Wed Sep 25 11:53:35 2013 +1000 + + Fix: Bug rhbz#1011618 - Consistently use 'Slave' as the role for unpromoted master/slave resources + + (cherry picked from commit bc5e0b677b7ee45c022496cb926f91bad3731974) + +diff --git a/lib/pengine/native.c b/lib/pengine/native.c +index c81a218..adfd5ba 100644 +--- a/lib/pengine/native.c ++++ b/lib/pengine/native.c +@@ -294,16 +294,21 @@ native_print_attr(gpointer key, gpointer value, gpointer user_data) + static void + native_print_xml(resource_t * rsc, const char *pre_text, long options, void *print_data) + { ++ enum rsc_role_e role = rsc->role; + const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); + const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); + ++ if(role == RSC_ROLE_STARTED && uber_parent(rsc)->variant == pe_master) { ++ role = RSC_ROLE_SLAVE; ++ } ++ + /* resource information. */ + status_print("%sxml, XML_ATTR_TYPE)); +- status_print("role=\"%s\" ", role2text(rsc->role)); ++ status_print("role=\"%s\" ", role2text(role)); + status_print("active=\"%s\" ", rsc->fns->active(rsc, TRUE) ? "true" : "false"); + status_print("orphaned=\"%s\" ", is_set(rsc->flags, pe_rsc_orphan) ? "true" : "false"); + status_print("managed=\"%s\" ", is_set(rsc->flags, pe_rsc_managed) ? "true" : "false"); diff --git a/SOURCES/bz1028627-pcmk-fix_controld_use_corosync2_dlm_variant.patch b/SOURCES/bz1028627-pcmk-fix_controld_use_corosync2_dlm_variant.patch new file mode 100644 index 0000000..f8803c5 --- /dev/null +++ b/SOURCES/bz1028627-pcmk-fix_controld_use_corosync2_dlm_variant.patch @@ -0,0 +1,22 @@ +commit 16ed615a81294fb32e7d5795db86172d167975ae +Author: Andrew Beekhof +Date: Mon Nov 11 09:28:18 2013 +1100 + + Fix: controld: Use the correct variant of dlm_controld for corosync-2 clusters + (cherry picked from commit 0e33fe668aa23520da9552b271aba59016b9cb03) + +diff --git a/extra/resources/controld b/extra/resources/controld +index bacf0e9..bdd31bb 100644 +--- a/extra/resources/controld ++++ b/extra/resources/controld +@@ -209,8 +209,8 @@ controld_validate() { + : ${OCF_RESKEY_CRM_meta_globally_unique:="false"} + + case "$HA_quorum_type" in +- cman|corosync) daemon_ext="";; +- *) daemon_ext=".pcmk";; ++ pcmk) daemon_ext=".pcmk";; ++ *) daemon_ext="";; + esac + + case "$OCF_RESOURCE_INSTANCE" in diff --git a/SOURCES/bz720543-pcmk-cib_allow_values_to_be_added_updated_and_removed_in_a_single_update.patch b/SOURCES/bz720543-pcmk-cib_allow_values_to_be_added_updated_and_removed_in_a_single_update.patch new file mode 100644 index 0000000..5ca2615 --- /dev/null +++ b/SOURCES/bz720543-pcmk-cib_allow_values_to_be_added_updated_and_removed_in_a_single_update.patch @@ -0,0 +1,51 @@ +commit fc48cd10b4daca72217d7be42cd8eb71984d454a +Author: Andrew Beekhof +Date: Fri Aug 30 17:51:06 2013 +1000 + + Feature: cib: Allow values to be added/updated and removed in a single update + + (cherry picked from commit 9819039f15277c05011c6100934167227cfd135d) + + Conflicts: + attrd/commands.c + +diff --git a/include/crm/cib.h b/include/crm/cib.h +index 7a694ac..5ff57eb 100644 +--- a/include/crm/cib.h ++++ b/include/crm/cib.h +@@ -63,6 +63,7 @@ enum cib_call_options { + cib_discard_reply = 0x00000010, + cib_no_children = 0x00000020, + cib_xpath_address = 0x00000040, ++ cib_mixed_update = 0x00000080, + cib_scope_local = 0x00000100, + cib_dryrun = 0x00000200, + cib_sync_call = 0x00001000, +diff --git a/lib/cib/cib_ops.c b/lib/cib/cib_ops.c +index 4e1196b..26ae373 100644 +--- a/lib/cib/cib_ops.c ++++ b/lib/cib/cib_ops.c +@@ -354,6 +354,23 @@ cib_process_modify(const char *op, int options, const char *section, xmlNode * r + } + } + ++ if(options & cib_mixed_update) { ++ int max = 0, lpc; ++ xmlXPathObjectPtr xpathObj = xpath_search(*result_cib, "//@__delete__"); ++ ++ if (xpathObj) { ++ max = numXpathResults(xpathObj); ++ crm_log_xml_info(*result_cib, "Mixed result"); ++ } ++ ++ for (lpc = 0; lpc < max; lpc++) { ++ xmlNode *match = getXpathResult(xpathObj, lpc); ++ crm_debug("Destroying %s", (char *)xmlGetNodePath(match)); ++ free_xml(match); ++ } ++ ++ freeXpathObject(xpathObj); ++ } + return pcmk_ok; + } + diff --git a/SOURCES/bz720543-pcmk-cli_do_not_enabled_blackbox_for_cli_tools.patch b/SOURCES/bz720543-pcmk-cli_do_not_enabled_blackbox_for_cli_tools.patch new file mode 100644 index 0000000..b11e0d8 --- /dev/null +++ b/SOURCES/bz720543-pcmk-cli_do_not_enabled_blackbox_for_cli_tools.patch @@ -0,0 +1,21 @@ +commit 32a30ee51d3d16e4ad33c329c047030f3060afe0 +Author: Andrew Beekhof +Date: Thu Oct 3 21:01:38 2013 +1000 + + Fix: cli: Do not enabled blackbox for cli tools + + (cherry picked from commit ab0f2fede2a8ddfa250a8ea5e57fea0b79348edb) + +diff --git a/lib/common/logging.c b/lib/common/logging.c +index 84884ac..0b85093 100644 +--- a/lib/common/logging.c ++++ b/lib/common/logging.c +@@ -697,7 +697,7 @@ crm_log_init(const char *entity, int level, gboolean daemon, gboolean to_stderr, + crm_add_logfile(logfile); + } + +- if (daemon_option_enabled(crm_system_name, "blackbox")) { ++ if (crm_is_daemon && daemon_option_enabled(crm_system_name, "blackbox")) { + crm_enable_blackbox(0); + } + diff --git a/SOURCES/bz720543-pcmk-command_line_tools_should_stop_after_an_assertion_failure.patch b/SOURCES/bz720543-pcmk-command_line_tools_should_stop_after_an_assertion_failure.patch new file mode 100644 index 0000000..b442646 --- /dev/null +++ b/SOURCES/bz720543-pcmk-command_line_tools_should_stop_after_an_assertion_failure.patch @@ -0,0 +1,96 @@ +commit 5a743a9378faf251d03f19f37facd2ddfc19989b +Author: Andrew Beekhof +Date: Tue Aug 6 13:36:45 2013 +1000 + + Fix: Command-line tools should stop after an assertion failure + + (cherry picked from commit 912db519b293ab18840c36e0b5d91b3ee6e205dd) + +diff --git a/lib/common/logging.c b/lib/common/logging.c +index 0b85093..571cd03 100644 +--- a/lib/common/logging.c ++++ b/lib/common/logging.c +@@ -46,6 +46,7 @@ unsigned int crm_log_priority = LOG_NOTICE; + unsigned int crm_log_level = LOG_INFO; + static gboolean crm_tracing_enabled(void); + unsigned int crm_trace_nonlog = 0; ++bool crm_is_daemon = 0; + + #ifdef HAVE_G_LOG_SET_DEFAULT_HANDLER + GLogFunc glib_log_default; +@@ -626,6 +627,8 @@ crm_log_init(const char *entity, int level, gboolean daemon, gboolean to_stderr, + const char *facility = daemon_option("logfacility"); + const char *f_copy = facility; + ++ crm_is_daemon = daemon; ++ + if (crm_trace_nonlog == 0) { + crm_trace_nonlog = g_quark_from_static_string("Pacemaker non-logging tracepoint"); + } +@@ -711,11 +714,11 @@ crm_log_init(const char *entity, int level, gboolean daemon, gboolean to_stderr, + qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE); + } + +- if (daemon) { ++ if (crm_is_daemon) { + set_daemon_option("logfacility", facility); + } + +- if (daemon && crm_tracing_enabled() ++ if (crm_is_daemon && crm_tracing_enabled() + && qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED + && qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) { + /* Make sure tracing goes somewhere */ +@@ -725,20 +728,20 @@ crm_log_init(const char *entity, int level, gboolean daemon, gboolean to_stderr, + crm_update_callsites(); + + /* Ok, now we can start logging... */ +- if (quiet == FALSE && daemon == FALSE) { ++ if (quiet == FALSE && crm_is_daemon == FALSE) { + crm_log_args(argc, argv); + } + +- if (daemon) { ++ if (crm_is_daemon) { + const char *user = getenv("USER"); + + if (user != NULL && safe_str_neq(user, "root") && safe_str_neq(user, CRM_DAEMON_USER)) { + crm_trace("Not switching to corefile directory for %s", user); +- daemon = FALSE; ++ crm_is_daemon = FALSE; + } + } + +- if (daemon) { ++ if (crm_is_daemon) { + int user = getuid(); + const char *base = CRM_CORE_DIR; + struct passwd *pwent = getpwuid(user); +diff --git a/lib/common/utils.c b/lib/common/utils.c +index 069b5c8..527c9e0 100644 +--- a/lib/common/utils.c ++++ b/lib/common/utils.c +@@ -1085,6 +1085,8 @@ filter_reload_parameters(xmlNode * param_set, const char *restart_string) + } + } + ++extern bool crm_is_daemon; ++ + /* coverity[+kill] */ + void + crm_abort(const char *file, const char *function, int line, +@@ -1097,6 +1099,14 @@ crm_abort(const char *file, const char *function, int line, + /* Implied by the parent's error logging below */ + /* crm_write_blackbox(0); */ + ++ if(crm_is_daemon == FALSE) { ++ /* This is a command line tool - do not fork */ ++ ++ /* crm_add_logfile(NULL); * Record it to a file? */ ++ crm_enable_stderr(TRUE); /* Make sure stderr is enabled so we can tell the caller */ ++ do_fork = FALSE; /* Just crash if needed */ ++ } ++ + if (do_core == FALSE) { + crm_err("%s: Triggered assert at %s:%d : %s", function, file, line, assert_condition); + return; diff --git a/SOURCES/bz720543-pcmk-crm_report_do_not_print_garbage_when_collecting_from_the_local_node.patch b/SOURCES/bz720543-pcmk-crm_report_do_not_print_garbage_when_collecting_from_the_local_node.patch new file mode 100644 index 0000000..ec44c63 --- /dev/null +++ b/SOURCES/bz720543-pcmk-crm_report_do_not_print_garbage_when_collecting_from_the_local_node.patch @@ -0,0 +1,21 @@ +commit 9b488a436dcdba49bd3b5e5365eb9ac44719d308 +Author: Andrew Beekhof +Date: Wed Sep 4 14:46:23 2013 +1000 + + Fix: crm_report: Do not print garbage when collecting from the local node + + (cherry picked from commit 2c78ded0c66dc2f113ed1620efeaef51fdb489e5) + +diff --git a/tools/report.collector b/tools/report.collector +index 1667364..62cbe8b 100644 +--- a/tools/report.collector ++++ b/tools/report.collector +@@ -748,8 +748,6 @@ done + + if [ -e $REPORT_HOME/.env ]; then + debug "Localhost: $REPORT_MASTER $REPORT_TARGET" +- # Need to send something back or tar on the caller will complain +- (cd $REPORT_HOME && tar cf - .env) + + elif [ "$REPORT_MASTER" != "$REPORT_TARGET" ]; then + debug "Streaming report back to $REPORT_MASTER" diff --git a/SOURCES/bz720543-pcmk-crm_report_record_the_output_of_the_collector.patch b/SOURCES/bz720543-pcmk-crm_report_record_the_output_of_the_collector.patch new file mode 100644 index 0000000..91e5000 --- /dev/null +++ b/SOURCES/bz720543-pcmk-crm_report_record_the_output_of_the_collector.patch @@ -0,0 +1,42 @@ +commit c3fb9d983fbbcc7f19908c384cd29656e0620ec3 +Author: Andrew Beekhof +Date: Wed Sep 4 12:54:37 2013 +1000 + + Feature: crm_report: Record the output of the collector + + (cherry picked from commit 494a01897f07327ec475a86957b8fc7fd3ad362c) + +diff --git a/tools/report.common.in b/tools/report.common.in +index c4023a8..9742f1c 100644 +--- a/tools/report.common.in ++++ b/tools/report.common.in +@@ -72,15 +72,29 @@ glibc + # + # keep the user posted + # ++record() { ++ if [ x != x"$REPORT_HOME" -a -d "${REPORT_HOME}/$shorthost" ]; then ++ rec="${REPORT_HOME}/$shorthost/report.out" ++ ++ elif [ x != x"${l_base}" ]; then ++ rec="${l_base}/report.summary" ++ ++ else ++ rec="/dev/null" ++ fi ++ printf "%-10s $*\n" "$shorthost:" 2>&1 >> "${rec}" ++} + + log() { + printf "%-10s $*\n" "$shorthost:" 1>&2 ++ record "$*" + } + + debug() { + if [ $verbose -gt 0 ]; then + log "Debug: $*" + fi ++ record "Debug: $*" + } + + info() { diff --git a/SOURCES/bz720543-pcmk-crm_resource_wait_for_all_replies_when_cleaning_up_resources.patch b/SOURCES/bz720543-pcmk-crm_resource_wait_for_all_replies_when_cleaning_up_resources.patch new file mode 100644 index 0000000..ff7c066 --- /dev/null +++ b/SOURCES/bz720543-pcmk-crm_resource_wait_for_all_replies_when_cleaning_up_resources.patch @@ -0,0 +1,36 @@ +commit 8da149c887c80b1bcf778089268b060e014159ef +Author: Andrew Beekhof +Date: Thu Oct 3 17:01:38 2013 +1000 + + Fix: crm_resource: Wait for all replies when cleaning up resources + + (cherry picked from commit 62e59ab2ad211cef798792632ad7df4f8a5c3418) + +diff --git a/tools/crm_resource.c b/tools/crm_resource.c +index 44d96b0..c03501d 100644 +--- a/tools/crm_resource.c ++++ b/tools/crm_resource.c +@@ -801,11 +801,15 @@ delete_lrm_rsc(cib_t *cib_conn, crm_ipc_t * crmd_channel, const char *host_uname + + printf("Cleaning up %s on %s\n", rsc->id, host_uname); + rc = send_lrm_rsc_op(crmd_channel, CRM_OP_LRM_DELETE, host_uname, rsc->id, TRUE, data_set); ++ + if (rc == pcmk_ok) { + char *attr_name = NULL; + const char *id = rsc->id; + node_t *node = pe_find_node(data_set->nodes, host_uname); + ++ if(node->details->remote_rsc == NULL) { ++ crmd_replies_needed++; ++ } + if (rsc->clone_name) { + id = rsc->clone_name; + } +@@ -2165,6 +2169,7 @@ main(int argc, char **argv) + + crm_debug("Re-checking the state of %s on %s", rsc_id, host_uname); + if(rsc) { ++ crmd_replies_needed = 0; + rc = delete_lrm_rsc(cib_conn, crmd_channel, host_uname, rsc, &data_set); + } else { + rc = -ENODEV; diff --git a/SOURCES/bz720543-pcmk-crmd_cache_rsc_info_retrieved_from_lrmd_and_pacemaker_remoted.patch b/SOURCES/bz720543-pcmk-crmd_cache_rsc_info_retrieved_from_lrmd_and_pacemaker_remoted.patch new file mode 100644 index 0000000..9d12301 --- /dev/null +++ b/SOURCES/bz720543-pcmk-crmd_cache_rsc_info_retrieved_from_lrmd_and_pacemaker_remoted.patch @@ -0,0 +1,112 @@ +commit 701e10aba853afb4cd1ab4a1e4e3dd64ea96e907 +Author: David Vossel +Date: Thu Oct 10 17:22:29 2013 -0500 + + Low: crmd: Cache rsc_info retrieved from lrmd and pacemaker_remoted + + (cherry picked from commit d65b2703d2107665365b0db06cff67386981e346) + +diff --git a/crmd/crmd_lrm.h b/crmd/crmd_lrm.h +index d0ca58c..2239638 100644 +--- a/crmd/crmd_lrm.h ++++ b/crmd/crmd_lrm.h +@@ -56,6 +56,8 @@ typedef struct lrm_state_s { + GHashTable *pending_ops; + GHashTable *deletion_ops; + ++ GHashTable *rsc_info_cache; ++ + int num_lrm_register_fails; + } lrm_state_t; + +diff --git a/crmd/lrm_state.c b/crmd/lrm_state.c +index b1b1b7f..57eb87e 100644 +--- a/crmd/lrm_state.c ++++ b/crmd/lrm_state.c +@@ -60,6 +60,13 @@ history_cache_destroy(gpointer data) + free(entry->id); + free(entry); + } ++static void ++free_rsc_info(gpointer value) ++{ ++ lrmd_rsc_info_t *rsc_info = value; ++ ++ lrmd_free_rsc_info(rsc_info); ++} + + static void + free_deletion_op(gpointer value) +@@ -99,6 +106,9 @@ lrm_state_create(const char *node_name) + + state->node_name = strdup(node_name); + ++ state->rsc_info_cache = g_hash_table_new_full(crm_str_hash, ++ g_str_equal, NULL, free_rsc_info); ++ + state->deletion_ops = g_hash_table_new_full(crm_str_hash, + g_str_equal, g_hash_destroy_str, free_deletion_op); + +@@ -146,6 +156,10 @@ internal_lrm_state_destroy(gpointer data) + remote_ra_cleanup(lrm_state); + lrmd_api_delete(lrm_state->conn); + ++ if (lrm_state->rsc_info_cache) { ++ crm_trace("Destroying rsc info cache with %d members", g_hash_table_size(lrm_state->rsc_info_cache)); ++ g_hash_table_destroy(lrm_state->rsc_info_cache); ++ } + if (lrm_state->resource_history) { + crm_trace("Destroying history op cache with %d members", g_hash_table_size(lrm_state->resource_history)); + g_hash_table_destroy(lrm_state->resource_history); +@@ -181,6 +195,11 @@ lrm_state_reset_tables(lrm_state_t * lrm_state) + g_hash_table_size(lrm_state->pending_ops)); + g_hash_table_remove_all(lrm_state->pending_ops); + } ++ if (lrm_state->rsc_info_cache) { ++ crm_trace("Re-setting rsc info cache with %d members", ++ g_hash_table_size(lrm_state->rsc_info_cache)); ++ g_hash_table_remove_all(lrm_state->rsc_info_cache); ++ } + } + + static void +@@ -590,16 +609,28 @@ lrm_state_cancel(lrm_state_t * lrm_state, const char *rsc_id, const char *action + lrmd_rsc_info_t * + lrm_state_get_rsc_info(lrm_state_t * lrm_state, const char *rsc_id, enum lrmd_call_options options) + { ++ lrmd_rsc_info_t *rsc = NULL; ++ + if (!lrm_state->conn) { + return NULL; + } +- /* optimize this... this function is a synced round trip from client to daemon. +- * It should be possible to cache the resource info in the lrmd client to prevent this. */ + if (is_remote_lrmd_ra(NULL, NULL, rsc_id)) { + return remote_ra_get_rsc_info(lrm_state, rsc_id); + } + +- return ((lrmd_t *) lrm_state->conn)->cmds->get_rsc_info(lrm_state->conn, rsc_id, options); ++ rsc = g_hash_table_lookup(lrm_state->rsc_info_cache, rsc_id); ++ if (rsc == NULL) { ++ /* only contact the lrmd if we don't already have a cached rsc info */ ++ rsc = ((lrmd_t *) lrm_state->conn)->cmds->get_rsc_info(lrm_state->conn, rsc_id, options); ++ if (rsc == NULL) { ++ return NULL; ++ } ++ /* cache the result */ ++ g_hash_table_insert(lrm_state->rsc_info_cache, rsc->id, rsc); ++ } ++ ++ return lrmd_copy_rsc_info(rsc); ++ + } + + int +@@ -667,5 +698,7 @@ lrm_state_unregister_rsc(lrm_state_t * lrm_state, + return pcmk_ok; + } + ++ g_hash_table_remove(lrm_state->rsc_info_cache, rsc_id); ++ + return ((lrmd_t *) lrm_state->conn)->cmds->unregister_rsc(lrm_state->conn, rsc_id, options); + } diff --git a/SOURCES/bz720543-pcmk-crmd_correctly_update_expected_state_when_the_previous_dc_shuts_down.patch b/SOURCES/bz720543-pcmk-crmd_correctly_update_expected_state_when_the_previous_dc_shuts_down.patch new file mode 100644 index 0000000..9854a8f --- /dev/null +++ b/SOURCES/bz720543-pcmk-crmd_correctly_update_expected_state_when_the_previous_dc_shuts_down.patch @@ -0,0 +1,88 @@ +commit 4443e76aaccb60fb49f7c32eb2c0a34e0965a291 +Author: Andrew Beekhof +Date: Wed Oct 2 09:00:39 2013 +1000 + + Fix: crmd: Correctly update expected state when the previous DC shuts down + + (cherry picked from commit 25ebce69ecc07799b50cf6e0ca4704345e7cf336) + +diff --git a/crmd/join_dc.c b/crmd/join_dc.c +index b45fff2..5e6c827 100644 +--- a/crmd/join_dc.c ++++ b/crmd/join_dc.c +@@ -103,17 +103,19 @@ initialize_join(gboolean before) + static void + join_make_offer(gpointer key, gpointer value, gpointer user_data) + { +- const char *join_to = NULL; +- const crm_node_t *member = value; ++ xmlNode *offer = NULL; ++ crm_node_t *member = (crm_node_t *)value; + + CRM_ASSERT(member != NULL); + if (crm_is_peer_active(member) == FALSE) { +- crm_trace("Not making an offer to %s: not active", member->uname); ++ crm_info("Not making an offer to %s: not active (%s)", member->uname, member->state); ++ if(member->expected == NULL && safe_str_eq(member->state, CRM_NODE_LOST)) { ++ crm_update_peer_expected(__FUNCTION__, member, CRMD_JOINSTATE_DOWN); ++ } + return; + } + +- join_to = member->uname; +- if (join_to == NULL) { ++ if (member->uname == NULL) { + crm_err("No recipient for welcome message"); + return; + } +@@ -130,26 +132,18 @@ join_make_offer(gpointer key, gpointer value, gpointer user_data) + + crm_update_peer_join(__FUNCTION__, (crm_node_t*)member, crm_join_none); + +- if (crm_is_peer_active(member)) { +- crm_node_t *peer = crm_get_peer(0, join_to); +- xmlNode *offer = create_request(CRM_OP_JOIN_OFFER, NULL, join_to, +- CRM_SYSTEM_CRMD, CRM_SYSTEM_DC, NULL); +- +- crm_xml_add_int(offer, F_CRM_JOIN_ID, current_join_id); +- /* send the welcome */ +- crm_info("join-%d: Sending offer to %s", current_join_id, join_to); ++ offer = create_request(CRM_OP_JOIN_OFFER, NULL, member->uname, ++ CRM_SYSTEM_CRMD, CRM_SYSTEM_DC, NULL); + +- send_cluster_message(peer, crm_msg_crmd, offer, TRUE); +- free_xml(offer); ++ crm_xml_add_int(offer, F_CRM_JOIN_ID, current_join_id); ++ /* send the welcome */ ++ crm_info("join-%d: Sending offer to %s", current_join_id, member->uname); + +- crm_update_peer_join(__FUNCTION__, peer, crm_join_welcomed); +- /* crm_update_peer_expected(__FUNCTION__, member, CRMD_JOINSTATE_PENDING); */ +- +- } else { +- crm_info("Peer process on %s is not active (yet?): %.8lx %d", +- join_to, (long)member->processes, g_hash_table_size(crm_peer_cache)); +- } ++ send_cluster_message(member, crm_msg_crmd, offer, TRUE); ++ free_xml(offer); + ++ crm_update_peer_join(__FUNCTION__, member, crm_join_welcomed); ++ /* crm_update_peer_expected(__FUNCTION__, member, CRMD_JOINSTATE_PENDING); */ + } + + /* A_DC_JOIN_OFFER_ALL */ +diff --git a/lib/cluster/membership.c b/lib/cluster/membership.c +index e3082b4..e7d5b69 100644 +--- a/lib/cluster/membership.c ++++ b/lib/cluster/membership.c +@@ -532,8 +532,8 @@ crm_update_peer_expected(const char *source, crm_node_t * node, const char *expe + } + + if (changed) { +- crm_info("%s: Node %s[%u] - expected state is now %s", source, node->uname, node->id, +- expected); ++ crm_info("%s: Node %s[%u] - expected state is now %s (was %s)", source, node->uname, node->id, ++ expected, last); + free(last); + } else { + crm_trace("%s: Node %s[%u] - expected state is unchanged (%s)", source, node->uname, diff --git a/SOURCES/bz720543-pcmk-crmd_don_t_add_node_state_to_cib_if_we_have_not_seen_or_fenced_this_node_yet.patch b/SOURCES/bz720543-pcmk-crmd_don_t_add_node_state_to_cib_if_we_have_not_seen_or_fenced_this_node_yet.patch new file mode 100644 index 0000000..a4d8612 --- /dev/null +++ b/SOURCES/bz720543-pcmk-crmd_don_t_add_node_state_to_cib_if_we_have_not_seen_or_fenced_this_node_yet.patch @@ -0,0 +1,30 @@ +commit e03e4f32fca5857618603e3e1c9500dbf3d348ef +Author: Lars Ellenberg +Date: Fri Aug 2 14:33:57 2013 +1000 + + Fix: crmd: Don't add node_state to cib, if we have not seen or fenced this node yet + + Also fixes the incredibly dangerous option: startup-fencing=false + + (cherry picked from commit ac7aa1c94f317fc1d4024fbc09b012bc9f1b229e) + +diff --git a/crmd/membership.c b/crmd/membership.c +index e2bcd45..d102db0 100644 +--- a/crmd/membership.c ++++ b/crmd/membership.c +@@ -131,8 +131,14 @@ 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); ++ xmlNode *node_state; + ++ if (!node->state) { ++ crm_info("Node update for %s cancelled: no state, not seen yet", node->uname); ++ return NULL; ++ } ++ ++ node_state = create_xml_node(parent, XML_CIB_TAG_STATE); + set_uuid(node_state, XML_ATTR_UUID, node); + + if (crm_element_value(node_state, XML_ATTR_UUID) == NULL) { diff --git a/SOURCES/bz720543-pcmk-crmd_pad_internal_lrmd_rsc_info_and_metadata_retrieval_timeout.patch b/SOURCES/bz720543-pcmk-crmd_pad_internal_lrmd_rsc_info_and_metadata_retrieval_timeout.patch new file mode 100644 index 0000000..732e869 --- /dev/null +++ b/SOURCES/bz720543-pcmk-crmd_pad_internal_lrmd_rsc_info_and_metadata_retrieval_timeout.patch @@ -0,0 +1,30 @@ +commit 21172ada434f549515d4480e821872b8cbd12566 +Author: David Vossel +Date: Thu Oct 10 17:30:40 2013 -0500 + + Low: crmd: Pad internal lrmd rsc_info and metadata retrieval timeout + + (cherry picked from commit 5c21a6b6e7789da50111f3d955593c7fbda1ddc2) + +diff --git a/lib/lrmd/lrmd_client.c b/lib/lrmd/lrmd_client.c +index e577293..d037022 100644 +--- a/lib/lrmd/lrmd_client.c ++++ b/lib/lrmd/lrmd_client.c +@@ -1437,7 +1437,7 @@ lrmd_api_get_rsc_info(lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options + + crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__); + crm_xml_add(data, F_LRMD_RSC_ID, rsc_id); +- lrmd_send_command(lrmd, LRMD_OP_RSC_INFO, data, &output, 0, options, TRUE); ++ lrmd_send_command(lrmd, LRMD_OP_RSC_INFO, data, &output, 30000, options, TRUE); + free_xml(data); + + if (!output) { +@@ -1743,7 +1743,7 @@ generic_get_metadata(const char *standard, const char *provider, const char *typ + type, + "meta-data", + 0, +- 5000, ++ 30000, + NULL); + + if (!(services_action_sync(action))) { diff --git a/SOURCES/bz720543-pcmk-fencing_allow_fencing_for_node_after_topology_entries_are_deleted.patch b/SOURCES/bz720543-pcmk-fencing_allow_fencing_for_node_after_topology_entries_are_deleted.patch new file mode 100644 index 0000000..b01bc8e --- /dev/null +++ b/SOURCES/bz720543-pcmk-fencing_allow_fencing_for_node_after_topology_entries_are_deleted.patch @@ -0,0 +1,45 @@ +commit ca9ea8de96463d137f64977a01517bf794d1f4e4 +Author: David Vossel +Date: Tue Oct 1 18:26:56 2013 -0500 + + Fix: fencing: Allow fencing for node after topology entries are deleted + + (cherry picked from commit 57de742c237ac5c01b4a7ead70003cbaffed9a3e) + +diff --git a/fencing/remote.c b/fencing/remote.c +index 525f1d7..af4fb9e 100644 +--- a/fencing/remote.c ++++ b/fencing/remote.c +@@ -374,6 +374,23 @@ remote_op_query_timeout(gpointer data) + return FALSE; + } + ++static gboolean ++topology_is_empty(stonith_topology_t *tp) ++{ ++ int i; ++ ++ if (tp == NULL) { ++ return TRUE; ++ } ++ ++ for (i = 0; i < ST_LEVEL_MAX; i++) { ++ if (tp->levels[i] != NULL) { ++ return FALSE; ++ } ++ } ++ return TRUE; ++} ++ + static int + stonith_topology_next(remote_fencing_op_t * op) + { +@@ -383,7 +400,7 @@ stonith_topology_next(remote_fencing_op_t * op) + /* Queries don't have a target set */ + tp = g_hash_table_lookup(topology, op->target); + } +- if (tp == NULL) { ++ if (topology_is_empty(tp)) { + return pcmk_ok; + } + diff --git a/SOURCES/bz720543-pcmk-fencing_deep_copy_current_topology_level_list_on_remote_op.patch b/SOURCES/bz720543-pcmk-fencing_deep_copy_current_topology_level_list_on_remote_op.patch new file mode 100644 index 0000000..99f1ed7 --- /dev/null +++ b/SOURCES/bz720543-pcmk-fencing_deep_copy_current_topology_level_list_on_remote_op.patch @@ -0,0 +1,68 @@ +commit 5cc40550ed6f385eb25042b1ab14339a760de1e8 +Author: David Vossel +Date: Thu Oct 17 20:34:48 2013 -0500 + + Fix: fencing: Deep copy current topology level list on remote op + + (cherry picked from commit ef29a502e0e0506fd52fc60e51e06ffd6c375f4a) + +diff --git a/fencing/internal.h b/fencing/internal.h +index 11a8c58..da510c3 100644 +--- a/fencing/internal.h ++++ b/fencing/internal.h +@@ -105,6 +105,8 @@ typedef struct remote_fencing_op_s { + /*! The current topology level being executed */ + guint level; + /*! The device list of all the devices at the current executing topology level. */ ++ GListPtr devices_list; ++ /*! Current entry in the topology device list */ + GListPtr devices; + + /*! List of duplicate operations attached to this operation. Once this operation +diff --git a/fencing/remote.c b/fencing/remote.c +index af4fb9e..8c8df6d 100644 +--- a/fencing/remote.c ++++ b/fencing/remote.c +@@ -124,6 +124,10 @@ free_remote_op(gpointer data) + free_xml(op->request); + op->request = NULL; + } ++ if (op->devices_list) { ++ g_list_free_full(op->devices_list, free); ++ op->devices_list = NULL; ++ } + free(op); + } + +@@ -391,6 +395,22 @@ topology_is_empty(stonith_topology_t *tp) + return TRUE; + } + ++/* deep copy the device list */ ++static void ++set_op_device_list(remote_fencing_op_t * op, GListPtr devices) ++{ ++ GListPtr lpc = NULL; ++ ++ if (op->devices_list) { ++ g_list_free_full(op->devices_list, free); ++ op->devices_list = NULL; ++ } ++ for (lpc = devices; lpc != NULL; lpc = lpc->next) { ++ op->devices_list = g_list_append(op->devices_list, strdup(lpc->data)); ++ } ++ op->devices = op->devices_list; ++} ++ + static int + stonith_topology_next(remote_fencing_op_t * op) + { +@@ -415,7 +435,7 @@ stonith_topology_next(remote_fencing_op_t * op) + crm_trace("Attempting fencing level %d for %s (%d devices) - %s@%s.%.8s", + op->level, op->target, g_list_length(tp->levels[op->level]), + op->client_name, op->originator, op->id); +- op->devices = tp->levels[op->level]; ++ set_op_device_list(op, tp->levels[op->level]); + return pcmk_ok; + } + diff --git a/SOURCES/bz720543-pcmk-fencing_do_not_broadcast_suicide_if_the_on_action_is_being_executed.patch b/SOURCES/bz720543-pcmk-fencing_do_not_broadcast_suicide_if_the_on_action_is_being_executed.patch new file mode 100644 index 0000000..f8f6965 --- /dev/null +++ b/SOURCES/bz720543-pcmk-fencing_do_not_broadcast_suicide_if_the_on_action_is_being_executed.patch @@ -0,0 +1,21 @@ +commit c041f6362e9e33e78e2645ae7c10f5aa2ad41874 +Author: David Vossel +Date: Tue Oct 1 17:12:17 2013 -0500 + + Low: fencing: Do not broadcast suicide if the on action is being executed + + (cherry picked from commit fd5d4e2f3b61a614f92781bd4280efe282bc142a) + +diff --git a/fencing/commands.c b/fencing/commands.c +index 7d04952..909dc24 100644 +--- a/fencing/commands.c ++++ b/fencing/commands.c +@@ -1352,7 +1352,7 @@ stonith_send_async_reply(async_command_t * cmd, const char *output, int rc, GPid + crm_str_eq(cmd->action, "list", TRUE) || crm_str_eq(cmd->action, "status", TRUE)) { + crm_trace("Never broadcast %s replies", cmd->action); + +- } else if (!stand_alone && safe_str_eq(cmd->origin, cmd->victim)) { ++ } else if (!stand_alone && safe_str_eq(cmd->origin, cmd->victim) && safe_str_neq(cmd->action, "on")) { + crm_trace("Broadcast %s reply for %s", cmd->action, cmd->victim); + crm_xml_add(reply, F_SUBTYPE, "broadcast"); + bcast = TRUE; diff --git a/SOURCES/bz720543-pcmk-ipc_raise_the_default_buffer_size_to_128k.patch b/SOURCES/bz720543-pcmk-ipc_raise_the_default_buffer_size_to_128k.patch new file mode 100644 index 0000000..d0ea458 --- /dev/null +++ b/SOURCES/bz720543-pcmk-ipc_raise_the_default_buffer_size_to_128k.patch @@ -0,0 +1,75 @@ +commit d42392c04d9f81a51d708723d978558690f5724b +Author: Andrew Beekhof +Date: Tue Sep 17 12:36:45 2013 +1000 + + Feature: ipc: Raise the default buffer size to 128k + + (cherry picked from commit 8196f23a829ed02edb887209bccc88dc851b198b) + +diff --git a/lib/common/ipc.c b/lib/common/ipc.c +index 2cd42bf..451bda5 100644 +--- a/lib/common/ipc.c ++++ b/lib/common/ipc.c +@@ -521,13 +521,6 @@ crm_ipc_prepare(uint32_t request, xmlNode * message, struct iovec ** result) + } else { + unsigned int new_size = 0; + +- if (total > biggest) { +- biggest = 2 * QB_MAX(total, biggest); +- crm_notice("Message exceeds the configured ipc limit (%d bytes), " +- "consider configuring PCMK_ipc_buffer to %d or higher " +- "to avoid compression overheads", ipc_buffer_max, biggest); +- } +- + if (crm_compress_string + (buffer, header->size_uncompressed, ipc_buffer_max, &compressed, &new_size)) { + +@@ -539,10 +532,15 @@ crm_ipc_prepare(uint32_t request, xmlNode * message, struct iovec ** result) + + free(buffer); + ++ if (header->size_compressed > biggest) { ++ biggest = 2 * QB_MAX(header->size_compressed, biggest); ++ } ++ + } else { + ssize_t rc = -EMSGSIZE; + + crm_log_xml_trace(message, "EMSGSIZE"); ++ biggest = 2 * QB_MAX(header->size_uncompressed, biggest); + + crm_err + ("Could not compress the message into less than the configured ipc limit (%d bytes)." +@@ -665,7 +663,7 @@ crm_ipcs_send_ack(crm_client_t * c, uint32_t request, const char *tag, const cha + /* Client... */ + + #define MIN_MSG_SIZE 12336 /* sizeof(struct qb_ipc_connection_response) */ +-#define MAX_MSG_SIZE 50*1024 /* 50k default */ ++#define MAX_MSG_SIZE 128*1024 /* 128k default */ + + struct crm_ipc_s { + struct pollfd pfd; +@@ -1004,6 +1002,7 @@ crm_ipc_send(crm_ipc_t * client, xmlNode * message, enum crm_ipc_flags flags, in + long rc = 0; + struct iovec *iov; + static uint32_t id = 0; ++ static int factor = 8; + struct crm_ipc_response_header *header; + + crm_ipc_init(); +@@ -1041,6 +1040,15 @@ crm_ipc_send(crm_ipc_t * client, xmlNode * message, enum crm_ipc_flags flags, in + header = iov[0].iov_base; + header->flags |= flags; + ++ if(header->flags | crm_ipc_compressed) { ++ if(factor < 10 && (ipc_buffer_max / 10) < (rc / factor)) { ++ crm_notice("Compressed message exceeds %d0%% of the configured ipc limit (%d bytes), " ++ "consider setting PCMK_ipc_buffer to %d or higher", ++ factor, ipc_buffer_max, 2*ipc_buffer_max); ++ factor++; ++ } ++ } ++ + if (ms_timeout == 0) { + ms_timeout = 5000; + } diff --git a/SOURCES/bz720543-pcmk-ipc_use_the_higher_of_the_configured_buffer_size_or_the_default.patch b/SOURCES/bz720543-pcmk-ipc_use_the_higher_of_the_configured_buffer_size_or_the_default.patch new file mode 100644 index 0000000..e862a7f --- /dev/null +++ b/SOURCES/bz720543-pcmk-ipc_use_the_higher_of_the_configured_buffer_size_or_the_default.patch @@ -0,0 +1,44 @@ +commit 20845c58bf1003225241dcefb47d7d71013aa432 +Author: Andrew Beekhof +Date: Fri Oct 18 12:20:29 2013 +1100 + + Fix: ipc: Use the higher of the configured buffer size or the default + + (cherry picked from commit 87a34aa975ae2a114e964e3dd9c3c84a937c1979) + +diff --git a/lib/common/ipc.c b/lib/common/ipc.c +index 451bda5..435b392 100644 +--- a/lib/common/ipc.c ++++ b/lib/common/ipc.c +@@ -681,22 +681,19 @@ struct crm_ipc_s { + static int + pick_ipc_buffer(int max) + { +- const char *env = getenv("PCMK_ipc_buffer"); ++ static int global_max = 0; + +- if (env) { +- max = crm_parse_int(env, "0"); +- } +- +- if (max <= 0) { +- max = MAX_MSG_SIZE; +- } ++ if(global_max == 0) { ++ const char *env = getenv("PCMK_ipc_buffer"); + +- if (max < MIN_MSG_SIZE) { +- max = MIN_MSG_SIZE; ++ if (env) { ++ global_max = crm_parse_int(env, "0"); ++ } else { ++ global_max = MAX_MSG_SIZE; ++ } + } + +- crm_trace("Using max message size of %d", max); +- return max; ++ return QB_MAX(max, global_max); + } + + crm_ipc_t * diff --git a/SOURCES/bz720543-pcmk-iso8601_prevent_dates_from_jumping_backwards_a_day_in_some_timezones.patch b/SOURCES/bz720543-pcmk-iso8601_prevent_dates_from_jumping_backwards_a_day_in_some_timezones.patch new file mode 100644 index 0000000..12e6a68 --- /dev/null +++ b/SOURCES/bz720543-pcmk-iso8601_prevent_dates_from_jumping_backwards_a_day_in_some_timezones.patch @@ -0,0 +1,20 @@ +commit aa0e9c4d42f7ae4a856c5716444e9333b099013b +Author: Andrew Beekhof +Date: Wed Oct 2 09:02:19 2013 +1000 + + Fix: iso8601: Prevent dates from jumping backwards a day in some timezones + + (cherry picked from commit ed70b9864247030bc21163411b60a7e962068d88) + +diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c +index d68e7e6..d88c519 100644 +--- a/lib/common/iso8601.c ++++ b/lib/common/iso8601.c +@@ -1115,7 +1115,6 @@ crm_time_add_seconds(crm_time_t * a_time, int extra) + days++; + } + +- days = 0; + while (a_time->seconds < 0) { + crm_trace("s=%d, d=%d", a_time->seconds, days); + a_time->seconds += seconds; diff --git a/SOURCES/bz720543-pcmk-lrmd_correctly_cancel_monitor_actions_for_lsb_systemd_service_resources_on_cleaning_up.patch b/SOURCES/bz720543-pcmk-lrmd_correctly_cancel_monitor_actions_for_lsb_systemd_service_resources_on_cleaning_up.patch new file mode 100644 index 0000000..8d4bafa --- /dev/null +++ b/SOURCES/bz720543-pcmk-lrmd_correctly_cancel_monitor_actions_for_lsb_systemd_service_resources_on_cleaning_up.patch @@ -0,0 +1,21 @@ +commit 59a56d6fef5885f6d22f1e20bd189d91d5844827 +Author: Gao,Yan +Date: Mon Sep 30 21:10:44 2013 +0800 + + Fix: lrmd: Correctly cancel monitor actions for lsb/systemd/service resources on cleaning up + + (cherry picked from commit 1c14b9d69470ff56fd814091867394cd0a1cf61d) + +diff --git a/lrmd/lrmd.c b/lrmd/lrmd.c +index 8592b6c..65421d0 100644 +--- a/lrmd/lrmd.c ++++ b/lrmd/lrmd.c +@@ -978,7 +978,7 @@ free_rsc(gpointer data) + * let service library cancel it and tell us via the callback + * when it is cancelled. The rsc can be safely destroyed + * even if we are waiting for the cancel result */ +- services_action_cancel(rsc->rsc_id, cmd->action, cmd->interval); ++ services_action_cancel(rsc->rsc_id, normalize_action_name(rsc, cmd->action), cmd->interval); + } + } + /* frees list, but not list elements. */ diff --git a/SOURCES/bz720543-pcmk-pcmk_remote_ipv6_support.patch b/SOURCES/bz720543-pcmk-pcmk_remote_ipv6_support.patch new file mode 100644 index 0000000..40248e3 --- /dev/null +++ b/SOURCES/bz720543-pcmk-pcmk_remote_ipv6_support.patch @@ -0,0 +1,173 @@ +commit edabd027144c2a9fcd44a997f47981b836b53b77 +Author: David Vossel +Date: Wed Nov 6 13:27:11 2013 -0500 + + High: remote: Add support for ipv6 into pacemaker_remote daemon + (cherry picked from commit 1595263ff56ac14cc697d9866b532c14267d708f) + +diff --git a/lrmd/tls_backend.c b/lrmd/tls_backend.c +index 780d17b..46e7f27 100644 +--- a/lrmd/tls_backend.c ++++ b/lrmd/tls_backend.c +@@ -30,6 +30,7 @@ + + #include + ++#include + #include + #include + #include +@@ -38,7 +39,7 @@ + # define LRMD_REMOTE_AUTH_TIMEOUT 10000 + gnutls_psk_server_credentials_t psk_cred_s; + gnutls_dh_params_t dh_params; +-static int ssock = 0; ++static int ssock = -1; + extern int lrmd_call_id; + + static void +@@ -253,12 +254,72 @@ lrmd_tls_server_key_cb(gnutls_session_t session, const char *username, gnutls_da + return lrmd_tls_set_key(key); + } + ++static int ++bind_and_listen(struct addrinfo *addr) ++{ ++ int optval; ++ int fd; ++ int rc; ++ char buffer[256] = { 0, }; ++ ++ if (addr->ai_family == AF_INET6) { ++ struct sockaddr_in6 *addr_in = (struct sockaddr_in6 *)addr->ai_addr; ++ inet_ntop(addr->ai_family, &addr_in->sin6_addr, buffer, DIMOF(buffer)); ++ ++ } else { ++ struct sockaddr_in *addr_in = (struct sockaddr_in *)addr->ai_addr; ++ inet_ntop(addr->ai_family, &addr_in->sin_addr, buffer, DIMOF(buffer)); ++ } ++ ++ crm_trace("Attempting to bind on address %s", buffer); ++ ++ fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); ++ if (fd < 0) { ++ return -1; ++ } ++ ++ /* reuse address */ ++ optval = 1; ++ rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); ++ if (rc < 0) { ++ crm_perror(LOG_INFO, "Couldn't allow the reuse of local addresses by our remote listener, bind address %s", buffer); ++ close(fd); ++ return -1; ++ } ++ ++ if (addr->ai_family == AF_INET6) { ++ optval = 0; ++ rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)); ++ if (rc < 0) { ++ crm_perror(LOG_INFO, "Couldn't disable IPV6 only on address %s", buffer); ++ close(fd); ++ return -1; ++ } ++ } ++ ++ if (bind(fd, addr->ai_addr, addr->ai_addrlen) != 0) { ++ close(fd); ++ return -1; ++ } ++ ++ if (listen(fd, 10) == -1) { ++ crm_err("Can not start listen on address %s", buffer); ++ close(fd); ++ return -1; ++ } ++ ++ crm_notice("Listening on address %s", buffer); ++ ++ return fd; ++} ++ + int + lrmd_init_remote_tls_server(int port) + { + int rc; +- struct sockaddr_in saddr; +- int optval; ++ int filter; ++ struct addrinfo hints, *res = NULL, *iter; ++ char port_str[16]; + + static struct mainloop_fd_callbacks remote_listen_fd_callbacks = { + .dispatch = lrmd_remote_listen, +@@ -275,34 +336,39 @@ lrmd_init_remote_tls_server(int port) + gnutls_psk_set_server_credentials_function(psk_cred_s, lrmd_tls_server_key_cb); + gnutls_psk_set_server_dh_params(psk_cred_s, dh_params); + +- /* create server socket */ +- ssock = socket(AF_INET, SOCK_STREAM, 0); +- if (ssock == -1) { +- crm_err("Can not create server socket."); +- return -1; +- } ++ memset(&hints, 0, sizeof(struct addrinfo)); ++ hints.ai_flags = AI_PASSIVE; /* Only return socket addresses with wildcard INADDR_ANY or IN6ADDR_ANY_INIT */ ++ hints.ai_family = AF_UNSPEC; /* Return IPv6 or IPv4 */ ++ hints.ai_socktype = SOCK_STREAM; ++ hints.ai_protocol = IPPROTO_TCP; + +- /* reuse address */ +- optval = 1; +- rc = setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); +- if (rc < 0) { +- crm_perror(LOG_INFO, "Couldn't allow the reuse of local addresses by our remote listener"); ++ snprintf(port_str, sizeof(port_str), "%d", port); ++ rc = getaddrinfo(NULL, port_str, &hints, &res); ++ if (rc) { ++ crm_err("getaddrinfo: %s", gai_strerror(rc)); ++ return -1; + } + +- rc = -1; ++ iter = res; ++ filter = AF_INET6; ++ /* Try IPv6 addresses first, then IPv4 */ ++ while (iter) { ++ if (iter->ai_family == filter) { ++ ssock = bind_and_listen(iter); ++ } ++ if (ssock != -1) { ++ break; ++ } + +- /* bind server socket */ +- memset(&saddr, '\0', sizeof(saddr)); +- saddr.sin_family = AF_INET; +- saddr.sin_addr.s_addr = INADDR_ANY; +- saddr.sin_port = htons(port); +- if (bind(ssock, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { +- crm_err("Can not bind server socket."); +- goto init_remote_cleanup; ++ iter = iter->ai_next; ++ if (iter == NULL && filter == AF_INET6) { ++ iter = res; ++ filter = AF_INET; ++ } + } + +- if (listen(ssock, 10) == -1) { +- crm_err("Can not start listen."); ++ if (ssock < 0) { ++ crm_err("unable to bind to address"); + goto init_remote_cleanup; + } + +@@ -314,6 +380,7 @@ lrmd_init_remote_tls_server(int port) + close(ssock); + ssock = 0; + } ++ freeaddrinfo(res); + return rc; + + } diff --git a/SOURCES/bz720543-pcmk-pe_don_t_prevent_clones_from_running_due_to_dependant_resources.patch b/SOURCES/bz720543-pcmk-pe_don_t_prevent_clones_from_running_due_to_dependant_resources.patch new file mode 100644 index 0000000..7976c71 --- /dev/null +++ b/SOURCES/bz720543-pcmk-pe_don_t_prevent_clones_from_running_due_to_dependant_resources.patch @@ -0,0 +1,89 @@ +commit 7d47ad8be7a9c31a1eba2a3714a645ae3985fc37 +Author: Andrew Beekhof +Date: Fri Aug 9 15:00:40 2013 +1000 + + Bug cl#5171 - PE: Don't prevent clones from running due to dependant resources + + (cherry picked from commit 1c057f8808c71763134ae829851d2a2b3b604d07) + +diff --git a/include/crm/pengine/internal.h b/include/crm/pengine/internal.h +index a6b9369..7240106 100644 +--- a/include/crm/pengine/internal.h ++++ b/include/crm/pengine/internal.h +@@ -129,6 +129,7 @@ pe_hash_table_lookup(GHashTable * hash, gconstpointer key) + extern action_t *get_pseudo_op(const char *name, pe_working_set_t * data_set); + extern gboolean order_actions(action_t * lh_action, action_t * rh_action, enum pe_ordering order); + ++GHashTable *node_hash_dup(GHashTable * hash); + extern GListPtr node_list_and(GListPtr list1, GListPtr list2, gboolean filter); + + extern GListPtr node_list_xor(GListPtr list1, GListPtr list2, gboolean filter); +diff --git a/pengine/clone.c b/pengine/clone.c +index b15f76f..9113e9d 100644 +--- a/pengine/clone.c ++++ b/pengine/clone.c +@@ -385,8 +385,9 @@ color_instance(resource_t * rsc, node_t * prefer, gboolean all_coloc, pe_working + { + node_t *chosen = NULL; + node_t *local_node = NULL; ++ GHashTable *backup = NULL; + +- pe_rsc_trace(rsc, "Processing %s", rsc->id); ++ pe_rsc_trace(rsc, "Processing %s %d", rsc->id, all_coloc); + + if (is_not_set(rsc->flags, pe_rsc_provisional)) { + return rsc->fns->location(rsc, NULL, FALSE); +@@ -421,15 +422,19 @@ color_instance(resource_t * rsc, node_t * prefer, gboolean all_coloc, pe_working + } + } + ++ backup = node_hash_dup(rsc->allowed_nodes); + chosen = rsc->cmds->allocate(rsc, prefer, data_set); + if (chosen) { + local_node = pe_hash_table_lookup(rsc->parent->allowed_nodes, chosen->details->id); + + if (prefer && chosen && chosen->details != prefer->details) { +- crm_err("Pre-allocation failed: got %s instead of %s", +- chosen->details->uname, prefer->details->uname); ++ crm_notice("Pre-allocation failed: got %s instead of %s", ++ chosen->details->uname, prefer->details->uname); ++ g_hash_table_destroy(rsc->allowed_nodes); ++ rsc->allowed_nodes = backup; + native_deallocate(rsc); + chosen = NULL; ++ backup = NULL; + + } else if (local_node) { + local_node->count++; +@@ -442,6 +447,9 @@ color_instance(resource_t * rsc, node_t * prefer, gboolean all_coloc, pe_working + } + } + ++ if(backup) { ++ g_hash_table_destroy(backup); ++ } + return chosen; + } + +@@ -587,7 +595,7 @@ clone_color(resource_t * rsc, node_t * prefer, pe_working_set_t * data_set) + } + } + +- pe_rsc_trace(rsc, "Done pre-allocating"); ++ pe_rsc_trace(rsc, "Done pre-allocating (%d of %d)", allocated, clone_data->clone_max); + g_list_free(nodes); + + for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) { +diff --git a/pengine/native.c b/pengine/native.c +index 21ad629..4016a3c 100644 +--- a/pengine/native.c ++++ b/pengine/native.c +@@ -313,7 +313,7 @@ node_hash_update(GHashTable * list1, GHashTable * list2, const char *attr, float + } + } + +-static GHashTable * ++GHashTable * + node_hash_dup(GHashTable * hash) + { + /* Hack! */ diff --git a/SOURCES/bz720543-pcmk-pe_probe_containers_not_expected_to_be_up.patch b/SOURCES/bz720543-pcmk-pe_probe_containers_not_expected_to_be_up.patch new file mode 100644 index 0000000..368aec0 --- /dev/null +++ b/SOURCES/bz720543-pcmk-pe_probe_containers_not_expected_to_be_up.patch @@ -0,0 +1,121 @@ +commit 7d17d8ab2dd91bdcaf2dea199f2ef66b514daea0 +Author: Andrew Beekhof +Date: Wed Nov 6 14:15:24 2013 +1100 + + PE: Probe containers not expected to be up + + RHEL-Only work-around, fixing properly upstream + +diff --git a/include/crm/pengine/internal.h b/include/crm/pengine/internal.h +index 7240106..dd52e7f 100644 +--- a/include/crm/pengine/internal.h ++++ b/include/crm/pengine/internal.h +@@ -262,4 +262,5 @@ op_digest_cache_t *rsc_action_digest_cmp(resource_t * rsc, xmlNode * xml_op, nod + + gboolean is_remote_node(xmlNode *xml); + ++resource_t * rsc_contains_remote_node(pe_working_set_t * data_set, resource_t *rsc); + #endif +diff --git a/include/crm/pengine/status.h b/include/crm/pengine/status.h +index 8eb4a1d..eb52464 100644 +--- a/include/crm/pengine/status.h ++++ b/include/crm/pengine/status.h +@@ -183,6 +183,7 @@ struct node_s { + # define pe_rsc_migrating 0x00400000ULL + + # define pe_rsc_failure_ignored 0x01000000ULL ++# define pe_rsc_unexpectedly_running 0x02000000ULL + + # define pe_rsc_needs_quorum 0x10000000ULL + # define pe_rsc_needs_fencing 0x20000000ULL +diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c +index 78ceb85..56ed291 100644 +--- a/lib/pengine/unpack.c ++++ b/lib/pengine/unpack.c +@@ -2014,6 +2014,9 @@ unpack_lrm_resources(node_t * node, xmlNode * lrm_rsc_list, pe_working_set_t * d + { + xmlNode *rsc_entry = NULL; + gboolean found_orphaned_container_filler = FALSE; ++ GListPtr unexpected_containers = NULL; ++ GListPtr gIter = NULL; ++ resource_t *remote = NULL; + + CRM_CHECK(node != NULL, return FALSE); + +@@ -2025,9 +2028,29 @@ unpack_lrm_resources(node_t * node, xmlNode * lrm_rsc_list, pe_working_set_t * d + if (crm_str_eq((const char *)rsc_entry->name, XML_LRM_TAG_RESOURCE, TRUE)) { + resource_t *rsc; + rsc = unpack_lrm_rsc_state(node, rsc_entry, data_set); +- if (rsc && is_set(rsc->flags, pe_rsc_orphan_container_filler)) { ++ if (!rsc) { ++ continue; ++ } ++ if (is_set(rsc->flags, pe_rsc_orphan_container_filler)) { + found_orphaned_container_filler = TRUE; + } ++ if (is_set(rsc->flags, pe_rsc_unexpectedly_running)) { ++ remote = rsc_contains_remote_node(data_set, rsc); ++ if (remote) { ++ unexpected_containers = g_list_append(unexpected_containers, remote); ++ } ++ } ++ } ++ } ++ ++ /* If a container resource is unexpectedly up... and the remote-node ++ * connection resource for that container is not up, the entire container ++ * must be recovered. */ ++ for (gIter = unexpected_containers; gIter != NULL; gIter = gIter->next) { ++ remote = (resource_t *) gIter->data; ++ if (remote->role != RSC_ROLE_STARTED) { ++ crm_warn("Recovering container resource %s. Resource is unexpectedly running and involves a remote-node."); ++ set_bit(remote->container->flags, pe_rsc_failed); + } + } + +@@ -2037,7 +2060,7 @@ unpack_lrm_resources(node_t * node, xmlNode * lrm_rsc_list, pe_working_set_t * d + if (found_orphaned_container_filler) { + handle_orphaned_container_fillers(lrm_rsc_list, data_set); + } +- ++ g_list_free(unexpected_containers); + return TRUE; + } + +@@ -2366,6 +2389,7 @@ unpack_rsc_op(resource_t * rsc, node_t * node, xmlNode * xml_op, + case PCMK_OCF_OK: + if (is_probe && target_rc == 7) { + task_status_i = PCMK_LRM_OP_DONE; ++ set_bit(rsc->flags, pe_rsc_unexpectedly_running); + pe_rsc_info(rsc, "Operation %s found resource %s active on %s", + task, rsc->id, node->details->uname); + +diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c +index 1e3877d..e9997a2 100644 +--- a/lib/pengine/utils.c ++++ b/lib/pengine/utils.c +@@ -1776,3 +1776,24 @@ const char *rsc_printable_id(resource_t *rsc) + } + return rsc->id; + } ++ ++resource_t * ++rsc_contains_remote_node(pe_working_set_t * data_set, resource_t *rsc) ++{ ++ if (is_set(data_set->flags, pe_flag_have_remote_nodes) == FALSE) { ++ return FALSE; ++ } ++ ++ if (rsc->fillers) { ++ GListPtr gIter = NULL; ++ for (gIter = rsc->fillers; gIter != NULL; gIter = gIter->next) { ++ resource_t *filler = (resource_t *) gIter->data; ++ ++ if (filler->is_remote_node) { ++ return filler; ++ } ++ } ++ } ++ return NULL; ++} ++ diff --git a/SOURCES/bz720543-pcmk-pe_update_regression_test_scores.patch b/SOURCES/bz720543-pcmk-pe_update_regression_test_scores.patch new file mode 100644 index 0000000..27fe927 --- /dev/null +++ b/SOURCES/bz720543-pcmk-pe_update_regression_test_scores.patch @@ -0,0 +1,21 @@ +commit 1106a46aa325068e42d36d70cdbb78d128602a0d +Author: Andrew Beekhof +Date: Mon Aug 12 11:54:10 2013 +1000 + + Test: PE: Update regression test scores + + (cherry picked from commit 86b339c959f41e9c94195317ba4aa90f09d72450) + +diff --git a/pengine/test10/utilization-order2.scores b/pengine/test10/utilization-order2.scores +index b289b72..22748db 100644 +--- a/pengine/test10/utilization-order2.scores ++++ b/pengine/test10/utilization-order2.scores +@@ -7,7 +7,7 @@ clone_color: rsc2:1 allocation score on node1: 0 + clone_color: rsc2:1 allocation score on node2: 1 + native_color: rsc1 allocation score on node1: 0 + native_color: rsc1 allocation score on node2: 0 +-native_color: rsc2:0 allocation score on node1: -INFINITY ++native_color: rsc2:0 allocation score on node1: 1 + native_color: rsc2:0 allocation score on node1: 1 + native_color: rsc2:0 allocation score on node2: -INFINITY + native_color: rsc2:0 allocation score on node2: 0 diff --git a/SOURCES/bz720543-pcmk-prevent_use_of_null_when_ping_resources_do_not_define_a_host_list.patch b/SOURCES/bz720543-pcmk-prevent_use_of_null_when_ping_resources_do_not_define_a_host_list.patch new file mode 100644 index 0000000..42b4265 --- /dev/null +++ b/SOURCES/bz720543-pcmk-prevent_use_of_null_when_ping_resources_do_not_define_a_host_list.patch @@ -0,0 +1,39 @@ +commit d4cf7c479c30b4543db45fcce9bf69352b77f85c +Author: Andrew Beekhof +Date: Tue Aug 6 20:36:14 2013 +1000 + + Fix: Prevent use-of-NULL when ping resources do not define a host list + + (cherry picked from commit 7f76afac965afa209e570deac612c696fdcaddb2) + +diff --git a/tools/crm_mon.c b/tools/crm_mon.c +index 9387b46..9d68237 100644 +--- a/tools/crm_mon.c ++++ b/tools/crm_mon.c +@@ -973,7 +973,6 @@ print_attr_msg(node_t * node, GListPtr rsc_list, const char *attrname, const cha + if (safe_str_eq(type, "ping") || safe_str_eq(type, "pingd")) { + const char *name = "pingd"; + const char *multiplier = NULL; +- char **host_list = NULL; + int host_list_num = 0; + int expected_score = 0; + +@@ -984,11 +983,15 @@ print_attr_msg(node_t * node, GListPtr rsc_list, const char *attrname, const cha + /* To identify the resource with the attribute name. */ + if (safe_str_eq(name, attrname)) { + int value = crm_parse_int(attrvalue, "0"); ++ const char *hosts = g_hash_table_lookup(rsc->parameters, "host_list"); + + multiplier = g_hash_table_lookup(rsc->parameters, "multiplier"); +- host_list = g_strsplit(g_hash_table_lookup(rsc->parameters, "host_list"), " ", 0); +- host_list_num = g_strv_length(host_list); +- g_strfreev(host_list); ++ if(hosts) { ++ char **host_list = g_strsplit(hosts, " ", 0); ++ host_list_num = g_strv_length(host_list); ++ g_strfreev(host_list); ++ } ++ + /* pingd multiplier is the same as the default value. */ + expected_score = host_list_num * crm_parse_int(multiplier, "1"); + diff --git a/SOURCES/bz720543-pcmk-reduce_duplication_by_merging_the_lrmd_exec_rc_enum_with_ocf_exitcode.patch b/SOURCES/bz720543-pcmk-reduce_duplication_by_merging_the_lrmd_exec_rc_enum_with_ocf_exitcode.patch new file mode 100644 index 0000000..ccbd8b6 --- /dev/null +++ b/SOURCES/bz720543-pcmk-reduce_duplication_by_merging_the_lrmd_exec_rc_enum_with_ocf_exitcode.patch @@ -0,0 +1,1075 @@ +commit 6de9bff49d55a5e03f3aac134fa651da02acc805 +Author: Andrew Beekhof +Date: Thu Aug 8 10:07:43 2013 +1000 + + Refactor: Reduce duplication by merging the lrmd_exec_rc enum with ocf_exitcode + + (cherry picked from commit 7c87227849a589b65eb4864fae2811d9cc39bc1b) + +diff --git a/crmd/lrm.c b/crmd/lrm.c +index 5f4d3bb..318c7f8 100644 +--- a/crmd/lrm.c ++++ b/crmd/lrm.c +@@ -691,20 +691,20 @@ is_rsc_active(lrm_state_t * lrm_state, const char *rsc_id) + + crm_trace("Processing %s: %s.%d=%d", + rsc_id, entry->last->op_type, entry->last->interval, entry->last->rc); +- if (entry->last->rc == PCMK_EXECRA_OK && safe_str_eq(entry->last->op_type, CRMD_ACTION_STOP)) { ++ if (entry->last->rc == PCMK_OCF_OK && safe_str_eq(entry->last->op_type, CRMD_ACTION_STOP)) { + return FALSE; + +- } else if (entry->last->rc == PCMK_EXECRA_OK ++ } else if (entry->last->rc == PCMK_OCF_OK + && safe_str_eq(entry->last->op_type, CRMD_ACTION_MIGRATE)) { + /* a stricter check is too complex... + * leave that to the PE + */ + return FALSE; + +- } else if (entry->last->rc == PCMK_EXECRA_NOT_RUNNING) { ++ } else if (entry->last->rc == PCMK_OCF_NOT_RUNNING) { + return FALSE; + +- } else if (entry->last->interval == 0 && entry->last->rc == PCMK_EXECRA_NOT_CONFIGURED) { ++ } else if (entry->last->interval == 0 && entry->last->rc == PCMK_OCF_NOT_CONFIGURED) { + /* Badly configured resources can't be reliably stopped */ + return FALSE; + } +@@ -812,10 +812,10 @@ notify_deleted(lrm_state_t * lrm_state, ha_msg_input_t * input, const char *rsc_ + + if (rc == pcmk_ok) { + op->op_status = PCMK_LRM_OP_DONE; +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + } else { + op->op_status = PCMK_LRM_OP_ERROR; +- op->rc = PCMK_EXECRA_UNKNOWN_ERROR; ++ op->rc = PCMK_OCF_UNKNOWN_ERROR; + } + + send_direct_ack(from_host, from_sys, NULL, op, rsc_id); +@@ -1295,7 +1295,7 @@ do_lrm_invoke(long long action, + } + op->interval = 0; + op->op_status = PCMK_LRM_OP_DONE; +- op->rc = PCMK_EXECRA_UNKNOWN_ERROR; ++ op->rc = PCMK_OCF_UNKNOWN_ERROR; + op->t_run = time(NULL); + op->t_rcchange = op->t_run; + +@@ -1313,7 +1313,7 @@ do_lrm_invoke(long long action, + crm_info("Failing resource %s...", rsc->id); + process_lrm_event(lrm_state, op); + op->op_status = PCMK_LRM_OP_DONE; +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + lrmd_free_rsc_info(rsc); + } else { + crm_info("Cannot find/create resource in order to fail it..."); +@@ -1425,7 +1425,7 @@ do_lrm_invoke(long long action, + + op = construct_op(lrm_state, input->xml, ID(xml_rsc), operation); + op->op_status = PCMK_LRM_OP_DONE; +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + CRM_ASSERT(op != NULL); + send_direct_ack(from_host, from_sys, NULL, op, ID(xml_rsc)); + lrmd_free_event(op); +@@ -1486,7 +1486,7 @@ do_lrm_invoke(long long action, + g_hash_table_remove(lrm_state->pending_ops, op_key); + } + +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + op->op_status = PCMK_LRM_OP_DONE; + send_direct_ack(from_host, from_sys, rsc, op, rsc->id); + +@@ -1509,9 +1509,9 @@ do_lrm_invoke(long long action, + op->op_status = PCMK_LRM_OP_ERROR; + + if (cib_rc == -EACCES) { +- op->rc = PCMK_EXECRA_INSUFFICIENT_PRIV; ++ op->rc = PCMK_OCF_INSUFFICIENT_PRIV; + } else { +- op->rc = PCMK_EXECRA_UNKNOWN_ERROR; ++ op->rc = PCMK_OCF_UNKNOWN_ERROR; + } + send_direct_ack(from_host, from_sys, NULL, op, rsc->id); + lrmd_free_event(op); +@@ -2046,7 +2046,7 @@ process_lrm_event(lrm_state_t * lrm_state, lrmd_event_data_t * op) + } + + if (op->op_status == PCMK_LRM_OP_ERROR +- && (op->rc == PCMK_EXECRA_RUNNING_MASTER || op->rc == PCMK_EXECRA_NOT_RUNNING)) { ++ && (op->rc == PCMK_OCF_RUNNING_MASTER || op->rc == PCMK_OCF_NOT_RUNNING)) { + /* Leave it up to the TE/PE to decide if this is an error */ + op->op_status = PCMK_LRM_OP_DONE; + log_level = LOG_INFO; +@@ -2096,7 +2096,7 @@ process_lrm_event(lrm_state_t * lrm_state, lrmd_event_data_t * op) + do_crm_log(log_level, + "LRM operation %s (call=%d, rc=%d, cib-update=%d, confirmed=%s) %s", + op_key, op->call_id, op->rc, update_id, removed ? "true" : "false", +- lrmd_event_rc2str(op->rc)); ++ services_ocf_exitcode_str(op->rc)); + } else { + do_crm_log(log_level, + "LRM operation %s (call=%d, status=%d, cib-update=%d, confirmed=%s) %s", +diff --git a/crmd/remote_lrmd_ra.c b/crmd/remote_lrmd_ra.c +index 42ea043..fbb9ecb 100644 +--- a/crmd/remote_lrmd_ra.c ++++ b/crmd/remote_lrmd_ra.c +@@ -211,7 +211,7 @@ retry_start_cmd_cb(gpointer data) + } + + if (rc != 0) { +- cmd->rc = PCMK_EXECRA_UNKNOWN_ERROR; ++ cmd->rc = PCMK_OCF_UNKNOWN_ERROR; + cmd->op_status = PCMK_LRM_OP_ERROR; + report_remote_ra_result(cmd); + +@@ -236,7 +236,7 @@ monitor_timeout_cb(gpointer data) + crm_debug("Poke async response timed out for node %s", cmd->rsc_id); + cmd->monitor_timeout_id = 0; + cmd->op_status = PCMK_LRM_OP_TIMEOUT; +- cmd->rc = PCMK_EXECRA_UNKNOWN_ERROR; ++ cmd->rc = PCMK_OCF_UNKNOWN_ERROR; + + lrm_state = lrm_state_find(cmd->rsc_id); + if (lrm_state && lrm_state->remote_ra_data) { +@@ -291,7 +291,7 @@ remote_lrm_op_callback(lrmd_event_data_t * op) + lrmd_event_type2str(op->type), + op->remote_nodename, + op->op_type ? op->op_type : "none", +- lrmd_event_rc2str(op->rc), services_lrm_status_str(op->op_status)); ++ services_ocf_exitcode_str(op->rc), services_lrm_status_str(op->op_status)); + + /* filter all EXEC events up */ + if (op->type == lrmd_event_exec_complete) { +@@ -329,7 +329,7 @@ remote_lrm_op_callback(lrmd_event_data_t * op) + cmd->remaining_timeout); + } + cmd->op_status = PCMK_LRM_OP_TIMEOUT; +- cmd->rc = PCMK_EXECRA_UNKNOWN_ERROR; ++ cmd->rc = PCMK_OCF_UNKNOWN_ERROR; + + } else { + /* make sure we have a clean status section to start with */ +@@ -338,7 +338,7 @@ remote_lrm_op_callback(lrmd_event_data_t * op) + erase_status_tag(lrm_state->node_name, XML_CIB_TAG_LRM, cib_scope_local); + erase_status_tag(lrm_state->node_name, XML_TAG_TRANSIENT_NODEATTRS, cib_scope_local); + +- cmd->rc = PCMK_EXECRA_OK; ++ cmd->rc = PCMK_OCF_OK; + cmd->op_status = PCMK_LRM_OP_DONE; + } + +@@ -361,7 +361,7 @@ remote_lrm_op_callback(lrmd_event_data_t * op) + * For this function, if we get the poke pack, it is always a success. Pokes + * only fail if the send fails, or the response times out. */ + if (!cmd->reported_success) { +- cmd->rc = PCMK_EXECRA_OK; ++ cmd->rc = PCMK_OCF_OK; + cmd->op_status = PCMK_LRM_OP_DONE; + report_remote_ra_result(cmd); + cmd->reported_success = 1; +@@ -442,7 +442,7 @@ handle_remote_ra_exec(gpointer user_data) + return TRUE; + } else { + crm_debug("connect failed, not expecting to match any connection event later"); +- cmd->rc = PCMK_EXECRA_UNKNOWN_ERROR; ++ cmd->rc = PCMK_OCF_UNKNOWN_ERROR; + cmd->op_status = PCMK_LRM_OP_ERROR; + } + report_remote_ra_result(cmd); +@@ -452,13 +452,13 @@ handle_remote_ra_exec(gpointer user_data) + if (lrm_state_is_connected(lrm_state) == TRUE) { + rc = lrm_state_poke_connection(lrm_state); + if (rc < 0) { +- cmd->rc = PCMK_EXECRA_UNKNOWN_ERROR; ++ cmd->rc = PCMK_OCF_UNKNOWN_ERROR; + cmd->op_status = PCMK_LRM_OP_ERROR; + } + } else { + rc = -1; + cmd->op_status = PCMK_LRM_OP_DONE; +- cmd->rc = PCMK_EXECRA_NOT_RUNNING; ++ cmd->rc = PCMK_OCF_NOT_RUNNING; + } + + if (rc == 0) { +@@ -471,7 +471,7 @@ handle_remote_ra_exec(gpointer user_data) + + } else if (!strcmp(cmd->action, "stop")) { + lrm_state_disconnect(lrm_state); +- cmd->rc = PCMK_EXECRA_OK; ++ cmd->rc = PCMK_OCF_OK; + cmd->op_status = PCMK_LRM_OP_DONE; + + if (ra_data->cmds) { +@@ -486,7 +486,7 @@ handle_remote_ra_exec(gpointer user_data) + + } else if (!strcmp(cmd->action, "migrate_to")) { + /* no-op. */ +- cmd->rc = PCMK_EXECRA_OK; ++ cmd->rc = PCMK_OCF_OK; + cmd->op_status = PCMK_LRM_OP_DONE; + report_remote_ra_result(cmd); + } +diff --git a/crmd/te_actions.c b/crmd/te_actions.c +index b533f58..63d15bb 100644 +--- a/crmd/te_actions.c ++++ b/crmd/te_actions.c +@@ -465,7 +465,7 @@ te_rsc_command(crm_graph_t * graph, crm_action_t * action) + && safe_str_neq(task, CRMD_ACTION_DELETE)) { + /* write a "pending" entry to the CIB, inhibit notification */ + crm_debug("Recording pending op %s in the CIB", task_uuid); +- cib_action_update(action, PCMK_LRM_OP_PENDING, PCMK_EXECRA_STATUS_UNKNOWN); ++ cib_action_update(action, PCMK_LRM_OP_PENDING, PCMK_OCF_STATUS_UNKNOWN); + } + + return TRUE; +diff --git a/crmd/te_callbacks.c b/crmd/te_callbacks.c +index 3d923b2..c0360b4 100644 +--- a/crmd/te_callbacks.c ++++ b/crmd/te_callbacks.c +@@ -548,8 +548,8 @@ action_timer_callback(gpointer data) + } + + if (send_update) { +- /* cib_action_update(timer->action, PCMK_LRM_OP_PENDING, PCMK_EXECRA_STATUS_UNKNOWN); */ +- cib_action_update(timer->action, PCMK_LRM_OP_TIMEOUT, PCMK_EXECRA_UNKNOWN_ERROR); ++ /* cib_action_update(timer->action, PCMK_LRM_OP_PENDING, PCMK_OCF_STATUS_UNKNOWN); */ ++ cib_action_update(timer->action, PCMK_LRM_OP_TIMEOUT, PCMK_OCF_UNKNOWN_ERROR); + } + } + +diff --git a/crmd/te_events.c b/crmd/te_events.c +index bc474bd..78d00dd 100644 +--- a/crmd/te_events.c ++++ b/crmd/te_events.c +@@ -540,7 +540,7 @@ process_graph_event(xmlNode * event, const char *event_node) + desc = "failed"; + } + crm_info("Detected action (%d.%d) %s.%d=%s: %s", transition_num, action, id, callid, +- lrmd_event_rc2str(rc), desc); ++ services_ocf_exitcode_str(rc), desc); + } + + bail: +diff --git a/fencing/commands.c b/fencing/commands.c +index 7ef003d..7d04952 100644 +--- a/fencing/commands.c ++++ b/fencing/commands.c +@@ -224,7 +224,7 @@ stonith_device_execute(stonith_device_t * device) + } else { + crm_err("failed to get secrets for %s, " + "considering resource not configured", device->id); +- exec_rc = PCMK_EXECRA_NOT_CONFIGURED; ++ exec_rc = PCMK_OCF_NOT_CONFIGURED; + cmd->done_cb(0, exec_rc, NULL, cmd); + return TRUE; + } +diff --git a/include/crm/lrmd.h b/include/crm/lrmd.h +index f627373..b8c3167 100644 +--- a/include/crm/lrmd.h ++++ b/include/crm/lrmd.h +@@ -22,6 +22,7 @@ + * \brief Local Resource Manager + * \ingroup lrm + */ ++#include + + #ifndef LRMD__H + # define LRMD__H +@@ -166,21 +167,6 @@ enum lrmd_callback_event { + lrmd_event_poke, + }; + +-enum lrmd_exec_rc { +- PCMK_EXECRA_OK = 0, +- PCMK_EXECRA_UNKNOWN_ERROR = 1, +- PCMK_EXECRA_INVALID_PARAM = 2, +- PCMK_EXECRA_UNIMPLEMENT_FEATURE = 3, +- PCMK_EXECRA_INSUFFICIENT_PRIV = 4, +- PCMK_EXECRA_NOT_INSTALLED = 5, +- PCMK_EXECRA_NOT_CONFIGURED = 6, +- PCMK_EXECRA_NOT_RUNNING = 7, +- PCMK_EXECRA_RUNNING_MASTER = 8, +- PCMK_EXECRA_FAILED_MASTER = 9, +- +- /* For status command only */ +- PCMK_EXECRA_STATUS_UNKNOWN = 14, +-}; + /* *INDENT-ON* */ + + typedef struct lrmd_event_data_s { +@@ -205,8 +191,8 @@ typedef struct lrmd_event_data_s { + /*! This operation that just completed is on a deleted rsc. */ + int rsc_deleted; + +- /*! The executed ra return code */ +- enum lrmd_exec_rc rc; ++ /*! The executed ra return code mapped to OCF */ ++ enum ocf_exitcode rc; + /*! The lrmd status returned for exec_complete events */ + int op_status; + /*! stdout from resource agent operation */ +@@ -448,38 +434,6 @@ struct lrmd_s { + }; + + static inline const char * +-lrmd_event_rc2str(enum lrmd_exec_rc rc) +-{ +- switch (rc) { +- case PCMK_EXECRA_OK: +- return "ok"; +- case PCMK_EXECRA_UNKNOWN_ERROR: +- return "unknown error"; +- case PCMK_EXECRA_INVALID_PARAM: +- return "invalid parameter"; +- case PCMK_EXECRA_UNIMPLEMENT_FEATURE: +- return "unimplemented feature"; +- case PCMK_EXECRA_INSUFFICIENT_PRIV: +- return "insufficient privileges"; +- case PCMK_EXECRA_NOT_INSTALLED: +- return "not installed"; +- case PCMK_EXECRA_NOT_CONFIGURED: +- return "not configured"; +- case PCMK_EXECRA_NOT_RUNNING: +- return "not running"; +- case PCMK_EXECRA_RUNNING_MASTER: +- return "master"; +- case PCMK_EXECRA_FAILED_MASTER: +- return "master (failed)"; +- case PCMK_EXECRA_STATUS_UNKNOWN: +- return "status: unknown"; +- default: +- break; +- } +- return ""; +-} +- +-static inline const char * + lrmd_event_type2str(enum lrmd_callback_event type) + { + switch (type) { +diff --git a/include/crm/services.h b/include/crm/services.h +index fb5c6b0..0c0cca9 100644 +--- a/include/crm/services.h ++++ b/include/crm/services.h +@@ -31,6 +31,7 @@ extern "C" { + + # include + # include ++# include + + # ifndef OCF_ROOT_DIR + # define OCF_ROOT_DIR "/usr/lib/ocf" +@@ -59,34 +60,22 @@ enum lsb_exitcode { + PCMK_LSB_NOT_INSTALLED = 5, + PCMK_LSB_NOT_CONFIGURED = 6, + PCMK_LSB_NOT_RUNNING = 7, +- +- /* 150-199 reserved for application use */ +- PCMK_LSB_SIGNAL = 194, +- PCMK_LSB_NOT_SUPPORTED = 195, +- PCMK_LSB_PENDING = 196, +- PCMK_LSB_CANCELLED = 197, +- PCMK_LSB_TIMEOUT = 198, +- PCMK_LSB_OTHER_ERROR = 199, + }; + + /* The return codes for the status operation are not the same for other +- * operatios - go figure */ ++ * operatios - go figure ++ */ + enum lsb_status_exitcode { + PCMK_LSB_STATUS_OK = 0, + PCMK_LSB_STATUS_VAR_PID = 1, + PCMK_LSB_STATUS_VAR_LOCK = 2, + PCMK_LSB_STATUS_NOT_RUNNING = 3, + PCMK_LSB_STATUS_NOT_INSTALLED = 4, +- +- /* 150-199 reserved for application use */ +- PCMK_LSB_STATUS_SIGNAL = 194, +- PCMK_LSB_STATUS_NOT_SUPPORTED = 195, +- PCMK_LSB_STATUS_PENDING = 196, +- PCMK_LSB_STATUS_CANCELLED = 197, +- PCMK_LSB_STATUS_TIMEOUT = 198, +- PCMK_LSB_STATUS_OTHER_ERROR = 199, + }; + ++/* Uniform exit codes ++ * Everything is mapped to its OCF equivalent so that Pacemaker only deals with one set of codes ++ */ + enum ocf_exitcode { + PCMK_OCF_OK = 0, + PCMK_OCF_UNKNOWN_ERROR = 1, +@@ -95,10 +84,12 @@ enum ocf_exitcode { + PCMK_OCF_INSUFFICIENT_PRIV = 4, + PCMK_OCF_NOT_INSTALLED = 5, + PCMK_OCF_NOT_CONFIGURED = 6, +- PCMK_OCF_NOT_RUNNING = 7, ++ PCMK_OCF_NOT_RUNNING = 7, /* End of overlap with LSB */ + PCMK_OCF_RUNNING_MASTER = 8, + PCMK_OCF_FAILED_MASTER = 9, + ++ PCMK_OCF_STATUS_UNKNOWN = 14, /* Already in use */ ++ + /* 150-199 reserved for application use */ + PCMK_OCF_SIGNAL = 194, + PCMK_OCF_NOT_SUPPORTED = 195, +@@ -114,7 +105,7 @@ enum op_status { + PCMK_LRM_OP_CANCELLED, + PCMK_LRM_OP_TIMEOUT, + PCMK_LRM_OP_NOTSUPPORTED, +- PCMK_LRM_OP_ERROR ++ PCMK_LRM_OP_ERROR, + }; + + enum nagios_exitcode { +@@ -276,25 +267,25 @@ enum nagios_exitcode { + }} static inline const char *services_ocf_exitcode_str(enum ocf_exitcode code) { + switch (code) { + case PCMK_OCF_OK: +- return "OCF_OK"; ++ return "ok"; + case PCMK_OCF_UNKNOWN_ERROR: +- return "OCF_UNKNOWN_ERROR"; ++ return "unknown error"; + case PCMK_OCF_INVALID_PARAM: +- return "OCF_INVALID_PARAM"; ++ return "invalid parameter"; + case PCMK_OCF_UNIMPLEMENT_FEATURE: +- return "OCF_UNIMPLEMENT_FEATURE"; ++ return "unimplemented feature"; + case PCMK_OCF_INSUFFICIENT_PRIV: +- return "OCF_INSUFFICIENT_PRIV"; ++ return "insufficient privileges"; + case PCMK_OCF_NOT_INSTALLED: +- return "OCF_NOT_INSTALLED"; ++ return "not installed"; + case PCMK_OCF_NOT_CONFIGURED: +- return "OCF_NOT_CONFIGURED"; ++ return "not configured"; + case PCMK_OCF_NOT_RUNNING: +- return "OCF_NOT_RUNNING"; ++ return "not running"; + case PCMK_OCF_RUNNING_MASTER: +- return "OCF_RUNNING_MASTER"; ++ return "master"; + case PCMK_OCF_FAILED_MASTER: +- return "OCF_FAILED_MASTER"; ++ return "master (failed)"; + case PCMK_OCF_SIGNAL: + return "OCF_SIGNAL"; + case PCMK_OCF_NOT_SUPPORTED: +diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c +index 26cecb2..78ceb85 100644 +--- a/lib/pengine/unpack.c ++++ b/lib/pengine/unpack.c +@@ -2205,8 +2205,8 @@ unpack_rsc_op(resource_t * rsc, node_t * node, xmlNode * xml_op, + task_status_i = PCMK_LRM_OP_ERROR; + pe_rsc_debug(rsc, "%s on %s returned %d (%s) instead of the expected value: %d (%s)", + id, node->details->uname, +- actual_rc_i, lrmd_event_rc2str(actual_rc_i), +- target_rc, lrmd_event_rc2str(target_rc)); ++ actual_rc_i, services_ocf_exitcode_str(actual_rc_i), ++ target_rc, services_ocf_exitcode_str(target_rc)); + } + + } else if (task_status_i == PCMK_LRM_OP_ERROR) { +@@ -2215,7 +2215,7 @@ unpack_rsc_op(resource_t * rsc, node_t * node, xmlNode * xml_op, + } + + if (task_status_i == PCMK_LRM_OP_NOTSUPPORTED) { +- actual_rc_i = PCMK_EXECRA_UNIMPLEMENT_FEATURE; ++ actual_rc_i = PCMK_OCF_UNIMPLEMENT_FEATURE; + } + + if (expired) { +@@ -2254,8 +2254,8 @@ unpack_rsc_op(resource_t * rsc, node_t * node, xmlNode * xml_op, + } + + if (expired +- && actual_rc_i != PCMK_EXECRA_NOT_RUNNING +- && actual_rc_i != PCMK_EXECRA_RUNNING_MASTER && actual_rc_i != PCMK_EXECRA_OK) { ++ && actual_rc_i != PCMK_OCF_NOT_RUNNING ++ && actual_rc_i != PCMK_OCF_RUNNING_MASTER && actual_rc_i != PCMK_OCF_OK) { + if(interval == 0) { + crm_notice("Ignoring expired failure %s (rc=%d, magic=%s) on %s", + id, actual_rc_i, magic, node->details->uname); +@@ -2273,7 +2273,7 @@ unpack_rsc_op(resource_t * rsc, node_t * node, xmlNode * xml_op, + * didnt include target_rc and liked to remap status + */ + switch (actual_rc_i) { +- case PCMK_EXECRA_NOT_RUNNING: ++ case PCMK_OCF_NOT_RUNNING: + if (is_probe || target_rc == actual_rc_i) { + task_status_i = PCMK_LRM_OP_DONE; + rsc->role = RSC_ROLE_STOPPED; +@@ -2287,7 +2287,7 @@ unpack_rsc_op(resource_t * rsc, node_t * node, xmlNode * xml_op, + } + break; + +- case PCMK_EXECRA_RUNNING_MASTER: ++ case PCMK_OCF_RUNNING_MASTER: + if (is_probe) { + task_status_i = PCMK_LRM_OP_DONE; + crm_notice("Operation %s found resource %s active in master mode on %s", +@@ -2311,42 +2311,42 @@ unpack_rsc_op(resource_t * rsc, node_t * node, xmlNode * xml_op, + rsc->role = RSC_ROLE_MASTER; + break; + +- case PCMK_EXECRA_FAILED_MASTER: ++ case PCMK_OCF_FAILED_MASTER: + rsc->role = RSC_ROLE_MASTER; + task_status_i = PCMK_LRM_OP_ERROR; + break; + +- case PCMK_EXECRA_UNIMPLEMENT_FEATURE: ++ case PCMK_OCF_UNIMPLEMENT_FEATURE: + if (interval > 0) { + task_status_i = PCMK_LRM_OP_NOTSUPPORTED; + break; + } + /* else: fall through */ +- case PCMK_EXECRA_INSUFFICIENT_PRIV: +- case PCMK_EXECRA_NOT_INSTALLED: +- case PCMK_EXECRA_INVALID_PARAM: ++ case PCMK_OCF_INSUFFICIENT_PRIV: ++ case PCMK_OCF_NOT_INSTALLED: ++ case PCMK_OCF_INVALID_PARAM: + effective_node = node; + if(pe_can_fence(data_set, node) == FALSE + && safe_str_eq(task, CRMD_ACTION_STOP)) { + /* If a stop fails and we can't fence, there's nothing else we can do */ + pe_proc_err("No further recovery can be attempted for %s: %s action failed with '%s' (%d)", +- rsc->id, task, lrmd_event_rc2str(actual_rc_i), actual_rc_i); ++ rsc->id, task, services_ocf_exitcode_str(actual_rc_i), actual_rc_i); + clear_bit(rsc->flags, pe_rsc_managed); + set_bit(rsc->flags, pe_rsc_block); + } + /* fall through */ +- case PCMK_EXECRA_NOT_CONFIGURED: ++ case PCMK_OCF_NOT_CONFIGURED: + failed = rsc; + if (is_not_set(rsc->flags, pe_rsc_unique)) { + failed = uber_parent(failed); + } + +- do_crm_log(actual_rc_i == PCMK_EXECRA_NOT_INSTALLED ? LOG_NOTICE : LOG_ERR, ++ do_crm_log(actual_rc_i == PCMK_OCF_NOT_INSTALLED ? LOG_NOTICE : LOG_ERR, + "Preventing %s from re-starting %s %s: operation %s failed '%s' (rc=%d)", + failed->id, + effective_node ? "on" : "anywhere in the cluster", + effective_node ? effective_node->details->uname : "", +- task, lrmd_event_rc2str(actual_rc_i), actual_rc_i); ++ task, services_ocf_exitcode_str(actual_rc_i), actual_rc_i); + + resource_location(failed, effective_node, -INFINITY, "hard-error", data_set); + if (is_probe) { +@@ -2354,7 +2354,7 @@ unpack_rsc_op(resource_t * rsc, node_t * node, xmlNode * xml_op, + task = CRMD_ACTION_STOP; + task_status_i = PCMK_LRM_OP_DONE; + crm_xml_add(xml_op, XML_ATTR_UNAME, node->details->uname); +- if (actual_rc_i != PCMK_EXECRA_NOT_INSTALLED ++ if (actual_rc_i != PCMK_OCF_NOT_INSTALLED + || is_set(data_set->flags, pe_flag_symmetric_cluster)) { + if ((node->details->shutdown == FALSE) || (node->details->online == TRUE)) { + add_node_copy(data_set->failed, xml_op); +@@ -2363,7 +2363,7 @@ unpack_rsc_op(resource_t * rsc, node_t * node, xmlNode * xml_op, + } + break; + +- case PCMK_EXECRA_OK: ++ case PCMK_OCF_OK: + if (is_probe && target_rc == 7) { + task_status_i = PCMK_LRM_OP_DONE; + pe_rsc_info(rsc, "Operation %s found resource %s active on %s", +@@ -2447,7 +2447,7 @@ unpack_rsc_op(resource_t * rsc, node_t * node, xmlNode * xml_op, + case PCMK_LRM_OP_DONE: + pe_rsc_trace(rsc, "%s/%s completed on %s", rsc->id, task, node->details->uname); + +- if (actual_rc_i == PCMK_EXECRA_NOT_RUNNING) { ++ if (actual_rc_i == PCMK_OCF_NOT_RUNNING) { + clear_past_failure = TRUE; + + } else if (safe_str_eq(task, CRMD_ACTION_STATUS)) { +@@ -2519,7 +2519,7 @@ unpack_rsc_op(resource_t * rsc, node_t * node, xmlNode * xml_op, + ID(migrate_from), migrate_target, from_status, from_rc); + } + +- if (migrate_from && from_rc == PCMK_EXECRA_OK ++ if (migrate_from && from_rc == PCMK_OCF_OK + && from_status == PCMK_LRM_OP_DONE) { + pe_rsc_trace(rsc, "Detected dangling migration op: %s on %s", ID(xml_op), + migrate_source); +@@ -2603,7 +2603,7 @@ unpack_rsc_op(resource_t * rsc, node_t * node, xmlNode * xml_op, + case PCMK_LRM_OP_TIMEOUT: + case PCMK_LRM_OP_NOTSUPPORTED: + crm_warn("Processing failed op %s for %s on %s: %s (%d)", +- task, rsc->id, node->details->uname, lrmd_event_rc2str(actual_rc_i), ++ task, rsc->id, node->details->uname, services_ocf_exitcode_str(actual_rc_i), + actual_rc_i); + crm_xml_add(xml_op, XML_ATTR_UNAME, node->details->uname); + if ((node->details->shutdown == FALSE) || (node->details->online == TRUE)) { +diff --git a/lib/services/systemd.c b/lib/services/systemd.c +index 74cf53e..783caca 100644 +--- a/lib/services/systemd.c ++++ b/lib/services/systemd.c +@@ -381,10 +381,10 @@ systemd_unit_exec_done(GObject * source_object, GAsyncResult * res, gpointer use + + if (safe_str_eq(op->action, "stop")) { + crm_trace("Masking Stop failure for %s: unknown services are stopped", op->rsc); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + + } else { +- op->rc = PCMK_EXECRA_NOT_INSTALLED; ++ op->rc = PCMK_OCF_NOT_INSTALLED; + } + + } else { +@@ -398,11 +398,11 @@ systemd_unit_exec_done(GObject * source_object, GAsyncResult * res, gpointer use + g_variant_get(_ret, "(o)", &path); + crm_info("Call to %s passed: type '%s' %s", op->action, g_variant_get_type_string(_ret), + path); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + + } else { + crm_err("Call to %s passed but return type was '%s' not '(o)'", op->action, g_variant_get_type_string(_ret)); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + } + + operation_finalize(op); +@@ -423,7 +423,7 @@ systemd_unit_exec(svc_action_t * op, gboolean synchronous) + const char *action = op->action; + char *name = systemd_service_name(op->agent); + +- op->rc = PCMK_EXECRA_UNKNOWN_ERROR; ++ op->rc = PCMK_OCF_UNKNOWN_ERROR; + CRM_ASSERT(systemd_init()); + + crm_debug("Performing %ssynchronous %s op on systemd unit %s named '%s'", +@@ -431,7 +431,7 @@ systemd_unit_exec(svc_action_t * op, gboolean synchronous) + + if (safe_str_eq(op->action, "meta-data")) { + op->stdout_data = systemd_unit_metadata(op->agent); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + goto cleanup; + } + +@@ -440,7 +440,7 @@ systemd_unit_exec(svc_action_t * op, gboolean synchronous) + crm_debug("Could not obtain unit named '%s': %s", op->agent, + error ? error->message : "unknown"); + if (error && strstr(error->message, "systemd1.NoSuchUnit")) { +- op->rc = PCMK_EXECRA_NOT_INSTALLED; ++ op->rc = PCMK_OCF_NOT_INSTALLED; + } + if(error) { + g_error_free(error); +@@ -452,9 +452,9 @@ systemd_unit_exec(svc_action_t * op, gboolean synchronous) + char *state = systemd_unit_property(unit, BUS_NAME ".Unit", "ActiveState"); + + if (g_strcmp0(state, "active") == 0) { +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + } else { +- op->rc = PCMK_EXECRA_NOT_RUNNING; ++ op->rc = PCMK_OCF_NOT_RUNNING; + } + + free(state); +@@ -504,7 +504,7 @@ systemd_unit_exec(svc_action_t * op, gboolean synchronous) + } else if (g_strcmp0(action, "restart") == 0) { + action = "RestartUnit"; + } else { +- op->rc = PCMK_EXECRA_UNIMPLEMENT_FEATURE; ++ op->rc = PCMK_OCF_UNIMPLEMENT_FEATURE; + goto cleanup; + } + +@@ -525,7 +525,7 @@ systemd_unit_exec(svc_action_t * op, gboolean synchronous) + if (safe_str_eq(op->action, "stop") + && strstr(error->message, "systemd1.InvalidName")) { + crm_trace("Masking Stop failure for %s: unknown services are stopped", op->rsc); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + } else { + crm_err("Could not issue %s for %s: %s (%s)", action, op->rsc, error->message, unit); + } +@@ -537,11 +537,11 @@ systemd_unit_exec(svc_action_t * op, gboolean synchronous) + g_variant_get(_ret, "(o)", &path); + crm_info("Call to %s passed: type '%s' %s", op->action, g_variant_get_type_string(_ret), + path); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + + } else { + crm_err("Call to %s passed but return type was '%s' not '(o)'", op->action, g_variant_get_type_string(_ret)); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + } + + cleanup: +@@ -555,5 +555,5 @@ systemd_unit_exec(svc_action_t * op, gboolean synchronous) + operation_finalize(op); + return TRUE; + } +- return op->rc == PCMK_EXECRA_OK; ++ return op->rc == PCMK_OCF_OK; + } +diff --git a/lib/services/upstart.c b/lib/services/upstart.c +index f5fa189..daeb398 100644 +--- a/lib/services/upstart.c ++++ b/lib/services/upstart.c +@@ -384,12 +384,12 @@ upstart_job_exec_done(GObject * source_object, GAsyncResult * res, gpointer user + if (safe_str_eq(op->action, "start") + && strstr(error->message, BUS_MANAGER_IFACE ".Error.AlreadyStarted")) { + crm_trace("Masking Start failure for %s: already started", op->rsc); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + + } else if (safe_str_eq(op->action, "stop") + && strstr(error->message, BUS_MANAGER_IFACE ".Error.UnknownInstance")) { + crm_trace("Masking Stop failure for %s: unknown services are stopped", op->rsc); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + } else { + crm_err("Could not issue %s for %s: %s", op->action, op->rsc, error->message); + } +@@ -401,11 +401,11 @@ upstart_job_exec_done(GObject * source_object, GAsyncResult * res, gpointer user + g_variant_get(_ret, "(o)", &path); + crm_info("Call to %s passed: type '%s' %s", op->action, g_variant_get_type_string(_ret), + path); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + + } else { + crm_err("Call to %s passed but return type was '%s' not '(o)'", op->action, g_variant_get_type_string(_ret)); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + } + + operation_finalize(op); +@@ -427,12 +427,12 @@ upstart_job_exec(svc_action_t * op, gboolean synchronous) + GVariant *_ret = NULL; + GDBusProxy *job_proxy = NULL; + +- op->rc = PCMK_EXECRA_UNKNOWN_ERROR; ++ op->rc = PCMK_OCF_UNKNOWN_ERROR; + CRM_ASSERT(upstart_init()); + + if (safe_str_eq(op->action, "meta-data")) { + op->stdout_data = upstart_job_metadata(op->agent); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + goto cleanup; + } + +@@ -443,18 +443,18 @@ upstart_job_exec(svc_action_t * op, gboolean synchronous) + } + if (pass == FALSE) { + if (!g_strcmp0(action, "stop")) { +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + } else { +- op->rc = PCMK_EXECRA_NOT_INSTALLED; ++ op->rc = PCMK_OCF_NOT_INSTALLED; + } + goto cleanup; + } + + if (safe_str_eq(op->action, "monitor") || safe_str_eq(action, "status")) { + if (upstart_job_running(op->agent)) { +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + } else { +- op->rc = PCMK_EXECRA_NOT_RUNNING; ++ op->rc = PCMK_OCF_NOT_RUNNING; + } + goto cleanup; + +@@ -465,7 +465,7 @@ upstart_job_exec(svc_action_t * op, gboolean synchronous) + } else if (!g_strcmp0(action, "restart")) { + action = "Restart"; + } else { +- op->rc = PCMK_EXECRA_UNIMPLEMENT_FEATURE; ++ op->rc = PCMK_OCF_UNIMPLEMENT_FEATURE; + goto cleanup; + } + +@@ -487,11 +487,11 @@ upstart_job_exec(svc_action_t * op, gboolean synchronous) + if (safe_str_eq(action, "Start") + && strstr(error->message, BUS_MANAGER_IFACE ".Error.AlreadyStarted")) { + crm_trace("Masking Start failure for %s: already started", op->rsc); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + } else if (safe_str_eq(action, "Stop") + && strstr(error->message, BUS_MANAGER_IFACE ".Error.UnknownInstance")) { + crm_trace("Masking Stop failure for %s: unknown services are stopped", op->rsc); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + } else { + crm_err("Could not issue %s for %s: %s (%s)", action, op->rsc, error->message, job); + } +@@ -502,11 +502,11 @@ upstart_job_exec(svc_action_t * op, gboolean synchronous) + g_variant_get(_ret, "(o)", &path); + crm_info("Call to %s passed: type '%s' %s", op->action, g_variant_get_type_string(_ret), + path); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + + } else { + crm_err("Call to %s passed but return type was '%s' not '(o)'", op->action, g_variant_get_type_string(_ret)); +- op->rc = PCMK_EXECRA_OK; ++ op->rc = PCMK_OCF_OK; + } + + cleanup: +@@ -524,5 +524,5 @@ upstart_job_exec(svc_action_t * op, gboolean synchronous) + operation_finalize(op); + return TRUE; + } +- return op->rc == PCMK_EXECRA_OK; ++ return op->rc == PCMK_OCF_OK; + } +diff --git a/lrmd/lrmd.c b/lrmd/lrmd.c +index b5bbea0..8592b6c 100644 +--- a/lrmd/lrmd.c ++++ b/lrmd/lrmd.c +@@ -460,38 +460,38 @@ static int + lsb2uniform_rc(const char *action, int rc) + { + if (rc < 0) { +- return PCMK_EXECRA_UNKNOWN_ERROR; ++ return PCMK_OCF_UNKNOWN_ERROR; + } + + /* status has different return codes that everything else. */ + if (!safe_str_eq(action, "status") && !safe_str_eq(action, "monitor")) { + if (rc > PCMK_LSB_NOT_RUNNING) { +- return PCMK_EXECRA_UNKNOWN_ERROR; ++ return PCMK_OCF_UNKNOWN_ERROR; + } + return rc; + } + + switch (rc) { + case PCMK_LSB_STATUS_OK: +- return PCMK_EXECRA_OK; ++ return PCMK_OCF_OK; + case PCMK_LSB_STATUS_NOT_INSTALLED: +- return PCMK_EXECRA_NOT_INSTALLED; ++ return PCMK_OCF_NOT_INSTALLED; + case PCMK_LSB_STATUS_VAR_PID: + case PCMK_LSB_STATUS_VAR_LOCK: + case PCMK_LSB_STATUS_NOT_RUNNING: +- return PCMK_EXECRA_NOT_RUNNING; ++ return PCMK_OCF_NOT_RUNNING; + default: +- return PCMK_EXECRA_UNKNOWN_ERROR; ++ return PCMK_OCF_UNKNOWN_ERROR; + } + +- return PCMK_EXECRA_UNKNOWN_ERROR; ++ return PCMK_OCF_UNKNOWN_ERROR; + } + + static int + ocf2uniform_rc(int rc) + { + if (rc < 0 || rc > PCMK_OCF_FAILED_MASTER) { +- return PCMK_EXECRA_UNKNOWN_ERROR; ++ return PCMK_OCF_UNKNOWN_ERROR; + } + + return rc; +@@ -502,14 +502,14 @@ stonith2uniform_rc(const char *action, int rc) + { + if (rc == -ENODEV) { + if (safe_str_eq(action, "stop")) { +- rc = PCMK_EXECRA_OK; ++ rc = PCMK_OCF_OK; + } else if (safe_str_eq(action, "start")) { +- rc = PCMK_EXECRA_NOT_INSTALLED; ++ rc = PCMK_OCF_NOT_INSTALLED; + } else { +- rc = PCMK_EXECRA_NOT_RUNNING; ++ rc = PCMK_OCF_NOT_RUNNING; + } + } else if (rc != 0) { +- rc = PCMK_EXECRA_UNKNOWN_ERROR; ++ rc = PCMK_OCF_UNKNOWN_ERROR; + } + return rc; + } +@@ -519,25 +519,25 @@ static int + nagios2uniform_rc(const char *action, int rc) + { + if (rc < 0) { +- return PCMK_EXECRA_UNKNOWN_ERROR; ++ return PCMK_OCF_UNKNOWN_ERROR; + } + + switch (rc) { + case NAGIOS_STATE_OK: +- return PCMK_EXECRA_OK; ++ return PCMK_OCF_OK; + case NAGIOS_INSUFFICIENT_PRIV: +- return PCMK_EXECRA_INSUFFICIENT_PRIV; ++ return PCMK_OCF_INSUFFICIENT_PRIV; + case NAGIOS_NOT_INSTALLED: +- return PCMK_EXECRA_NOT_INSTALLED; ++ return PCMK_OCF_NOT_INSTALLED; + case NAGIOS_STATE_WARNING: + case NAGIOS_STATE_CRITICAL: + case NAGIOS_STATE_UNKNOWN: + case NAGIOS_STATE_DEPENDENT: + default: +- return PCMK_EXECRA_UNKNOWN_ERROR; ++ return PCMK_OCF_UNKNOWN_ERROR; + } + +- return PCMK_EXECRA_UNKNOWN_ERROR; ++ return PCMK_OCF_UNKNOWN_ERROR; + } + #endif + +@@ -605,11 +605,11 @@ action_complete(svc_action_t * action) + #if SUPPORT_NAGIOS + if (rsc && safe_str_eq(rsc->class, "nagios")) { + if (safe_str_eq(cmd->action, "monitor") && +- cmd->interval == 0 && cmd->exec_rc == PCMK_EXECRA_OK) { ++ cmd->interval == 0 && cmd->exec_rc == PCMK_OCF_OK) { + /* Successfully executed --version for the nagios plugin */ +- cmd->exec_rc = PCMK_EXECRA_NOT_RUNNING; ++ cmd->exec_rc = PCMK_OCF_NOT_RUNNING; + +- } else if (safe_str_eq(cmd->action, "start") && cmd->exec_rc != PCMK_EXECRA_OK) { ++ } else if (safe_str_eq(cmd->action, "start") && cmd->exec_rc != PCMK_OCF_OK) { + int time_sum = 0; + int timeout_left = 0; + int delay = cmd->timeout_orig / 10; +@@ -841,7 +841,7 @@ lrmd_rsc_execute_service_lib(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd) + #if SUPPORT_NAGIOS + /* Recurring operations are cancelled anyway for a stop operation */ + if (safe_str_eq(rsc->class, "nagios") && safe_str_eq(cmd->action, "stop")) { +- cmd->exec_rc = PCMK_EXECRA_OK; ++ cmd->exec_rc = PCMK_OCF_OK; + goto exec_done; + } + #endif +diff --git a/lrmd/test.c b/lrmd/test.c +index 15ffd88..2d8571e 100644 +--- a/lrmd/test.c ++++ b/lrmd/test.c +@@ -110,7 +110,7 @@ test_exit(int rc) + lrmd_event_type2str(event->type), \ + event->rsc_id, \ + event->op_type ? event->op_type : "none", \ +- lrmd_event_rc2str(event->rc), \ ++ services_ocf_exitcode_str(event->rc), \ + services_lrm_status_str(event->op_status)); \ + crm_info("%s", event_buf_v0);; + +diff --git a/pengine/native.c b/pengine/native.c +index 37f5211..21ad629 100644 +--- a/pengine/native.c ++++ b/pengine/native.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + /* #define DELETE_THEN_REFRESH 1 // The crmd will remove the resource from the CIB itself, making this redundant */ + #define INFINITY_HACK (INFINITY * -100) +@@ -783,7 +784,7 @@ RecurringOp(resource_t * rsc, action_t * start, node_t * node, + } + + if (rsc->next_role == RSC_ROLE_MASTER) { +- char *running_master = crm_itoa(PCMK_EXECRA_RUNNING_MASTER); ++ char *running_master = crm_itoa(PCMK_OCF_RUNNING_MASTER); + + add_hash_param(mon->meta, XML_ATTR_TE_TARGET_RC, running_master); + free(running_master); +@@ -949,7 +950,7 @@ RecurringOp_Stopped(resource_t * rsc, action_t * start, node_t * node, + + stopped_mon = custom_action(rsc, strdup(key), name, stop_node, is_optional, TRUE, data_set); + +- rc_inactive = crm_itoa(PCMK_EXECRA_NOT_RUNNING); ++ rc_inactive = crm_itoa(PCMK_OCF_NOT_RUNNING); + add_hash_param(stopped_mon->meta, XML_ATTR_TE_TARGET_RC, rc_inactive); + free(rc_inactive); + +@@ -2400,8 +2401,8 @@ native_create_probe(resource_t * rsc, node_t * node, action_t * complete, + static const char *rc_inactive = NULL; + + if (rc_inactive == NULL) { +- rc_inactive = crm_itoa(PCMK_EXECRA_NOT_RUNNING); +- rc_master = crm_itoa(PCMK_EXECRA_RUNNING_MASTER); ++ rc_inactive = crm_itoa(PCMK_OCF_NOT_RUNNING); ++ rc_master = crm_itoa(PCMK_OCF_RUNNING_MASTER); + } + + CRM_CHECK(node != NULL, return FALSE); +diff --git a/tools/crm_mon.c b/tools/crm_mon.c +index 9d68237..7c6e495 100644 +--- a/tools/crm_mon.c ++++ b/tools/crm_mon.c +@@ -950,7 +950,7 @@ print_rsc_history(pe_working_set_t * data_set, node_t * node, xmlNode * rsc_entr + } + } + +- print_as(" rc=%s (%s)\n", op_rc, lrmd_event_rc2str(rc)); ++ print_as(" rc=%s (%s)\n", op_rc, services_ocf_exitcode_str(rc)); + } + + /* no need to free the contents */ +@@ -1405,11 +1405,11 @@ print_status(pe_working_set_t * data_set) + } + + print_as(" %s on %s '%s' (%d): call=%s, status=%s, last-rc-change='%s', queued=%sms, exec=%sms\n", +- op_key ? op_key : id, node, lrmd_event_rc2str(rc), rc, call, services_lrm_status_str(status), ++ op_key ? op_key : id, node, services_ocf_exitcode_str(rc), rc, call, services_lrm_status_str(status), + run_at_s, crm_element_value(xml_op, XML_RSC_OP_T_EXEC), crm_element_value(xml_op, XML_RSC_OP_T_QUEUE)); + } else { + print_as(" %s on %s '%s' (%d): call=%s, status=%s\n", +- op_key ? op_key : id, node, lrmd_event_rc2str(rc), rc, call, services_lrm_status_str(status)); ++ op_key ? op_key : id, node, services_ocf_exitcode_str(rc), rc, call, services_lrm_status_str(status)); + } + } + print_as("\n"); +@@ -2135,10 +2135,10 @@ send_smtp_trap(const char *node, const char *rsc, const char *task, int target_r + "\toperation status: (%d) %s\r\n", status, services_lrm_status_str(status)); + if (status == PCMK_LRM_OP_DONE) { + len += snprintf(crm_mail_body + len, BODY_MAX - len, +- "\tscript returned: (%d) %s\r\n", rc, lrmd_event_rc2str(rc)); ++ "\tscript returned: (%d) %s\r\n", rc, services_ocf_exitcode_str(rc)); + len += snprintf(crm_mail_body + len, BODY_MAX - len, + "\texpected return value: (%d) %s\r\n", target_rc, +- lrmd_event_rc2str(target_rc)); ++ services_ocf_exitcode_str(target_rc)); + } + + auth_client_init(); +@@ -2274,12 +2274,12 @@ handle_rsc_op(xmlNode * rsc_op) + desc = pcmk_strerror(pcmk_ok); + if (status == PCMK_LRM_OP_DONE && target_rc == rc) { + crm_notice("%s of %s on %s completed: %s", task, rsc, node, desc); +- if (rc == PCMK_EXECRA_NOT_RUNNING) { ++ if (rc == PCMK_OCF_NOT_RUNNING) { + notify = FALSE; + } + + } else if (status == PCMK_LRM_OP_DONE) { +- desc = lrmd_event_rc2str(rc); ++ desc = services_ocf_exitcode_str(rc); + crm_warn("%s of %s on %s failed: %s", task, rsc, node, desc); + + } else { diff --git a/SOURCES/bz720543-pcmk-remote_handle_endian_changes_between_client_and_server_and_improve_forward_compatibility.patch b/SOURCES/bz720543-pcmk-remote_handle_endian_changes_between_client_and_server_and_improve_forward_compatibility.patch new file mode 100644 index 0000000..acf5502 --- /dev/null +++ b/SOURCES/bz720543-pcmk-remote_handle_endian_changes_between_client_and_server_and_improve_forward_compatibility.patch @@ -0,0 +1,316 @@ +commit d0cd173e2b9d26a3af6e28746003453500f8f655 +Author: Andrew Beekhof +Date: Thu Oct 31 08:18:11 2013 +1100 + + Fix: remote: Handle endian changes between client and server and improve forward compatibility + + (cherry picked from commit 0c8cb451bb31335e242da328c8a537ab60095a0f) + +diff --git a/configure.ac b/configure.ac +index cfc1b1f..b94c26e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -727,6 +727,7 @@ AC_CHECK_HEADERS(glib.h) + AC_CHECK_HEADERS(grp.h) + AC_CHECK_HEADERS(limits.h) + AC_CHECK_HEADERS(linux/errqueue.h) ++AC_CHECK_HEADERS(linux/swab.h) + AC_CHECK_HEADERS(malloc.h) + AC_CHECK_HEADERS(netdb.h) + AC_CHECK_HEADERS(netinet/in.h) +diff --git a/lib/common/remote.c b/lib/common/remote.c +index c991761..47f0205 100644 +--- a/lib/common/remote.c ++++ b/lib/common/remote.c +@@ -43,9 +43,7 @@ + #ifdef HAVE_GNUTLS_GNUTLS_H + # undef KEYFILE + # include +-#endif + +-#ifdef HAVE_GNUTLS_GNUTLS_H + const int psk_tls_kx_order[] = { + GNUTLS_KX_DHE_PSK, + GNUTLS_KX_PSK, +@@ -58,17 +56,87 @@ const int anon_tls_kx_order[] = { + GNUTLS_KX_RSA, + 0 + }; ++#endif ++ ++/* Swab macros from linux/swab.h */ ++#ifdef HAVE_LINUX_SWAB_H ++# include ++#else ++/* ++ * casts are necessary for constants, because we never know how for sure ++ * how U/UL/ULL map to __u16, __u32, __u64. At least not in a portable way. ++ */ ++#define ___swab16(x) ((__u16)( \ ++ (((__u16)(x) & (__u16)0x00ffU) << 8) | \ ++ (((__u16)(x) & (__u16)0xff00U) >> 8))) ++ ++#define ___swab32(x) ((__u32)( \ ++ (((__u32)(x) & (__u32)0x000000ffUL) << 24) | \ ++ (((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \ ++ (((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \ ++ (((__u32)(x) & (__u32)0xff000000UL) >> 24))) ++ ++#define ___swab64(x) ((__u64)( \ ++ (((__u64)(x) & (__u64)0x00000000000000ffULL) << 56) | \ ++ (((__u64)(x) & (__u64)0x000000000000ff00ULL) << 40) | \ ++ (((__u64)(x) & (__u64)0x0000000000ff0000ULL) << 24) | \ ++ (((__u64)(x) & (__u64)0x00000000ff000000ULL) << 8) | \ ++ (((__u64)(x) & (__u64)0x000000ff00000000ULL) >> 8) | \ ++ (((__u64)(x) & (__u64)0x0000ff0000000000ULL) >> 24) | \ ++ (((__u64)(x) & (__u64)0x00ff000000000000ULL) >> 40) | \ ++ (((__u64)(x) & (__u64)0xff00000000000000ULL) >> 56))) ++#endif ++ ++#define REMOTE_MSG_VERSION 1 ++#define ENDIAN_LOCAL 0xBADADBBD + + struct crm_remote_header_v0 + { ++ uint32_t endian; /* Detect messages from hosts with different endian-ness */ ++ uint32_t version; + uint64_t id; + uint64_t flags; +- uint32_t error; +- uint32_t version; + uint32_t size_total; +- uint32_t payload_uncompressed; ++ uint32_t payload_offset; + uint32_t payload_compressed; +-}; ++ uint32_t payload_uncompressed; ++ ++ /* New fields get added here */ ++ ++} __attribute__ ((packed)); ++ ++static struct crm_remote_header_v0 * ++crm_remote_header(crm_remote_t * remote) ++{ ++ struct crm_remote_header_v0 *header = (struct crm_remote_header_v0 *)remote->buffer; ++ if(remote->buffer_offset < sizeof(struct crm_remote_header_v0)) { ++ return NULL; ++ ++ } else if(header->endian != ENDIAN_LOCAL) { ++ uint32_t endian = __swab32(header->endian); ++ ++ CRM_LOG_ASSERT(endian == ENDIAN_LOCAL); ++ if(endian != ENDIAN_LOCAL) { ++ crm_err("Invalid message detected, endian mismatch: %lx is neither %lx nor the swab'd %lx", ++ ENDIAN_LOCAL, header->endian, endian); ++ return NULL; ++ } ++ ++ header->id = __swab64(header->id); ++ header->flags = __swab64(header->flags); ++ header->endian = __swab32(header->endian); ++ ++ header->version = __swab32(header->version); ++ header->size_total = __swab32(header->size_total); ++ header->payload_offset = __swab32(header->payload_offset); ++ header->payload_compressed = __swab32(header->payload_compressed); ++ header->payload_uncompressed = __swab32(header->payload_uncompressed); ++ } ++ ++ return header; ++} ++ ++#ifdef HAVE_GNUTLS_GNUTLS_H + + int + crm_initiate_client_tls_handshake(crm_remote_t * remote, int timeout_ms) +@@ -253,13 +321,11 @@ crm_remote_sendv(crm_remote_t * remote, struct iovec * iov, int iovs) + return rc; + } + +-#define PCMK_TLS_VERSION 1 +- + int + crm_remote_send(crm_remote_t * remote, xmlNode * msg) + { +- static uint64_t id = 0; + int rc = -1; ++ static uint64_t id = 0; + char *xml_text = dump_xml_unformatted(msg); + + struct iovec iov[2]; +@@ -278,19 +344,25 @@ crm_remote_send(crm_remote_t * remote, xmlNode * msg) + + id++; + header->id = id; +- header->version = PCMK_TLS_VERSION; +- header->size_total = iov[0].iov_len + iov[1].iov_len; ++ header->endian = ENDIAN_LOCAL; ++ header->version = REMOTE_MSG_VERSION; ++ header->payload_offset = iov[0].iov_len; + header->payload_uncompressed = iov[1].iov_len; ++ header->size_total = iov[0].iov_len + iov[1].iov_len; + ++ crm_trace("Sending len[0]=%d, start=%x\n", ++ (int)iov[0].iov_len, *(int*)xml_text); + rc = crm_remote_sendv(remote, iov, 2); + if (rc < 0) { + crm_err("Failed to send remote msg, rc = %d", rc); + } + +- free(xml_text); ++ free(iov[0].iov_base); ++ free(iov[1].iov_base); + return rc; + } + ++ + /*! + * \internal + * \brief handles the recv buffer and parsing out msgs. +@@ -300,34 +372,35 @@ xmlNode * + crm_remote_parse_buffer(crm_remote_t * remote) + { + xmlNode *xml = NULL; +- size_t offset = sizeof(struct crm_remote_header_v0); +- struct crm_remote_header_v0 *header = NULL; ++ struct crm_remote_header_v0 *header = crm_remote_header(remote); + +- if (remote->buffer == NULL) { +- return NULL; +- +- } else if(remote->buffer_offset < sizeof(struct crm_remote_header_v0)) { ++ if (remote->buffer == NULL || header == NULL) { + return NULL; + } + + /* take ownership of the buffer */ + remote->buffer_offset = 0; + +- header = (struct crm_remote_header_v0 *)remote->buffer; + /* Support compression on the receiving end now, in case we ever want to add it later */ + if (header->payload_compressed) { + int rc = 0; + unsigned int size_u = 1 + header->payload_uncompressed; +- char *uncompressed = calloc(1, offset + size_u); ++ char *uncompressed = calloc(1, header->payload_offset + size_u); + + crm_trace("Decompressing message data %d bytes into %d bytes", + header->payload_compressed, size_u); + +- rc = BZ2_bzBuffToBuffDecompress(uncompressed + offset, &size_u, +- remote->buffer + offset, ++ rc = BZ2_bzBuffToBuffDecompress(uncompressed + header->payload_offset, &size_u, ++ remote->buffer + header->payload_offset, + header->payload_compressed, 1, 0); + +- if (rc != BZ_OK) { ++ if (rc != BZ_OK && header->version > REMOTE_MSG_VERSION) { ++ crm_warn("Couldn't decompress v%d message, we only understand v%d", ++ header->version, REMOTE_MSG_VERSION); ++ free(uncompressed); ++ return NULL; ++ ++ } else if (rc != BZ_OK) { + crm_err("Decompression failed: %s (%d)", bz2_strerror(rc), rc); + free(uncompressed); + return NULL; +@@ -335,19 +408,23 @@ crm_remote_parse_buffer(crm_remote_t * remote) + + CRM_ASSERT(size_u == header->payload_uncompressed); + +- memcpy(uncompressed, remote->buffer, offset); /* Preserve the header */ +- header = (struct crm_remote_header_v0 *)uncompressed; ++ memcpy(uncompressed, remote->buffer, header->payload_offset); /* Preserve the header */ ++ remote->buffer_size = header->payload_offset + size_u; + + free(remote->buffer); +- remote->buffer_size = offset + size_u; + remote->buffer = uncompressed; ++ header = crm_remote_header(remote); + } + +- CRM_ASSERT(remote->buffer[sizeof(struct crm_remote_header_v0) + header->payload_uncompressed - 1] == 0); ++ CRM_LOG_ASSERT(remote->buffer[sizeof(struct crm_remote_header_v0) + header->payload_uncompressed - 1] == 0); ++ ++ xml = string2xml(remote->buffer + header->payload_offset); ++ if (xml == NULL && header->version > REMOTE_MSG_VERSION) { ++ crm_warn("Couldn't parse v%d message, we only understand v%d", ++ header->version, REMOTE_MSG_VERSION); + +- xml = string2xml(remote->buffer + offset); +- if (xml == NULL) { +- crm_err("Couldn't parse: '%.120s'", remote->buffer + offset); ++ } else if (xml == NULL) { ++ crm_err("Couldn't parse: '%.120s'", remote->buffer + header->payload_offset); + } + + return xml; +@@ -424,16 +501,16 @@ crm_remote_recv_once(crm_remote_t * remote) + { + int rc = 0; + size_t read_len = sizeof(struct crm_remote_header_v0); ++ struct crm_remote_header_v0 *header = crm_remote_header(remote); + +- if(remote->buffer_offset >= sizeof(struct crm_remote_header_v0)) { +- struct crm_remote_header_v0 *hdr = (struct crm_remote_header_v0 *)remote->buffer; +- +- read_len = hdr->size_total; ++ if(header) { ++ /* Stop at the end of the current message */ ++ read_len = header->size_total; + } + + /* automatically grow the buffer when needed */ + if(remote->buffer_size < read_len) { +- remote->buffer_size = 2 * read_len; ++ remote->buffer_size = 2 * read_len; + crm_trace("Expanding buffer to %u bytes", remote->buffer_size); + + remote->buffer = realloc(remote->buffer, remote->buffer_size + 1); +@@ -488,23 +565,18 @@ crm_remote_recv_once(crm_remote_t * remote) + return -ENOTCONN; + } + +- if(remote->buffer_offset < sizeof(struct crm_remote_header_v0)) { +- crm_trace("Not enough data to fill header: %u < %u bytes", +- remote->buffer_offset, sizeof(struct crm_remote_header_v0)); +- return -EAGAIN; +- +- } else { +- struct crm_remote_header_v0 *hdr = (struct crm_remote_header_v0 *)remote->buffer; +- +- if(remote->buffer_offset < hdr->size_total) { ++ header = crm_remote_header(remote); ++ if(header) { ++ if(remote->buffer_offset < header->size_total) { + crm_trace("Read less than the advertised length: %u < %u bytes", +- remote->buffer_offset, hdr->size_total); +- return -EAGAIN; ++ remote->buffer_offset, header->size_total); ++ } else { ++ crm_trace("Read full message of %u bytes", remote->buffer_offset); ++ return remote->buffer_offset; + } + } + +- crm_trace("Read full message of %u bytes", remote->buffer_offset); +- return remote->buffer_offset; ++ return -EAGAIN; + } + + /*! +diff --git a/lib/lrmd/lrmd_client.c b/lib/lrmd/lrmd_client.c +index d037022..d99d7c8 100644 +--- a/lib/lrmd/lrmd_client.c ++++ b/lib/lrmd/lrmd_client.c +@@ -414,9 +414,6 @@ lrmd_poll(lrmd_t * lrmd, int timeout) + case CRM_CLIENT_TLS: + if (native->pending_notify) { + return 1; +- } else if (native->remote->buffer +- && strstr(native->remote->buffer, REMOTE_MSG_TERMINATOR)) { +- return 1; + } + + return crm_remote_ready(native->remote, 0); diff --git a/SOURCES/bz720543-pcmk-remote_improved_logging_of_recv_errors.patch b/SOURCES/bz720543-pcmk-remote_improved_logging_of_recv_errors.patch new file mode 100644 index 0000000..edb302c --- /dev/null +++ b/SOURCES/bz720543-pcmk-remote_improved_logging_of_recv_errors.patch @@ -0,0 +1,33 @@ +commit 15ebd31f77412e869c2bd7264a53117eb90d1229 +Author: Andrew Beekhof +Date: Tue Oct 15 10:01:05 2013 +1100 + + Log: remote: Improved logging of recv() errors + + (cherry picked from commit 3647b64d004b4377c90963de5ccbec45d1daef72) + +diff --git a/lib/common/remote.c b/lib/common/remote.c +index 297c75a..c991761 100644 +--- a/lib/common/remote.c ++++ b/lib/common/remote.c +@@ -459,7 +459,7 @@ crm_remote_recv_once(crm_remote_t * remote) + } else if (rc == GNUTLS_E_AGAIN) { + rc = -EAGAIN; + } else if (rc < 0) { +- crm_info("TLS receive failed: %s (%d)", gnutls_strerror(rc), rc); ++ crm_debug("TLS receive failed: %s (%d)", gnutls_strerror(rc), rc); + rc = -pcmk_err_generic; + } + #endif +@@ -482,9 +482,9 @@ crm_remote_recv_once(crm_remote_t * remote) + crm_debug("EOF encoutered after %u bytes", remote->buffer_offset); + return -ENOTCONN; + +- } else if (rc <= 0) { ++ } else { + crm_debug("Error receiving message after %u bytes: %s (%d)", +- remote->buffer_offset, gnutls_strerror(rc), rc); ++ remote->buffer_offset, pcmk_strerror(rc), rc); + return -ENOTCONN; + } + diff --git a/SOURCES/bz720543-pcmk-remote_properly_version_the_remote_connection_protocol.patch b/SOURCES/bz720543-pcmk-remote_properly_version_the_remote_connection_protocol.patch new file mode 100644 index 0000000..d562189 --- /dev/null +++ b/SOURCES/bz720543-pcmk-remote_properly_version_the_remote_connection_protocol.patch @@ -0,0 +1,607 @@ +commit 330600b4cafd37f51d109728f9377bc921a6aa7f +Author: Andrew Beekhof +Date: Mon Oct 14 13:50:41 2013 +1100 + + Feature: remote: Properly version the remote connection protocol + + (cherry picked from commit aa024490a023bd0d0d5568f08b2c60b61adb15f5) + +diff --git a/include/crm/common/ipcs.h b/include/crm/common/ipcs.h +index 3e78d51..84249a3 100644 +--- a/include/crm/common/ipcs.h ++++ b/include/crm/common/ipcs.h +@@ -41,14 +41,17 @@ enum client_type { + struct crm_remote_s { + /* Shared */ + char *buffer; ++ size_t buffer_size; ++ size_t buffer_offset; + int auth_timeout; +- bool authenticated; /* CIB-only */ ++ int tcp_socket; + mainloop_io_t *source; + +- char *token; /* CIB Only */ +- +- int tcp_socket; ++ /* CIB-only */ ++ bool authenticated; ++ char *token; + ++ /* TLS only */ + # ifdef HAVE_GNUTLS_GNUTLS_H + gnutls_session_t *tls_session; + bool tls_handshake_complete; +diff --git a/lib/common/remote.c b/lib/common/remote.c +index 8b00f16..297c75a 100644 +--- a/lib/common/remote.c ++++ b/lib/common/remote.c +@@ -34,6 +34,8 @@ + #include + #include + ++#include ++ + #include + #include + #include +@@ -57,6 +59,17 @@ const int anon_tls_kx_order[] = { + 0 + }; + ++struct crm_remote_header_v0 ++{ ++ uint64_t id; ++ uint64_t flags; ++ uint32_t error; ++ uint32_t version; ++ uint32_t size_total; ++ uint32_t payload_uncompressed; ++ uint32_t payload_compressed; ++}; ++ + int + crm_initiate_client_tls_handshake(crm_remote_t * remote, int timeout_ms) + { +@@ -176,97 +189,6 @@ crm_send_tls(gnutls_session_t * session, const char *buf, size_t len) + + return rc < 0 ? rc : total_send; + } +- +-/*! +- * \internal +- * \brief Read bytes off non blocking tls session. +- * +- * \param session - tls session to read +- * \param max_size - max bytes allowed to read for buffer. 0 assumes no limit +- * +- * \note only use with NON-Blocking sockets. Should only be used after polling socket. +- * This function will return once max_size is met, the socket read buffer +- * is empty, or an error is encountered. +- * +- * \retval '\0' terminated buffer on success +- */ +-static char * +-crm_recv_tls(gnutls_session_t * session, size_t max_size, size_t * recv_len, int *disconnected) +-{ +- char *buf = NULL; +- int rc = 0; +- size_t len = 0; +- size_t chunk_size = max_size ? max_size : 1024; +- size_t buf_size = 0; +- size_t read_size = 0; +- +- if (session == NULL) { +- if (disconnected) { +- *disconnected = 1; +- } +- goto done; +- } +- +- buf = calloc(1, chunk_size + 1); +- buf_size = chunk_size; +- +- while (TRUE) { +- read_size = buf_size - len; +- +- /* automatically grow the buffer when needed if max_size is not set. */ +- if (!max_size && (read_size < (chunk_size / 2))) { +- buf_size += chunk_size; +- crm_trace("Grow buffer by %d more bytes. buf is now %d bytes", (int)chunk_size, +- buf_size); +- buf = realloc(buf, buf_size + 1); +- CRM_ASSERT(buf != NULL); +- +- read_size = buf_size - len; +- } +- +- rc = gnutls_record_recv(*session, buf + len, read_size); +- +- if (rc > 0) { +- crm_trace("Got %d more bytes.", rc); +- len += rc; +- /* always null terminate buffer, the +1 to alloc always allows for this. */ +- buf[len] = '\0'; +- } +- if (max_size && (max_size == read_size)) { +- crm_trace("Buffer max read size %d met", max_size); +- goto done; +- } +- +- /* process any errors. */ +- if (rc == GNUTLS_E_INTERRUPTED) { +- crm_trace("EINTR encoutered, retry tls read"); +- } else if (rc == GNUTLS_E_AGAIN) { +- crm_trace("non-blocking, exiting read on rc = %d", rc); +- goto done; +- } else if (rc <= 0) { +- if (rc == 0) { +- crm_debug("EOF encoutered during TLS read"); +- } else { +- crm_debug("Error receiving message: %s (%d)", gnutls_strerror(rc), rc); +- } +- if (disconnected) { +- *disconnected = 1; +- } +- goto done; +- } +- } +- +- done: +- if (recv_len) { +- *recv_len = len; +- } +- if (!len) { +- free(buf); +- buf = NULL; +- } +- return buf; +- +-} + #endif + + static int +@@ -310,141 +232,57 @@ crm_send_plaintext(int sock, const char *buf, size_t len) + + } + +-/*! +- * \internal +- * \brief Read bytes off non blocking socket. +- * +- * \param session - tls session to read +- * \param max_size - max bytes allowed to read for buffer. 0 assumes no limit +- * +- * \note only use with NON-Blocking sockets. Should only be used after polling socket. +- * This function will return once max_size is met, the socket read buffer +- * is empty, or an error is encountered. +- * +- * \retval '\0' terminated buffer on success +- */ +-static char * +-crm_recv_plaintext(int sock, size_t max_size, size_t * recv_len, int *disconnected) +-{ +- char *buf = NULL; +- ssize_t rc = 0; +- ssize_t len = 0; +- ssize_t chunk_size = max_size ? max_size : 1024; +- size_t buf_size = 0; +- size_t read_size = 0; +- +- if (sock <= 0) { +- if (disconnected) { +- *disconnected = 1; +- } +- goto done; +- } +- +- buf = calloc(1, chunk_size + 1); +- buf_size = chunk_size; +- +- while (TRUE) { +- errno = 0; +- read_size = buf_size - len; +- +- /* automatically grow the buffer when needed if max_size is not set. */ +- if (!max_size && (read_size < (chunk_size / 2))) { +- buf_size += chunk_size; +- crm_trace("Grow buffer by %d more bytes. buf is now %d bytes", (int)chunk_size, +- buf_size); +- buf = realloc(buf, buf_size + 1); +- CRM_ASSERT(buf != NULL); +- +- read_size = buf_size - len; +- } +- +- rc = read(sock, buf + len, chunk_size); +- +- if (rc > 0) { +- crm_trace("Got %d more bytes. errno=%d", (int)rc, errno); +- len += rc; +- /* always null terminate buffer, the +1 to alloc always allows for this. */ +- buf[len] = '\0'; +- } +- if (max_size && (max_size == read_size)) { +- crm_trace("Buffer max read size %d met", max_size); +- goto done; +- } +- +- if (rc > 0) { +- continue; +- } else if (rc == 0) { +- if (disconnected) { +- *disconnected = 1; +- } +- crm_trace("EOF encoutered during read"); +- goto done; +- } +- +- /* process errors */ +- if (errno == EINTR) { +- crm_trace("EINTER encoutered, retry socket read."); +- } else if (errno == EAGAIN) { +- crm_trace("non-blocking, exiting read on rc = %d", rc); +- goto done; +- } else if (errno <= 0) { +- if (disconnected) { +- *disconnected = 1; +- } +- crm_debug("Error receiving message: %d", (int)rc); +- goto done; +- } +- } +- +- done: +- if (recv_len) { +- *recv_len = len; +- } +- if (!len) { +- free(buf); +- buf = NULL; +- } +- return buf; +-} +- + static int +-crm_remote_send_raw(crm_remote_t * remote, const char *buf, size_t len) ++crm_remote_sendv(crm_remote_t * remote, struct iovec * iov, int iovs) + { ++ int lpc = 0; + int rc = -ESOCKTNOSUPPORT; + +- if (remote->tcp_socket) { +- rc = crm_send_plaintext(remote->tcp_socket, buf, len); ++ for(; lpc < iovs; lpc++) { ++ if (remote->tcp_socket) { ++ rc = crm_send_plaintext(remote->tcp_socket, iov[lpc].iov_base, iov[lpc].iov_len); + #ifdef HAVE_GNUTLS_GNUTLS_H + +- } else if (remote->tls_session) { +- rc = crm_send_tls(remote->tls_session, buf, len); ++ } else if (remote->tls_session) { ++ rc = crm_send_tls(remote->tls_session, iov[lpc].iov_base, iov[lpc].iov_len); + #endif +- } else { +- crm_err("Unsupported connection type"); ++ } else { ++ crm_err("Unsupported connection type"); ++ } + } + return rc; + } + ++#define PCMK_TLS_VERSION 1 ++ + int + crm_remote_send(crm_remote_t * remote, xmlNode * msg) + { ++ static uint64_t id = 0; + int rc = -1; +- char *xml_text = NULL; +- int len = 0; ++ char *xml_text = dump_xml_unformatted(msg); + +- xml_text = dump_xml_unformatted(msg); +- if (xml_text) { +- len = strlen(xml_text); +- } else { ++ struct iovec iov[2]; ++ struct crm_remote_header_v0 *header = calloc(1, sizeof(struct crm_remote_header_v0)); ++ ++ if (xml_text == NULL) { + crm_err("Invalid XML, can not send msg"); + return -1; + } + +- rc = crm_remote_send_raw(remote, xml_text, len); +- if (rc >= 0) { +- rc = crm_remote_send_raw(remote, REMOTE_MSG_TERMINATOR, strlen(REMOTE_MSG_TERMINATOR)); +- } ++ iov[0].iov_base = header; ++ iov[0].iov_len = sizeof(struct crm_remote_header_v0); ++ ++ iov[1].iov_base = xml_text; ++ iov[1].iov_len = 1 + strlen(xml_text); + ++ id++; ++ header->id = id; ++ header->version = PCMK_TLS_VERSION; ++ header->size_total = iov[0].iov_len + iov[1].iov_len; ++ header->payload_uncompressed = iov[1].iov_len; ++ ++ rc = crm_remote_sendv(remote, iov, 2); + if (rc < 0) { + crm_err("Failed to send remote msg, rc = %d", rc); + } +@@ -461,44 +299,55 @@ crm_remote_send(crm_remote_t * remote, xmlNode * msg) + xmlNode * + crm_remote_parse_buffer(crm_remote_t * remote) + { +- char *buf = NULL; +- char *start = NULL; +- char *end = NULL; + xmlNode *xml = NULL; ++ size_t offset = sizeof(struct crm_remote_header_v0); ++ struct crm_remote_header_v0 *header = NULL; + + if (remote->buffer == NULL) { + return NULL; ++ ++ } else if(remote->buffer_offset < sizeof(struct crm_remote_header_v0)) { ++ return NULL; + } + + /* take ownership of the buffer */ +- buf = remote->buffer; +- remote->buffer = NULL; +- +- /* MSGS are separated by a '\r\n\r\n'. Split a message off the buffer and return it. */ +- start = buf; +- end = strstr(start, REMOTE_MSG_TERMINATOR); ++ remote->buffer_offset = 0; ++ ++ header = (struct crm_remote_header_v0 *)remote->buffer; ++ /* Support compression on the receiving end now, in case we ever want to add it later */ ++ if (header->payload_compressed) { ++ int rc = 0; ++ unsigned int size_u = 1 + header->payload_uncompressed; ++ char *uncompressed = calloc(1, offset + size_u); ++ ++ crm_trace("Decompressing message data %d bytes into %d bytes", ++ header->payload_compressed, size_u); ++ ++ rc = BZ2_bzBuffToBuffDecompress(uncompressed + offset, &size_u, ++ remote->buffer + offset, ++ header->payload_compressed, 1, 0); ++ ++ if (rc != BZ_OK) { ++ crm_err("Decompression failed: %s (%d)", bz2_strerror(rc), rc); ++ free(uncompressed); ++ return NULL; ++ } + +- while (!xml && end) { ++ CRM_ASSERT(size_u == header->payload_uncompressed); + +- /* grab the message */ +- end[0] = '\0'; +- end += strlen(REMOTE_MSG_TERMINATOR); ++ memcpy(uncompressed, remote->buffer, offset); /* Preserve the header */ ++ header = (struct crm_remote_header_v0 *)uncompressed; + +- xml = string2xml(start); +- if (xml == NULL) { +- crm_err("Couldn't parse: '%.120s'", start); +- } +- start = end; +- end = strstr(start, REMOTE_MSG_TERMINATOR); ++ free(remote->buffer); ++ remote->buffer_size = offset + size_u; ++ remote->buffer = uncompressed; + } + +- if (xml && start) { +- /* we have msgs left over, save it until next time */ +- remote->buffer = strdup(start); +- free(buf); +- } else if (!xml) { +- /* no msg present */ +- remote->buffer = buf; ++ CRM_ASSERT(remote->buffer[sizeof(struct crm_remote_header_v0) + header->payload_uncompressed - 1] == 0); ++ ++ xml = string2xml(remote->buffer + offset); ++ if (xml == NULL) { ++ crm_err("Couldn't parse: '%.120s'", remote->buffer + offset); + } + + return xml; +@@ -559,6 +408,105 @@ crm_remote_ready(crm_remote_t * remote, int timeout /* ms */ ) + return rc; + } + ++ ++/*! ++ * \internal ++ * \brief Read bytes off non blocking remote connection. ++ * ++ * \note only use with NON-Blocking sockets. Should only be used after polling socket. ++ * This function will return once max_size is met, the socket read buffer ++ * is empty, or an error is encountered. ++ * ++ * \retval number of bytes received ++ */ ++static size_t ++crm_remote_recv_once(crm_remote_t * remote) ++{ ++ int rc = 0; ++ size_t read_len = sizeof(struct crm_remote_header_v0); ++ ++ if(remote->buffer_offset >= sizeof(struct crm_remote_header_v0)) { ++ struct crm_remote_header_v0 *hdr = (struct crm_remote_header_v0 *)remote->buffer; ++ ++ read_len = hdr->size_total; ++ } ++ ++ /* automatically grow the buffer when needed */ ++ if(remote->buffer_size < read_len) { ++ remote->buffer_size = 2 * read_len; ++ crm_trace("Expanding buffer to %u bytes", remote->buffer_size); ++ ++ remote->buffer = realloc(remote->buffer, remote->buffer_size + 1); ++ CRM_ASSERT(remote->buffer != NULL); ++ } ++ ++ if (remote->tcp_socket) { ++ errno = 0; ++ rc = read(remote->tcp_socket, ++ remote->buffer + remote->buffer_offset, ++ remote->buffer_size - remote->buffer_offset); ++ if(rc < 0) { ++ rc = -errno; ++ } ++ ++#ifdef HAVE_GNUTLS_GNUTLS_H ++ } else if (remote->tls_session) { ++ rc = gnutls_record_recv(*(remote->tls_session), ++ remote->buffer + remote->buffer_offset, ++ remote->buffer_size - remote->buffer_offset); ++ if (rc == GNUTLS_E_INTERRUPTED) { ++ rc = -EINTR; ++ } else if (rc == GNUTLS_E_AGAIN) { ++ rc = -EAGAIN; ++ } else if (rc < 0) { ++ crm_info("TLS receive failed: %s (%d)", gnutls_strerror(rc), rc); ++ rc = -pcmk_err_generic; ++ } ++#endif ++ } else { ++ crm_err("Unsupported connection type"); ++ return -ESOCKTNOSUPPORT; ++ } ++ ++ /* process any errors. */ ++ if (rc > 0) { ++ remote->buffer_offset += rc; ++ /* always null terminate buffer, the +1 to alloc always allows for this. */ ++ remote->buffer[remote->buffer_offset] = '\0'; ++ crm_trace("Received %u more bytes, %u total", rc, remote->buffer_offset); ++ ++ } else if (rc == -EINTR || rc == -EAGAIN) { ++ crm_trace("non-blocking, exiting read: %s (%d)", pcmk_strerror(rc), rc); ++ ++ } else if (rc == 0) { ++ crm_debug("EOF encoutered after %u bytes", remote->buffer_offset); ++ return -ENOTCONN; ++ ++ } else if (rc <= 0) { ++ crm_debug("Error receiving message after %u bytes: %s (%d)", ++ remote->buffer_offset, gnutls_strerror(rc), rc); ++ return -ENOTCONN; ++ } ++ ++ if(remote->buffer_offset < sizeof(struct crm_remote_header_v0)) { ++ crm_trace("Not enough data to fill header: %u < %u bytes", ++ remote->buffer_offset, sizeof(struct crm_remote_header_v0)); ++ return -EAGAIN; ++ ++ } else { ++ struct crm_remote_header_v0 *hdr = (struct crm_remote_header_v0 *)remote->buffer; ++ ++ if(remote->buffer_offset < hdr->size_total) { ++ crm_trace("Read less than the advertised length: %u < %u bytes", ++ remote->buffer_offset, hdr->size_total); ++ return -EAGAIN; ++ } ++ } ++ ++ crm_trace("Read full message of %u bytes", remote->buffer_offset); ++ return remote->buffer_offset; ++} ++ + /*! + * \internal + * \brief Read data off the socket until at least one full message is present or timeout occures. +@@ -569,10 +517,8 @@ crm_remote_ready(crm_remote_t * remote, int timeout /* ms */ ) + gboolean + crm_remote_recv(crm_remote_t * remote, int total_timeout /*ms */ , int *disconnected) + { +- int ret; +- size_t request_len = 0; ++ int rc; + time_t start = time(NULL); +- char *raw_request = NULL; + int remaining_timeout = 0; + + if (total_timeout == 0) { +@@ -588,57 +534,30 @@ crm_remote_recv(crm_remote_t * remote, int total_timeout /*ms */ , int *disconne + /* read some more off the tls buffer if we still have time left. */ + crm_trace("waiting to receive remote msg, starting timeout %d, remaining_timeout %d", + total_timeout, remaining_timeout); +- ret = crm_remote_ready(remote, remaining_timeout); +- raw_request = NULL; ++ rc = crm_remote_ready(remote, remaining_timeout); + +- if (ret == 0) { ++ if (rc == 0) { + crm_err("poll timed out (%d ms) while waiting to receive msg", remaining_timeout); + return FALSE; + +- } else if (ret < 0) { +- if (errno != EINTR) { +- crm_debug("poll returned error while waiting for msg, rc: %d, errno: %d", ret, +- errno); +- *disconnected = 1; +- return FALSE; +- } +- crm_debug("poll EINTR encountered during poll, retrying"); +- +- } else if (remote->tcp_socket) { +- raw_request = crm_recv_plaintext(remote->tcp_socket, 0, &request_len, disconnected); ++ } else if(rc < 0) { ++ crm_debug("poll() failed: %s (%d)", pcmk_strerror(rc), rc); + +-#ifdef HAVE_GNUTLS_GNUTLS_H +- } else if (remote->tls_session) { +- raw_request = crm_recv_tls(remote->tls_session, 0, &request_len, disconnected); +-#endif + } else { +- crm_err("Unsupported connection type"); +- } +- +- remaining_timeout = remaining_timeout - ((time(NULL) - start) * 1000); +- +- if (!raw_request) { +- crm_debug("Empty msg received after poll"); +- continue; ++ rc = crm_remote_recv_once(remote); ++ if(rc > 0) { ++ return TRUE; ++ } else if (rc < 0) { ++ crm_debug("recv() failed: %s (%d)", pcmk_strerror(rc), rc); ++ } + } + +- if (remote->buffer) { +- int old_len = strlen(remote->buffer); +- +- crm_trace("Expanding recv buffer from %d to %d", old_len, old_len + request_len); +- +- remote->buffer = realloc(remote->buffer, old_len + request_len + 1); +- memcpy(remote->buffer + old_len, raw_request, request_len); +- *(remote->buffer + old_len + request_len) = '\0'; +- free(raw_request); +- +- } else { +- remote->buffer = raw_request; ++ if(rc == -ENOTCONN) { ++ *disconnected = 1; ++ return FALSE; + } + +- if (strstr(remote->buffer, REMOTE_MSG_TERMINATOR)) { +- return TRUE; +- } ++ remaining_timeout = remaining_timeout - ((time(NULL) - start) * 1000); + } + + return FALSE; diff --git a/SOURCES/bz902407-pcmk-crm_resource_handle_ban_for_master_slave_resources_as_advertised.patch b/SOURCES/bz902407-pcmk-crm_resource_handle_ban_for_master_slave_resources_as_advertised.patch new file mode 100644 index 0000000..346f593 --- /dev/null +++ b/SOURCES/bz902407-pcmk-crm_resource_handle_ban_for_master_slave_resources_as_advertised.patch @@ -0,0 +1,41 @@ +commit b15fd2bd176211fb9ae6b158e48f1ee07c21ecee +Author: Andrew Beekhof +Date: Fri Aug 23 13:29:00 2013 +1000 + + Bug rhbz#902407 - crm_resource: Handle --ban for master/slave resources as advertised + +diff --git a/tools/crm_resource.c b/tools/crm_resource.c +index e4d2215..ea23698 100644 +--- a/tools/crm_resource.c ++++ b/tools/crm_resource.c +@@ -905,16 +905,19 @@ ban_resource(const char *rsc_id, const char *host, GListPtr allnodes, cib_t * ci + CMD_ERR("WARNING: Creating rsc_location constraint '%s'" + " with a score of -INFINITY for resource %s" + " on %s.\n", ID(location), rsc_id, host); +- CMD_ERR("\tThis will prevent %s from running" ++ CMD_ERR("\tThis will prevent %s from %s" + " on %s until the constraint is removed using" + " the 'crm_resource --clear' command or manually" +- " with cibadmin\n", rsc_id, host); ++ " with cibadmin\n", rsc_id, scope_master?"being promoted":"running", host); + CMD_ERR("\tThis will be the case even if %s is" + " the last node in the cluster\n", host); + CMD_ERR("\tThis message can be disabled with --quiet\n"); + } + + crm_xml_add(location, XML_COLOC_ATTR_SOURCE, rsc_id); ++ if(scope_master) { ++ crm_xml_add(location, XML_RULE_ATTR_ROLE, RSC_ROLE_MASTER_S); ++ } + + if (later_s == NULL) { + /* Short form */ +@@ -2003,7 +2006,7 @@ main(int argc, char **argv) + node_t *current = rsc->running_on->data; + rc = ban_resource(rsc_id, current->details->uname, NULL, cib_conn); + +- } else if(scope_master && rsc->variant == pe_master) { ++ } else if(rsc->variant == pe_master) { + int count = 0; + GListPtr iter = NULL; + node_t *current = NULL; diff --git a/SOURCES/bz902407-pcmk-crm_resource_observe_master_modifier_for_move.patch b/SOURCES/bz902407-pcmk-crm_resource_observe_master_modifier_for_move.patch new file mode 100644 index 0000000..3781c22 --- /dev/null +++ b/SOURCES/bz902407-pcmk-crm_resource_observe_master_modifier_for_move.patch @@ -0,0 +1,180 @@ +commit 04c1373e2758744d53e83f8013c84c3517a028ce +Author: Andrew Beekhof +Date: Tue Oct 1 20:47:07 2013 +1000 + + Fix: crm_resource: Observe --master modifier for --move + + Also ensure role=Master is overwritten for --ban + Do something sane for --move when called for a clone + + (cherry picked from commit f36c32b47b58254caf580e7fe56e6b5a8eef7639) + +diff --git a/tools/crm_resource.c b/tools/crm_resource.c +index 6ded13d..44d96b0 100644 +--- a/tools/crm_resource.c ++++ b/tools/crm_resource.c +@@ -917,6 +917,8 @@ ban_resource(const char *rsc_id, const char *host, GListPtr allnodes, cib_t * ci + crm_xml_add(location, XML_COLOC_ATTR_SOURCE, rsc_id); + if(scope_master) { + crm_xml_add(location, XML_RULE_ATTR_ROLE, RSC_ROLE_MASTER_S); ++ } else { ++ crm_xml_add(location, XML_RULE_ATTR_ROLE, RSC_ROLE_STARTED_S); + } + + if (later_s == NULL) { +@@ -982,6 +984,11 @@ prefer_resource(const char *rsc_id, const char *host, cib_t * cib_conn) + free(id); + + crm_xml_add(location, XML_COLOC_ATTR_SOURCE, rsc_id); ++ if(scope_master) { ++ crm_xml_add(location, XML_RULE_ATTR_ROLE, RSC_ROLE_MASTER_S); ++ } else { ++ crm_xml_add(location, XML_RULE_ATTR_ROLE, RSC_ROLE_STARTED_S); ++ } + + if (later_s == NULL) { + /* Short form */ +@@ -1924,8 +1931,11 @@ main(int argc, char **argv) + } + + } else if (rsc_cmd == 'M' && host_uname) { +- resource_t *rsc = pe_find_resource(data_set.resources, rsc_id); ++ ++ int count = 0; ++ node_t *current = NULL; + node_t *dest = pe_find_node(data_set.nodes, host_uname); ++ resource_t *rsc = pe_find_resource(data_set.resources, rsc_id); + + rc = -EINVAL; + +@@ -1934,23 +1944,40 @@ main(int argc, char **argv) + rc = -ENXIO; + goto bail; + +- } else if(rsc->variant == pe_clone) { +- CMD_ERR("Resource '%s' not moved: moving a clone makes no sense\n", rsc_id); +- goto bail; +- +- } else if (rsc->variant < pe_clone && g_list_length(rsc->running_on) > 1) { +- CMD_ERR("Resource '%s' not moved: active on multiple nodes\n", rsc_id); +- goto bail; +- +- } else if (rsc->variant < pe_clone && scope_master) { ++ } else if (scope_master && rsc->variant < pe_master) { + resource_t *p = uber_parent(rsc); + if(p->variant == pe_master) { +- CMD_ERR("Resource '%s' not moved: The --master option is not a valid for %s resources." +- " Did you mean '%s'?\n", rsc_id, get_resource_typename(rsc->variant), p->id); ++ CMD_ERR("Using parent '%s' for --move command instead of '%s'.\n", rsc->id, rsc_id); ++ rsc_id = p->id; ++ rsc = p; ++ + } else { +- CMD_ERR("Resource '%s' not moved: The --master option is not a valid for %s resources.\n", +- rsc_id, get_resource_typename(rsc->variant)); ++ CMD_ERR("Ignoring '--master' option: not valid for %s resources.\n", ++ get_resource_typename(rsc->variant)); ++ scope_master = FALSE; + } ++ } ++ ++ if(rsc->variant == pe_master) { ++ GListPtr iter = NULL; ++ ++ for(iter = rsc->children; iter; iter = iter->next) { ++ resource_t *child = (resource_t *)iter->data; ++ if(child->role == RSC_ROLE_MASTER) { ++ rsc = child; ++ count++; ++ } ++ } ++ ++ if(scope_master == FALSE && count == 0) { ++ count = g_list_length(rsc->running_on); ++ } ++ ++ } else if (rsc->variant > pe_group) { ++ count = g_list_length(rsc->running_on); ++ ++ } else if (g_list_length(rsc->running_on) > 1) { ++ CMD_ERR("Resource '%s' not moved: active on multiple nodes\n", rsc_id); + goto bail; + } + +@@ -1961,13 +1988,19 @@ main(int argc, char **argv) + } + + if(g_list_length(rsc->running_on) == 1) { +- node_t *current = rsc->running_on->data; ++ current = rsc->running_on->data; ++ } + +- if (safe_str_eq(current->details->uname, dest->details->uname)) { +- CMD_ERR("Error performing operation: %s is already active on %s\n", rsc_id, dest->details->uname); +- goto bail; +- } +- /* } else if (rsc->variant == pe_master) { Find the master and ban it */ ++ if(current == NULL) { ++ /* Nothing to check */ ++ ++ } else if(scope_master && rsc->role != RSC_ROLE_MASTER) { ++ crm_trace("%s is already active on %s but not in correct state", rsc_id, dest->details->uname); ++ ++ } else if (safe_str_eq(current->details->uname, dest->details->uname)) { ++ CMD_ERR("Error performing operation: %s is already %s on %s\n", ++ rsc_id, scope_master?"promoted":"active", dest->details->uname); ++ goto bail; + } + + /* Clear any previous constraints for 'dest' */ +@@ -1976,11 +2009,23 @@ main(int argc, char **argv) + /* Record an explicit preference for 'dest' */ + rc = prefer_resource(rsc_id, dest->details->uname, cib_conn); + +- if(do_force && g_list_length(rsc->running_on) == 1) { +- node_t *current = rsc->running_on->data; ++ crm_trace("%s%s now prefers node %s%s", ++ rsc->id, scope_master?" (master)":"", dest->details->uname, do_force?"(forced)":""); + +- /* Ban the original location */ +- ban_resource(rsc_id, current->details->uname, NULL, cib_conn); ++ if(do_force) { ++ /* Ban the original location if possible */ ++ if(current) { ++ ban_resource(rsc_id, current->details->uname, NULL, cib_conn); ++ ++ } else if(count > 1) { ++ CMD_ERR("Resource '%s' is currently %s in %d locations. One may now move one to %s\n", ++ rsc_id, scope_master?"promoted":"active", count, dest->details->uname); ++ CMD_ERR("You can prevent '%s' from being %s at a specific location with:" ++ " --ban %s--host \n", rsc_id, scope_master?"promoted":"active", scope_master?"--master ":""); ++ ++ } else { ++ crm_trace("Not banning %s from it's current location: not active", rsc_id); ++ } + } + + } else if (rsc_cmd == 'B' && host_uname) { +@@ -2034,7 +2079,8 @@ main(int argc, char **argv) + rc = ban_resource(rsc_id, current->details->uname, NULL, cib_conn); + + } else { +- CMD_ERR("Resource '%s' not moved: currently promoted in %d locations.\n", rsc_id, count); ++ CMD_ERR("Resource '%s' not moved: active in %d locations (promoted in %d).\n", rsc_id, g_list_length(rsc->running_on), count); ++ CMD_ERR("You can prevent '%s' from running on a specific location with: --ban --host \n", rsc_id); + CMD_ERR("You can prevent '%s' from being promoted at a specific location with:" + " --ban --master --host \n", rsc_id); + } +@@ -2042,12 +2088,6 @@ main(int argc, char **argv) + } else { + CMD_ERR("Resource '%s' not moved: active in %d locations.\n", rsc_id, g_list_length(rsc->running_on)); + CMD_ERR("You can prevent '%s' from running on a specific location with: --ban --host \n", rsc_id); +- +- if(rsc->variant == pe_master && g_list_length(rsc->running_on) > 0) { +- CMD_ERR("You can prevent '%s' from being promoted at its current location with: --ban --master\n", rsc_id); +- CMD_ERR("You can prevent '%s' from being promoted at a specific location with:" +- " --ban --master --host \n", rsc_id); +- } + } + + } else if (rsc_cmd == 'G') { diff --git a/SOURCES/bz902407-pcmk-location_constraints_are_allowed_to_specify_a_role.patch b/SOURCES/bz902407-pcmk-location_constraints_are_allowed_to_specify_a_role.patch new file mode 100644 index 0000000..c06bfda --- /dev/null +++ b/SOURCES/bz902407-pcmk-location_constraints_are_allowed_to_specify_a_role.patch @@ -0,0 +1,45 @@ +commit 1bf33b4b3954cc7e8958d90c0dd02c1a108871d6 +Author: Andrew Beekhof +Date: Fri Aug 23 13:27:48 2013 +1000 + + Fix: xml: Location constraints are allowed to specify a role + +diff --git a/xml/constraints-1.1.rng b/xml/constraints-1.1.rng +index e224600..425b54c 100644 +--- a/xml/constraints-1.1.rng ++++ b/xml/constraints-1.1.rng +@@ -20,13 +20,13 @@ + + + ++ ++ ++ ++ ++ + + +- +- +- +- +- + + + +diff --git a/xml/constraints-1.2.rng b/xml/constraints-1.2.rng +index f3af61f..221140c 100644 +--- a/xml/constraints-1.2.rng ++++ b/xml/constraints-1.2.rng +@@ -20,6 +20,11 @@ + + + ++ ++ ++ ++ ++ + + + diff --git a/SOURCES/bz902407-pcmk-pe_location_constraints_with_role_started_should_prevent_masters_from_running_at_all.patch b/SOURCES/bz902407-pcmk-pe_location_constraints_with_role_started_should_prevent_masters_from_running_at_all.patch new file mode 100644 index 0000000..6cb28fa --- /dev/null +++ b/SOURCES/bz902407-pcmk-pe_location_constraints_with_role_started_should_prevent_masters_from_running_at_all.patch @@ -0,0 +1,37 @@ +commit fbb822a3f83a180380d16be59d8eb9e38abbdce3 +Author: Andrew Beekhof +Date: Tue Oct 1 15:20:25 2013 +1000 + + Fix: PE: Location constraints with role=Started should prevent masters from running at all + + (cherry picked from commit b4c34e06f5f355f5cf6ee721b4bff1ce455e114e) + +diff --git a/pengine/constraints.c b/pengine/constraints.c +index 9fc52d9..594d630 100644 +--- a/pengine/constraints.c ++++ b/pengine/constraints.c +@@ -402,13 +402,17 @@ unpack_rsc_location(xmlNode * xml_obj, pe_working_set_t * data_set) + return FALSE; + + } else { +- location->role_filter = text2role(role); +- if (location->role_filter == RSC_ROLE_SLAVE) { +- /* Fold slave back into Started for simplicity +- * At the point Slave location constraints are evaluated, +- * all resources are still either stopped or started +- */ +- location->role_filter = RSC_ROLE_STARTED; ++ enum rsc_role_e r = text2role(role); ++ switch(r) { ++ case RSC_ROLE_UNKNOWN: ++ case RSC_ROLE_STARTED: ++ case RSC_ROLE_SLAVE: ++ /* Applies to all */ ++ location->role_filter = RSC_ROLE_UNKNOWN; ++ break; ++ default: ++ location->role_filter = r; ++ break; + } + } + } diff --git a/SOURCES/bz902407-pcmk-provide_a_meaningful_error_if_master_is_used_for_primitives_and_groups.patch b/SOURCES/bz902407-pcmk-provide_a_meaningful_error_if_master_is_used_for_primitives_and_groups.patch new file mode 100644 index 0000000..4c79da2 --- /dev/null +++ b/SOURCES/bz902407-pcmk-provide_a_meaningful_error_if_master_is_used_for_primitives_and_groups.patch @@ -0,0 +1,28 @@ +commit 4cc5bf3a67cae9b17c49cd73d840b5388500ad13 +Author: Andrew Beekhof +Date: Tue Sep 17 14:06:41 2013 +1000 + + Fix: crm_resource: Provide a meaningful error if --master is used for primitives and groups + +diff --git a/tools/crm_resource.c b/tools/crm_resource.c +index 69470d7..b63b9ae 100644 +--- a/tools/crm_resource.c ++++ b/tools/crm_resource.c +@@ -1942,6 +1942,17 @@ main(int argc, char **argv) + } else if (rsc->variant < pe_clone && g_list_length(rsc->running_on) > 1) { + CMD_ERR("Resource '%s' not moved: active on multiple nodes\n", rsc_id); + goto bail; ++ ++ } else if (rsc->variant < pe_clone && scope_master) { ++ resource_t *p = uber_parent(rsc); ++ if(p->variant == pe_master) { ++ CMD_ERR("Resource '%s' not moved: The --master option is not a valid for %s resources." ++ " Did you mean '%s'?\n", rsc_id, get_resource_typename(rsc->variant), p->id); ++ } else { ++ CMD_ERR("Resource '%s' not moved: The --master option is not a valid for %s resources.\n", ++ rsc_id, get_resource_typename(rsc->variant)); ++ } ++ goto bail; + } + + if(dest == NULL) { diff --git a/SOURCES/bz996576-pcmk-crm_report_correctly_redirect_error_message_to_dev_null.patch b/SOURCES/bz996576-pcmk-crm_report_correctly_redirect_error_message_to_dev_null.patch new file mode 100644 index 0000000..86a9f9e --- /dev/null +++ b/SOURCES/bz996576-pcmk-crm_report_correctly_redirect_error_message_to_dev_null.patch @@ -0,0 +1,29 @@ +commit e3410ecf4c13dba52d11981b371f4f9c81b369be +Author: Andrew Beekhof +Date: Wed Sep 25 12:44:58 2013 +1000 + + Fix: crm_report: Correctly redirect error message to /dev/null + + (cherry picked from commit 2a977cb7a338fdb1e845c5403485c606b8c9eb2f) + + Conflicts: + tools/report.collector + +diff --git a/tools/report.collector b/tools/report.collector +index 00bd319..1667364 100644 +--- a/tools/report.collector ++++ b/tools/report.collector +@@ -711,6 +711,13 @@ for l in $logfiles $EXTRA_LOGS; do + cat $b | grep -f $pattfile >> $ANALYSIS_F + done + ++which journalctl > /dev/null 2>&1 ++if [ $? = 0 ]; then ++ log "Including segment [$LOG_START-$LOG_END] from journald" ++ journalctl --since "$start" --until "$end" > journal.log ++ cat journal.log | grep -f $pattfile >> $ANALYSIS_F ++fi ++ + rm -f $pattfile + trap "" 0 + diff --git a/SOURCES/bz996576-pcmk-observe_pcmk_host_list_during_automatic_unfencing.patch b/SOURCES/bz996576-pcmk-observe_pcmk_host_list_during_automatic_unfencing.patch new file mode 100644 index 0000000..5f58a19 --- /dev/null +++ b/SOURCES/bz996576-pcmk-observe_pcmk_host_list_during_automatic_unfencing.patch @@ -0,0 +1,66 @@ +commit dde47a0eca301ca97dbe03fc9a1f6328e3b127a3 +Author: Andrew Beekhof +Date: Mon Sep 23 09:23:45 2013 +1000 + + Fix: Fencing: Observe pcmk_host_list during automatic unfencing + +diff --git a/fencing/commands.c b/fencing/commands.c +index 73a7fc1..7d04952 100644 +--- a/fencing/commands.c ++++ b/fencing/commands.c +@@ -665,7 +665,7 @@ schedule_internal_command(const char *origin, + schedule_stonith_command(cmd, device); + } + +-static gboolean ++gboolean + string_in_list(GListPtr list, const char *item) + { + int lpc = 0; +diff --git a/fencing/internal.h b/fencing/internal.h +index 9a8b096..11a8c58 100644 +--- a/fencing/internal.h ++++ b/fencing/internal.h +@@ -164,6 +164,8 @@ int stonith_manual_ack(xmlNode * msg, remote_fencing_op_t * op); + + void unfence_cb(GPid pid, int rc, const char *output, gpointer user_data); + ++gboolean string_in_list(GListPtr list, const char *item); ++ + void + schedule_internal_command(const char *origin, + stonith_device_t * device, +diff --git a/fencing/main.c b/fencing/main.c +index 6401f2f..a90c43b 100644 +--- a/fencing/main.c ++++ b/fencing/main.c +@@ -669,12 +669,24 @@ static void cib_device_update(resource_t *rsc, pe_working_set_t *data_set) + if(have_fence_scsi == FALSE && safe_str_eq(agent, "fence_scsi")) { + stonith_device_t *device = g_hash_table_lookup(device_list, rsc->id); + +- if(device) { +- have_fence_scsi = TRUE; +- crm_notice("Unfencing ourselves with %s (%s)", agent, device->id); +- schedule_internal_command(__FUNCTION__, device, "on", stonith_our_uname, 0, NULL, unfence_cb); ++ if(stonith_our_uname == NULL) { ++ crm_trace("Cannot unfence ourselves: no local host name"); ++ ++ } else if(device == NULL) { ++ crm_err("Cannot unfence ourselves: no such device '%s'", rsc->id); ++ + } else { +- crm_err("Device %s does not exist", rsc->id); ++ const char *alias = g_hash_table_lookup(device->aliases, stonith_our_uname); ++ ++ if (!alias) { ++ alias = stonith_our_uname; ++ } ++ ++ if (device->targets && string_in_list(device->targets, alias)) { ++ have_fence_scsi = TRUE; ++ crm_notice("Unfencing ourselves with %s (%s)", agent, device->id); ++ schedule_internal_command(__FUNCTION__, device, "on", stonith_our_uname, 0, NULL, unfence_cb); ++ } + } + } + diff --git a/SOURCES/bz996850-pcmk-log_crmd_supply_arguments_in_the_correct_order.patch b/SOURCES/bz996850-pcmk-log_crmd_supply_arguments_in_the_correct_order.patch new file mode 100644 index 0000000..93f07e0 --- /dev/null +++ b/SOURCES/bz996850-pcmk-log_crmd_supply_arguments_in_the_correct_order.patch @@ -0,0 +1,21 @@ +commit d5875e38412739155a6e3480cd5797d86fdda301 +Author: Andrew Beekhof +Date: Mon Sep 23 15:37:18 2013 +1000 + + Log: crmd: Supply arguments in the correct order + + (cherry picked from commit 6cbe8c46fa82ab908d8b0731ad4995cc19b34cc4) + +diff --git a/crmd/lrm.c b/crmd/lrm.c +index 2e17488..0254a9f 100644 +--- a/crmd/lrm.c ++++ b/crmd/lrm.c +@@ -353,7 +353,7 @@ lrm_state_verify_stopped(lrm_state_t * lrm_state, enum crmd_fsa_state cur_state, + lrm_state->pending_ops, stop_recurring_actions, lrm_state); + + crm_notice("Stopped %u recurring operations at %s (%u ops remaining)", +- g_hash_table_size(lrm_state->pending_ops), when, removed); ++ removed, when, g_hash_table_size(lrm_state->pending_ops)); + } + + if (lrm_state->pending_ops) { diff --git a/SOURCES/pacemaker-add-RemoteLXC-cts-test.patch b/SOURCES/pacemaker-add-RemoteLXC-cts-test.patch new file mode 100644 index 0000000..e693975 --- /dev/null +++ b/SOURCES/pacemaker-add-RemoteLXC-cts-test.patch @@ -0,0 +1,581 @@ +commit c8136d5f0abe785223f4ea809073d6566aa36b58 +Author: David Vossel +Date: Wed Sep 25 18:14:13 2013 -0400 + + RemoteLXC port + +diff --git a/configure.ac b/configure.ac +index 6c80891..cfc1b1f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1084,6 +1084,10 @@ CRM_CONFIG_DIR="${localstatedir}/lib/pacemaker/cib" + AC_DEFINE_UNQUOTED(CRM_CONFIG_DIR,"$CRM_CONFIG_DIR", Where to keep configuration files) + AC_SUBST(CRM_CONFIG_DIR) + ++CRM_CONFIG_CTS="${localstatedir}/lib/pacemaker/cts" ++AC_DEFINE_UNQUOTED(CRM_CONFIG_CTS,"$CRM_CONFIG_CTS", Where to keep cts stateful data) ++AC_SUBST(CRM_CONFIG_CTS) ++ + CRM_LEGACY_CONFIG_DIR="${localstatedir}/lib/heartbeat/crm" + AC_DEFINE_UNQUOTED(CRM_LEGACY_CONFIG_DIR,"$CRM_LEGACY_CONFIG_DIR", Where Pacemaker used to keep configuration files) + AC_SUBST(CRM_LEGACY_CONFIG_DIR) +@@ -1790,7 +1794,8 @@ cts/Makefile \ + cts/CTSvars.py \ + cts/LSBDummy \ + cts/benchmark/Makefile \ +- cts/benchmark/clubench \ ++ cts/benchmark/clubench \ ++ cts/lxc_autogen.sh \ + cib/Makefile \ + crmd/Makefile \ + pengine/Makefile \ +diff --git a/cts/CTSlab.py b/cts/CTSlab.py +index 58506c3..f7e183c 100755 +--- a/cts/CTSlab.py ++++ b/cts/CTSlab.py +@@ -95,6 +95,7 @@ class LabEnvironment(CtsLab): + #self["valgrind-opts"] = """--trace-children=no --num-callers=25 --gen-suppressions=all --suppressions="""+CTSvars.CTS_home+"""/cts.supp""" + + self["experimental-tests"] = 0 ++ self["container-tests"] = 0 + self["valgrind-tests"] = 0 + self["unsafe-tests"] = 1 + self["loop-tests"] = 1 +@@ -148,6 +149,7 @@ def usage(arg, status=1): + print "\t [--no-unsafe-tests] dont run tests that are unsafe for use with ocfs2/drbd" + print "\t [--valgrind-tests] include tests using valgrind" + print "\t [--experimental-tests] include experimental tests" ++ print "\t [--container-tests] include pacemaker_remote tests that run in lxc container resources" + print "\t [--oprofile 'node list'] list of cluster nodes to run oprofile on]" + print "\t [--qarsh] use the QARSH backdoor to access nodes instead of SSH" + print "\t [--seed random_seed]" +@@ -427,6 +429,9 @@ if __name__ == '__main__': + elif args[i] == "--experimental-tests": + Environment["experimental-tests"] = 1 + ++ elif args[i] == "--container-tests": ++ Environment["container-tests"] = 1 ++ + elif args[i] == "--set": + skipthis=1 + (name, value) = args[i+1].split('=') +diff --git a/cts/CTStests.py b/cts/CTStests.py +index b5dd69a..19f6ef4 100644 +--- a/cts/CTStests.py ++++ b/cts/CTStests.py +@@ -73,6 +73,7 @@ class CTSTest: + self.is_loop = 0 + self.is_unsafe = 0 + self.is_experimental = 0 ++ self.is_container = 0 + self.is_valgrind = 0 + self.benchmark = 0 # which tests to benchmark + self.timer = {} # timers +@@ -205,6 +206,8 @@ class CTSTest: + return 0 + elif self.is_experimental and not self.CM.Env["experimental-tests"]: + return 0 ++ elif self.is_container and not self.CM.Env["container-tests"]: ++ return 0 + elif self.CM.Env["benchmark"] and self.benchmark == 0: + return 0 + +@@ -2473,4 +2476,118 @@ def TestList(cm, audits): + result.append(bound_test) + return result + ++################################################################### ++class RemoteLXC(CTSTest): ++################################################################### ++ def __init__(self, cm): ++ CTSTest.__init__(self,cm) ++ self.name="RemoteLXC" ++ self.start = StartTest(cm) ++ self.startall = SimulStartLite(cm) ++ self.num_containers = 2 ++ self.is_container = 1 ++ self.failed = 0 ++ self.fail_string = "" ++ ++ def start_lxc_simple(self, node): ++ ++ rc = self.CM.rsh(node, "/usr/share/pacemaker/tests/cts/lxc_autogen.sh -v &>/dev/null") ++ if rc == 1: ++ return self.skipped() ++ ++ # restore any artifacts laying around from a previous test. ++ self.CM.rsh(node, "/usr/share/pacemaker/tests/cts/lxc_autogen.sh -R &>/dev/null") ++ ++ # generate the containers, put them in the config, add some resources to them ++ pats = [ ] ++ watch = self.create_watch(pats, 120) ++ watch.setwatch() ++ pats.append("process_lrm_event: LRM operation lxc1_start_0.*confirmed.*ok") ++ pats.append("process_lrm_event: LRM operation lxc2_start_0.*confirmed.*ok") ++ pats.append("process_lrm_event: LRM operation lxc-ms_start_0.*confirmed.*ok") ++ pats.append("process_lrm_event: LRM operation lxc-ms_promote_0.*confirmed.*ok") ++ ++ self.CM.rsh(node, "/usr/share/pacemaker/tests/cts/lxc_autogen.sh -g -a -m -s -c %d &>/dev/null" % self.num_containers) ++ self.set_timer("remoteSimpleInit") ++ watch.lookforall() ++ self.log_timer("remoteSimpleInit") ++ if watch.unmatched: ++ self.fail_string = "Unmatched patterns: %s" % (repr(watch.unmatched)) ++ self.failed = 1 ++ ++ def cleanup_lxc_simple(self, node): ++ ++ pats = [ ] ++ # if the test failed, attempt to clean up the cib and libvirt environment ++ # as best as possible ++ if self.failed == 1: ++ # restore libvirt and cib ++ self.CM.rsh(node, "/usr/share/pacemaker/tests/cts/lxc_autogen.sh -R &>/dev/null") ++ self.CM.rsh(node, "crm_resource -C -r container1 &>/dev/null") ++ self.CM.rsh(node, "crm_resource -C -r container2 &>/dev/null") ++ self.CM.rsh(node, "crm_resource -C -r lxc1 &>/dev/null") ++ self.CM.rsh(node, "crm_resource -C -r lxc2 &>/dev/null") ++ self.CM.rsh(node, "crm_resource -C -r lxc-ms &>/dev/null") ++ time.sleep(20) ++ return ++ ++ watch = self.create_watch(pats, 120) ++ watch.setwatch() ++ ++ pats.append("process_lrm_event: LRM operation container1_stop_0.*confirmed.*ok") ++ pats.append("process_lrm_event: LRM operation container2_stop_0.*confirmed.*ok") ++ ++ self.CM.rsh(node, "/usr/share/pacemaker/tests/cts/lxc_autogen.sh -p &>/dev/null") ++ self.set_timer("remoteSimpleCleanup") ++ watch.lookforall() ++ self.log_timer("remoteSimpleCleanup") ++ ++ if watch.unmatched: ++ self.fail_string = "Unmatched patterns: %s" % (repr(watch.unmatched)) ++ self.failed = 1 ++ ++ # cleanup libvirt ++ self.CM.rsh(node, "/usr/share/pacemaker/tests/cts/lxc_autogen.sh -R &>/dev/null") ++ ++ def __call__(self, node): ++ '''Perform the 'RemoteLXC' test. ''' ++ self.incr("calls") ++ ++ ret = self.startall(None) ++ if not ret: ++ return self.failure("Setup failed, start all nodes failed.") ++ ++ self.start_lxc_simple(node) ++ self.cleanup_lxc_simple(node) ++ ++ self.CM.debug("Waiting for the cluster to recover") ++ self.CM.cluster_stable() ++ ++ if self.failed == 1: ++ return self.failure(self.fail_string) ++ ++ return self.success() ++ ++ def errorstoignore(self): ++ '''Return list of errors which should be ignored''' ++ return [ """Updating failcount for ping""", ++ """LogActions: Recover ping""", ++ """LogActions: Recover lxc-ms""", ++ """LogActions: Recover container""", ++ # The orphaned lxc-ms resource causes an expected transition error ++ # that is a result of the pengine not having knowledge that the ++ # ms resource used to be a clone. As a result it looks like that ++ # resource is running in multiple locations when it shouldn't... But in ++ # this instance we know why this error is occurring and that it is expected. ++ """Calculated Transition .* /var/lib/pacemaker/pengine/pe-error""", ++ """Resource lxc-ms .* is active on 2 nodes attempting recovery""", ++ """Unknown operation: fail""", ++ """notice: operation_finished: ping-""", ++ """notice: operation_finished: container""", ++ """notice: operation_finished: .*_monitor_0:.*:stderr""", ++ """(ERROR|error): sending stonithRA op to stonithd failed.""", ++ ] ++ ++AllTestClasses.append(RemoteLXC) ++ + # vim:ts=4:sw=4:et: +diff --git a/cts/Makefile.am b/cts/Makefile.am +index e01ac10..cb86db8 100644 +--- a/cts/Makefile.am ++++ b/cts/Makefile.am +@@ -40,6 +40,7 @@ cts_DATA = README cts.supp + + cts_SCRIPTS = cluster_test \ + CTSlab.py \ ++ lxc_autogen.sh \ + LSBDummy \ + $(top_srcdir)/fencing/fence_dummy + +diff --git a/cts/lxc_autogen.sh.in b/cts/lxc_autogen.sh.in +new file mode 100644 +index 0000000..1d334c4 +--- /dev/null ++++ b/cts/lxc_autogen.sh.in +@@ -0,0 +1,362 @@ ++#!/bin/bash ++ ++containers="2" ++download=0 ++share_configs=0 ++# different than default libvirt network in case this is run nested in a KVM instance ++addr="192.168.123.1" ++restore=0 ++restore_pcmk=0 ++restore_all=0 ++generate=0 ++key_gen=0 ++cib=0 ++add_master=0 ++verify=0 ++working_dir="@CRM_CONFIG_CTS@/lxc" ++curdir=$(pwd) ++ ++function helptext() { ++ echo "lxc_autogen.sh - A tool for generating libvirt lxc containers for testing purposes." ++ echo "" ++ echo "Usage: lxc-autogen [options]" ++ echo "" ++ echo "Options:" ++ echo "-g, --generate Generate libvirt lxc environment in the directory this script is run from." ++ echo "-k, --key-gen Generate local pacemaker remote key only." ++ echo "-r, --restore-libvirt Restore the default network, and libvirt config to before this script ran." ++ echo "-p, --restore-cib Remove cib entries this script generated." ++ echo "-R, --restore-all Restore both libvirt and cib plus clean working directory. This will leave libvirt xml files though so rsc can be stopped properly." ++ echo "" ++ echo "-a, --add-cib Add remote-node entries for each lxc instance into the cib" ++ echo "-m, --add-master Add master resource shared between remote-nodes" ++ echo "-d, --download-agent Download and install the latest VirtualDomain agent." ++ echo "-s, --share-configs Copy container configs to all other known cluster nodes, (crm_node -l)" ++ echo "-c, --containers Specify the number of containers to generate, defaults to $containers. Used with -g" ++ echo "-n, --network What network to override default libvirt network to. Example: -n 192.168.123.1. Used with -g" ++ echo "-v, --verify Verify environment is capable of running lxc" ++ echo "" ++ exit $1 ++} ++ ++while true ; do ++ case "$1" in ++ --help|-h|-\?) helptext 0;; ++ -c|--containers) containers="$2"; shift; shift;; ++ -d|--download-agent) download=1; shift;; ++ -s|--share-configs) share_configs=1; shift;; ++ -n|--network) addr="$2"; shift; shift;; ++ -r|--restore-libvirt) restore=1; shift;; ++ -p|--restore-cib) restore_pcmk=1; shift;; ++ -R|--restore-all) ++ restore_all=1 ++ restore=1 ++ restore_pcmk=1 ++ shift;; ++ -g|--generate) generate=1; shift;; ++ -k|--key-gen) key_gen=1; shift;; ++ -a|--add-cib) cib=1; shift;; ++ -m|--add-master) add_master=1; shift;; ++ -v|--verify) verify=1; shift;; ++ "") break;; ++ *) helptext 1;; ++ esac ++done ++ ++if [ $verify -eq 1 ]; then ++ # verify virsh tool is available and that ++ # we can connect to lxc driver. ++ virsh -c lxc:/// list --all > /dev/null 2>&1 ++ if [ $? -ne 0 ]; then ++ echo "Could not connect 'virsh -c lxc:///' check that libvirt lxc driver is installed" ++ exit 1 ++ fi ++ ++ cat /etc/selinux/config | grep -e "SELINUX.*=.*permissive" -e "SELINUX.*=.*enforcing" > /dev/null 2>&1 ++ if [ $? -ne 0 ]; then ++ echo "/etc/selinux/config must have SELINUX set to permissive or enforcing mode." ++ exit 1 ++ fi ++ ++ ps x > /tmp/lxc-autogen-libvirt-test.txt ++ grep "libvirtd" /tmp/lxc-autogen-libvirt-test.txt ++ if [ $? -ne 0 ]; then ++ rm -f /tmp/lxc-autogen-libvirt-test.txt ++ echo "libvirtd isn't up." ++ exit 1 ++ fi ++ rm -f /tmp/lxc-autogen-libvirt-test.txt ++ ++ which rsync > /dev/null 2>&1 ++ if [ $? -ne 0 ]; then ++ echo "rsync is required" ++ fi ++ ++fi ++ ++#strip last digits off addr ++tmp="s/\.$(echo "$addr" | tr '.' ' ' | awk '{print $4}')$//g" ++addr=$(echo $addr | sed -e ${tmp}) ++ ++set_network() ++{ ++ rm -f cur_network.xml ++ cat << END >> cur_network.xml ++ ++ default ++ 41ebdb84-7134-1111-a136-91f0f1119225 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++ ++ ls restore_default.xml > /dev/null 2>&1 ++ if [ $? -ne 0 ]; then ++ virsh net-dumpxml default > restore_default.xml ++ fi ++ virsh net-destroy default ++ virsh net-undefine default ++ virsh net-define cur_network.xml ++ virsh net-start default ++} ++ ++generate_key() ++{ ++ #generate pacemaker remote key ++ ls /etc/pacemaker/authkey > /dev/null 2>&1 ++ if [ $? != 0 ]; then ++ mkdir -p /etc/pacemaker ++ dd if=/dev/urandom of=/etc/pacemaker/authkey bs=4096 count=1 ++ fi ++} ++ ++generate() ++{ ++ set_network ++ ++ # Generate libvirt domains in xml ++ for (( c=1; c <= $containers; c++ )) ++ do ++ rm -rf lxc$c-filesystem ++ mkdir -p lxc$c-filesystem/var/run/ ++ mkdir -p lxc$c-filesystem/usr/var/run ++ rm -f lxc$c.xml ++ cat << END >> lxc$c.xml ++ ++ lxc$c ++ 102400 ++ ++ exe ++ $working_dir/lxc$c-filesystem/launch-helper ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++ rm -f container$c.cib ++ cat << END >> container$c.cib ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++ ++ rm -f lxc-ms$c.cib ++ cat << END >> lxc-ms.cib ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++ ++ rm -f lxc$c-filesystem/launch-helper ++ cat << END >> lxc$c-filesystem/launch-helper ++#!/bin/bash ++ifconfig eth0 $addr.10$c ++route add 0.0.0.0 gw $addr.1 eth0 ++hostname lxc$c ++/usr/sbin/pacemaker_remoted ++END ++ chmod 711 lxc$c-filesystem/launch-helper ++ ++ cat << END >> /etc/hosts ++$addr.10$c lxc$c ++END ++ done ++} ++ ++apply_cib_master() ++{ ++ cibadmin -Q > cur.cib ++ export CIB_file=cur.cib ++ ++ cibadmin -o resources -C -x lxc-ms.cib ++ for tmp in $(ls lxc*.xml); do ++ tmp=$(echo $tmp | sed -e 's/\.xml//g') ++ echo "" > tmp_constraint ++ cibadmin -o constraints -C -x tmp_constraint ++ echo "" > tmp_constraint ++ cibadmin -o constraints -C -x tmp_constraint > /dev/null 2>&1 ++ rm -f tmp_constraint ++ done ++ unset CIB_file ++ ++ cibadmin --replace --xml-file cur.cib ++ rm -f cur.cib ++} ++ ++apply_cib_entries() ++{ ++ node=$(crm_node -n) ++ ++ cibadmin -Q > cur.cib ++ export CIB_file=cur.cib ++ for tmp in $(ls container*.cib); do ++ cibadmin -o resources -C -x $tmp ++ ++ tmp=$(echo $tmp | sed -e 's/\.cib//g') ++ crm_resource -M -r $tmp -H $node ++ done ++ unset CIB_file ++ ++ cibadmin --replace --xml-file cur.cib ++ rm -f cur.cib ++} ++ ++restore_cib() ++{ ++ node=$(crm_node -n) ++ cibadmin -Q > cur.cib ++ export CIB_file=cur.cib ++ ++ for tmp in $(ls lxc*.xml); do ++ tmp=$(echo $tmp | sed -e 's/\.xml//g') ++ echo "" > tmp_constraint ++ cibadmin -o constraints -D -x tmp_constraint ++ echo "" > tmp_constraint ++ cibadmin -o constraints -D -x tmp_constraint ++ rm -f tmp_constraint ++ done ++ cibadmin -o resources -D -x lxc-ms.cib ++ ++ for tmp in $(ls container*.cib); do ++ tmp=$(echo $tmp | sed -e 's/\.cib//g') ++ crm_resource -U -r $tmp -H $node ++ crm_resource -D -r $tmp -t primitive ++ done ++ unset CIB_file ++ ++ cibadmin --replace --xml-file cur.cib ++ rm -f cur.cib ++} ++ ++restore_libvirt() ++{ ++ for tmp in $(ls lxc*.xml); do ++ tmp=$(echo $tmp | sed -e 's/\.xml//g') ++ virsh -c lxc:/// destroy $tmp > /dev/null 2>&1 ++ virsh -c lxc:/// undefine $tmp > /dev/null 2>&1 ++ ++ sed -i.bak "/...\....\....\..* ${tmp}/d" /etc/hosts ++ echo "$tmp destroyed" ++ done ++ ++ ls restore_default.xml > /dev/null 2>&1 ++ if [ $? -eq 0 ]; then ++ virsh net-destroy default > /dev/null 2>&1 ++ virsh net-undefine default > /dev/null 2>&1 ++ virsh net-define restore_default.xml ++ virsh net-start default ++ if [ $? -eq 0 ]; then ++ echo "default network restored" ++ fi ++ fi ++ rm -f restore_default.xml > /dev/null 2>&1 ++} ++ ++distribute_configs() ++{ ++ local node ++ local id ++ while read id node ++ do ++ rsync -ave 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' $working_dir/lxc*.xml $node:/$working_dir ++ rsync -ave 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' $working_dir/lxc*-filesystem $node:/$working_dir ++ done < <(crm_node -l) ++} ++ ++mkdir -p $working_dir ++cd $working_dir ++ ++if [ $download -eq 1 ]; then ++ wget https://raw.github.com/ClusterLabs/resource-agents/master/heartbeat/VirtualDomain ++ chmod 755 VirtualDomain ++ mv -f VirtualDomain /usr/lib/ocf/resource.d/heartbeat/VirtualDomain ++fi ++if [ $restore_pcmk -eq 1 ]; then ++ restore_cib ++fi ++if [ $restore -eq 1 ]; then ++ restore_libvirt ++fi ++if [ $key_gen -eq 1 ]; then ++ generate_key ++fi ++if [ $generate -eq 1 ]; then ++ if [ $key_gen -eq 0]; then ++ generate_key ++ fi ++ generate ++fi ++if [ $cib -eq 1 ]; then ++ apply_cib_entries ++fi ++if [ $add_master -eq 1 ]; then ++ apply_cib_master ++fi ++if [ $share_configs -eq 1 ]; then ++ distribute_configs ++fi ++if [ $restore_all -eq 1 ]; then ++ ls | grep -v "lxc.\.xml" | xargs rm -rf ++fi ++ ++cd $curdir diff --git a/SOURCES/pacemaker-doc_controld_update_the_description.patch b/SOURCES/pacemaker-doc_controld_update_the_description.patch new file mode 100644 index 0000000..ccdb1be --- /dev/null +++ b/SOURCES/pacemaker-doc_controld_update_the_description.patch @@ -0,0 +1,24 @@ +commit 41d245c28c5144423073e4fffa543a744c2ec321 +Author: Andrew Beekhof +Date: Wed Aug 7 09:11:31 2013 +1000 + + Doc: controld: Update the description + +diff --git a/extra/resources/controld b/extra/resources/controld +index 2122ff8..bacf0e9 100644 +--- a/extra/resources/controld ++++ b/extra/resources/controld +@@ -42,11 +42,11 @@ meta_data() { + 1.0 + + +-This Resource Agent can control the dlm_controld services needed by ocfs2. ++This Resource Agent can control the dlm_controld services needed by cluster-aware file systems. + It assumes that dlm_controld is in your default PATH. + In most cases, it should be run as an anonymous clone. + +-DLM Agent for OCFS2 ++DLM Agent for cluster file systems + + + diff --git a/SOURCES/pacemaker-fix-orphaned-connection-resources.patch b/SOURCES/pacemaker-fix-orphaned-connection-resources.patch new file mode 100644 index 0000000..01abbbb --- /dev/null +++ b/SOURCES/pacemaker-fix-orphaned-connection-resources.patch @@ -0,0 +1,2099 @@ +commit 261c6b836e4a44c6d20d5abd7550ef1f0b25c17c +Author: David Vossel +Date: Wed Sep 25 17:47:04 2013 -0400 + + fix orphaned connection resources + +diff --git a/crmd/lrm.c b/crmd/lrm.c +index 7157e24..5f4d3bb 100644 +--- a/crmd/lrm.c ++++ b/crmd/lrm.c +@@ -729,6 +729,13 @@ build_active_RAs(lrm_state_t * lrm_state, xmlNode * rsc_list) + crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, entry->rsc.class); + crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER, entry->rsc.provider); + ++ if (entry->last && entry->last->params) { ++ const char *container = g_hash_table_lookup(entry->last->params, CRM_META"_"XML_RSC_ATTR_CONTAINER); ++ if (container) { ++ crm_trace("Resource %s is a part of container resource %s", entry->id, container); ++ crm_xml_add(xml_rsc, XML_RSC_ATTR_CONTAINER, container); ++ } ++ } + build_operation_update(xml_rsc, &(entry->rsc), entry->last, __FUNCTION__); + build_operation_update(xml_rsc, &(entry->rsc), entry->failed, __FUNCTION__); + for (gIter = entry->recurring_op_list; gIter != NULL; gIter = gIter->next) { +@@ -1930,10 +1937,20 @@ do_update_resource(lrm_state_t * lrm_state, lrmd_rsc_info_t * rsc, lrmd_event_da + build_operation_update(iter, rsc, op, __FUNCTION__); + + if (rsc) { ++ const char *container = NULL; ++ + crm_xml_add(iter, XML_ATTR_TYPE, rsc->type); + crm_xml_add(iter, XML_AGENT_ATTR_CLASS, rsc->class); + crm_xml_add(iter, XML_AGENT_ATTR_PROVIDER, rsc->provider); + ++ if (op->params) { ++ container = g_hash_table_lookup(op->params, CRM_META"_"XML_RSC_ATTR_CONTAINER); ++ } ++ if (container) { ++ crm_trace("Resource %s is a part of container resource %s", op->rsc_id, container); ++ crm_xml_add(iter, XML_RSC_ATTR_CONTAINER, container); ++ } ++ + CRM_CHECK(rsc->type != NULL, crm_err("Resource %s has no value for type", op->rsc_id)); + CRM_CHECK(rsc->class != NULL, crm_err("Resource %s has no value for class", op->rsc_id)); + +diff --git a/include/crm/pengine/status.h b/include/crm/pengine/status.h +index bd3d923..8eb4a1d 100644 +--- a/include/crm/pengine/status.h ++++ b/include/crm/pengine/status.h +@@ -160,6 +160,7 @@ struct node_s { + # define pe_rsc_orphan 0x00000001ULL + # define pe_rsc_managed 0x00000002ULL + # define pe_rsc_block 0x00000004ULL /* Further operations are prohibited due to failure policy */ ++# define pe_rsc_orphan_container_filler 0x00000008ULL + + # define pe_rsc_notify 0x00000010ULL + # define pe_rsc_unique 0x00000020ULL +diff --git a/lib/cib/cib_attrs.c b/lib/cib/cib_attrs.c +index d1e1b74..5e21eef 100644 +--- a/lib/cib/cib_attrs.c ++++ b/lib/cib/cib_attrs.c +@@ -414,40 +414,54 @@ delete_attr_delegate(cib_t * the_cib, int options, + return rc; + } + +-static int +-get_remote_node_uuid(cib_t * the_cib, const char *uname, char **uuid) ++static gboolean ++found_remote_node_xpath(cib_t *the_cib, const char *xpath) + { +-#define REMOTE_NODE_XPATH "//nvpair[@name='remote-node'][@value='%s']" +-#define REMOTE_NODE_XPATH2 "//primitive[@type='remote'][@provider='pacemaker'][@id='%s']" + int rc = pcmk_ok; +- char *xpath_string = NULL; +- size_t len = strlen(REMOTE_NODE_XPATH) + strlen(uname) + 1; + xmlNode *xml_search = NULL; + +- xpath_string = calloc(1, len); +- sprintf(xpath_string, REMOTE_NODE_XPATH, uname); +- rc = cib_internal_op(the_cib, CIB_OP_QUERY, NULL, xpath_string, NULL, &xml_search, ++ rc = cib_internal_op(the_cib, CIB_OP_QUERY, NULL, xpath, NULL, &xml_search, + cib_sync_call | cib_scope_local | cib_xpath, NULL); +- free(xpath_string); + free(xml_search); +- xml_search = NULL; +- xpath_string = NULL; + +- if (rc != pcmk_ok) { +- len = strlen(REMOTE_NODE_XPATH2) + strlen(uname) + 1; +- xpath_string = calloc(1, len); +- sprintf(xpath_string, REMOTE_NODE_XPATH2, uname); +- rc = cib_internal_op(the_cib, CIB_OP_QUERY, NULL, xpath_string, NULL, &xml_search, +- cib_sync_call | cib_scope_local | cib_xpath, NULL); ++ return rc == pcmk_ok ? TRUE : FALSE; ++} + +- free(xpath_string); +- free(xml_search); ++static int ++get_remote_node_uuid(cib_t * the_cib, const char *uname, char **uuid) ++{ ++#define CONTAINER_REMOTE_NODE_XPATH "//" XML_CIB_TAG_NVPAIR "[@name='remote-node'][@value='%s']" ++#define BAREMETAL_REMOTE_NODE_XPATH "//" XML_CIB_TAG_RESOURCE "[@type='remote'][@provider='pacemaker'][@id='%s']" ++#define ORPHAN_REMOTE_NODE_XPATH "//" XML_CIB_TAG_STATUS "//" XML_CIB_TAG_STATE "[@id='%s'][@remote_node='true']" ++ int len = 128 + strlen(uname); ++ int rc = pcmk_ok; ++ char *xpath_string = calloc(1, len); ++ ++ sprintf(xpath_string, CONTAINER_REMOTE_NODE_XPATH, uname); ++ if (found_remote_node_xpath(the_cib, xpath_string)) { ++ goto found_remote; + } + +- if (rc == pcmk_ok) { +- *uuid = strdup(uname); ++ sprintf(xpath_string, BAREMETAL_REMOTE_NODE_XPATH, uname); ++ if (found_remote_node_xpath(the_cib, xpath_string)) { ++ goto found_remote; ++ } ++ ++ sprintf(xpath_string, ORPHAN_REMOTE_NODE_XPATH, uname); ++ if (found_remote_node_xpath(the_cib, xpath_string)) { ++ goto found_remote; + } + ++ rc = -1; ++found_remote: ++ if (rc == pcmk_ok) { ++ /* reuse allocation */ ++ *uuid = xpath_string; ++ strcpy(*uuid, uname); ++ } else { ++ *uuid = NULL; ++ free(xpath_string); ++ } + return rc; + } + +diff --git a/lib/pengine/complex.c b/lib/pengine/complex.c +index 5e2f4e0..8a6049d 100644 +--- a/lib/pengine/complex.c ++++ b/lib/pengine/complex.c +@@ -159,6 +159,10 @@ get_rsc_attributes(GHashTable * meta_hash, resource_t * rsc, + unpack_instance_attributes(data_set->input, rsc->xml, XML_TAG_ATTR_SETS, node_hash, + meta_hash, NULL, FALSE, data_set->now); + ++ if (rsc->container) { ++ g_hash_table_replace(meta_hash, strdup(CRM_META"_"XML_RSC_ATTR_CONTAINER), strdup(rsc->container->id)); ++ } ++ + /* set anything else based on the parent */ + if (rsc->parent != NULL) { + get_rsc_attributes(meta_hash, rsc->parent, node, data_set); +diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c +index b4986dd..26cecb2 100644 +--- a/lib/pengine/unpack.c ++++ b/lib/pengine/unpack.c +@@ -248,6 +248,7 @@ create_node(const char *id, const char *uname, const char *type, const char *sco + + if (safe_str_eq(type, "remote")) { + new_node->details->type = node_remote; ++ set_bit(data_set->flags, pe_flag_have_remote_nodes); + } else if (type == NULL || safe_str_eq(type, "member") + || safe_str_eq(type, NORMALNODE)) { + new_node->details->type = node_member; +@@ -612,7 +613,6 @@ unpack_remote_nodes(xmlNode * xml_resources, pe_working_set_t * data_set) + } + + if (new_node_id) { +- set_bit(data_set->flags, pe_flag_have_remote_nodes); + crm_trace("detected remote node %s", new_node_id); + create_node(new_node_id, new_node_id, "remote", NULL, data_set); + } +@@ -1399,6 +1399,22 @@ create_fake_resource(const char *rsc_id, xmlNode * rsc_entry, pe_working_set_t * + return NULL; + } + ++ if (is_remote_node(xml_rsc)) { ++ node_t *node; ++ ++ crm_debug("Detected orphaned remote node %s", rsc_id); ++ rsc->is_remote_node = TRUE; ++ node = create_node(rsc_id, rsc_id, "remote", NULL, data_set); ++ ++ CRM_ASSERT(node != NULL); ++ node->details->remote_rsc = rsc; ++ } ++ ++ if (crm_element_value(rsc_entry, XML_RSC_ATTR_CONTAINER)) { ++ /* This orphaned rsc needs to be mapped to a container. */ ++ crm_trace("Detected orphaned container filler %s", rsc_id); ++ set_bit(rsc->flags, pe_rsc_orphan_container_filler); ++ } + set_bit(rsc->flags, pe_rsc_orphan); + data_set->resources = g_list_append(data_set->resources, rsc); + return rsc; +@@ -1860,7 +1876,7 @@ calculate_active_ops(GListPtr sorted_op_list, int *start_index, int *stop_index) + } + } + +-static void ++static resource_t * + unpack_lrm_rsc_state(node_t * node, xmlNode * rsc_entry, pe_working_set_t * data_set) + { + GListPtr gIter = NULL; +@@ -1896,7 +1912,7 @@ unpack_lrm_rsc_state(node_t * node, xmlNode * rsc_entry, pe_working_set_t * data + + if (op_list == NULL) { + /* if there are no operations, there is nothing to do */ +- return; ++ return NULL; + } + + /* find the resource */ +@@ -1949,12 +1965,55 @@ unpack_lrm_rsc_state(node_t * node, xmlNode * rsc_entry, pe_working_set_t * data + if (saved_role > rsc->role) { + rsc->role = saved_role; + } ++ ++ return rsc; ++} ++ ++static void ++handle_orphaned_container_fillers(xmlNode * lrm_rsc_list, pe_working_set_t * data_set) ++{ ++ xmlNode *rsc_entry = NULL; ++ for (rsc_entry = __xml_first_child(lrm_rsc_list); rsc_entry != NULL; ++ rsc_entry = __xml_next(rsc_entry)) { ++ ++ resource_t *rsc; ++ resource_t *container; ++ const char *rsc_id; ++ const char *container_id; ++ ++ if (safe_str_neq((const char *)rsc_entry->name, XML_LRM_TAG_RESOURCE)) { ++ continue; ++ } ++ ++ container_id = crm_element_value(rsc_entry, XML_RSC_ATTR_CONTAINER); ++ rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID); ++ if (container_id == NULL || rsc_id == NULL) { ++ continue; ++ } ++ ++ container = pe_find_resource(data_set->resources, container_id); ++ if (container == NULL) { ++ continue; ++ } ++ ++ rsc = pe_find_resource(data_set->resources, rsc_id); ++ if (rsc == NULL || ++ is_set(rsc->flags, pe_rsc_orphan_container_filler) == FALSE || ++ rsc->container != NULL) { ++ continue; ++ } ++ ++ pe_rsc_trace(rsc, "Mapped orphaned rsc %s's container to %s", rsc->id, container_id); ++ rsc->container = container; ++ container->fillers = g_list_append(container->fillers, rsc); ++ } + } + + gboolean + unpack_lrm_resources(node_t * node, xmlNode * lrm_rsc_list, pe_working_set_t * data_set) + { + xmlNode *rsc_entry = NULL; ++ gboolean found_orphaned_container_filler = FALSE; + + CRM_CHECK(node != NULL, return FALSE); + +@@ -1962,11 +2021,23 @@ unpack_lrm_resources(node_t * node, xmlNode * lrm_rsc_list, pe_working_set_t * d + + for (rsc_entry = __xml_first_child(lrm_rsc_list); rsc_entry != NULL; + rsc_entry = __xml_next(rsc_entry)) { ++ + if (crm_str_eq((const char *)rsc_entry->name, XML_LRM_TAG_RESOURCE, TRUE)) { +- unpack_lrm_rsc_state(node, rsc_entry, data_set); ++ resource_t *rsc; ++ rsc = unpack_lrm_rsc_state(node, rsc_entry, data_set); ++ if (rsc && is_set(rsc->flags, pe_rsc_orphan_container_filler)) { ++ found_orphaned_container_filler = TRUE; ++ } + } + } + ++ /* now that all the resource state has been unpacked for this node ++ * we have to go back and map any orphaned container fillers to their ++ * container resource */ ++ if (found_orphaned_container_filler) { ++ handle_orphaned_container_fillers(lrm_rsc_list, data_set); ++ } ++ + return TRUE; + } + +diff --git a/pengine/allocate.c b/pengine/allocate.c +index bfa8e7b..e535b84 100644 +--- a/pengine/allocate.c ++++ b/pengine/allocate.c +@@ -1576,10 +1576,10 @@ apply_remote_node_ordering(pe_working_set_t *data_set) + + remote_rsc = action->node->details->remote_rsc; + container = remote_rsc->container; ++ + if (safe_str_eq(action->task, "monitor") || + safe_str_eq(action->task, "start") || + safe_str_eq(action->task, "promote") || +- safe_str_eq(action->task, "demote") || + safe_str_eq(action->task, CRM_OP_LRM_REFRESH) || + safe_str_eq(action->task, CRM_OP_CLEAR_FAILCOUNT) || + safe_str_eq(action->task, "delete")) { +@@ -1593,6 +1593,39 @@ apply_remote_node_ordering(pe_working_set_t *data_set) + pe_order_implies_then | pe_order_runnable_left, + data_set); + ++ } else if (safe_str_eq(action->task, "demote")) { ++ ++ /* If the connection is being torn down, we don't want ++ * to build a constraint between a resource's demotion and ++ * the connection resource starting... because the connection ++ * resource can not start. The connection might already be up, ++ * but the START action would not be allowed which in turn would ++ * block the demotion of any resournces living in the remote-node. ++ * ++ * In this case, only build the constraint between the demotion and ++ * the connection's stop action. This allows the connection and all the ++ * resources within the remote-node to be torn down properly. */ ++ if (remote_rsc->next_role == RSC_ROLE_STOPPED) { ++ custom_action_order(action->rsc, ++ NULL, ++ action, ++ remote_rsc, ++ generate_op_key(remote_rsc->id, RSC_STOP, 0), ++ NULL, ++ pe_order_implies_first, ++ data_set); ++ } else { ++ ++ custom_action_order(remote_rsc, ++ generate_op_key(remote_rsc->id, RSC_START, 0), ++ NULL, ++ action->rsc, ++ NULL, ++ action, ++ pe_order_implies_then | pe_order_runnable_left, ++ data_set); ++ } ++ + } else if (safe_str_eq(action->task, "stop") && + container && + is_set(container->flags, pe_rsc_failed)) { +diff --git a/pengine/test10/container-1.exp b/pengine/test10/container-1.exp +index 1924ef8..522b0f1 100644 +--- a/pengine/test10/container-1.exp ++++ b/pengine/test10/container-1.exp +@@ -47,7 +47,7 @@ + + + +- ++ + + + +@@ -60,7 +60,7 @@ + + + +- ++ + + + +@@ -73,7 +73,7 @@ + + + +- ++ + + + +@@ -86,7 +86,7 @@ + + + +- ++ + + + +diff --git a/pengine/test10/container-2.exp b/pengine/test10/container-2.exp +index d699d28..c5f9e9e 100644 +--- a/pengine/test10/container-2.exp ++++ b/pengine/test10/container-2.exp +@@ -45,7 +45,7 @@ + + + +- ++ + + + +@@ -61,7 +61,7 @@ + + + +- ++ + + + +@@ -70,7 +70,7 @@ + + + +- ++ + + + +@@ -83,7 +83,7 @@ + + + +- ++ + + + +@@ -99,7 +99,7 @@ + + + +- ++ + + + +@@ -108,7 +108,7 @@ + + + +- ++ + + + +diff --git a/pengine/test10/container-3.exp b/pengine/test10/container-3.exp +index cc774da..3c2703a 100644 +--- a/pengine/test10/container-3.exp ++++ b/pengine/test10/container-3.exp +@@ -42,7 +42,7 @@ + + + +- ++ + + + +@@ -55,7 +55,7 @@ + + + +- ++ + + + +@@ -68,7 +68,7 @@ + + + +- ++ + + + +@@ -84,7 +84,7 @@ + + + +- ++ + + + +@@ -93,7 +93,7 @@ + + + +- ++ + + + +diff --git a/pengine/test10/container-4.exp b/pengine/test10/container-4.exp +index 72f50cc..d1da381 100644 +--- a/pengine/test10/container-4.exp ++++ b/pengine/test10/container-4.exp +@@ -45,7 +45,7 @@ + + + +- ++ + + + +@@ -58,7 +58,7 @@ + + + +- ++ + + + +@@ -74,7 +74,7 @@ + + + +- ++ + + + +@@ -83,7 +83,7 @@ + + + +- ++ + + + +@@ -96,7 +96,7 @@ + + + +- ++ + + + +@@ -112,7 +112,7 @@ + + + +- ++ + + + +diff --git a/pengine/test10/container-group-1.exp b/pengine/test10/container-group-1.exp +index a007f84..b14aa4c 100644 +--- a/pengine/test10/container-group-1.exp ++++ b/pengine/test10/container-group-1.exp +@@ -79,7 +79,7 @@ + + + +- ++ + + + +@@ -92,7 +92,7 @@ + + + +- ++ + + + +@@ -111,7 +111,7 @@ + + + +- ++ + + + +@@ -124,7 +124,7 @@ + + + +- ++ + + + +diff --git a/pengine/test10/container-group-2.exp b/pengine/test10/container-group-2.exp +index 6d5e283..ce32cc3 100644 +--- a/pengine/test10/container-group-2.exp ++++ b/pengine/test10/container-group-2.exp +@@ -113,7 +113,7 @@ + + + +- ++ + + + +@@ -132,7 +132,7 @@ + + + +- ++ + + + +@@ -148,7 +148,7 @@ + + + +- ++ + + + +@@ -161,7 +161,7 @@ + + + +- ++ + + + +@@ -183,7 +183,7 @@ + + + +- ++ + + + +@@ -196,7 +196,7 @@ + + + +- ++ + + + +diff --git a/pengine/test10/container-group-3.exp b/pengine/test10/container-group-3.exp +index 4df7279..96d99c6 100644 +--- a/pengine/test10/container-group-3.exp ++++ b/pengine/test10/container-group-3.exp +@@ -101,7 +101,7 @@ + + + +- ++ + + + +@@ -114,7 +114,7 @@ + + + +- ++ + + + +@@ -130,7 +130,7 @@ + + + +- ++ + + + +@@ -143,7 +143,7 @@ + + + +- ++ + + + +diff --git a/pengine/test10/container-group-4.exp b/pengine/test10/container-group-4.exp +index dd5aad7..6128599 100644 +--- a/pengine/test10/container-group-4.exp ++++ b/pengine/test10/container-group-4.exp +@@ -113,7 +113,7 @@ + + + +- ++ + + + +@@ -126,7 +126,7 @@ + + + +- ++ + + + +@@ -145,7 +145,7 @@ + + + +- ++ + + + +@@ -161,7 +161,7 @@ + + + +- ++ + + + +@@ -174,7 +174,7 @@ + + + +- ++ + + + +@@ -196,7 +196,7 @@ + + + +- ++ + + + +diff --git a/pengine/test10/whitebox-asymmetric.exp b/pengine/test10/whitebox-asymmetric.exp +index 2c7e586..d60cffa 100644 +--- a/pengine/test10/whitebox-asymmetric.exp ++++ b/pengine/test10/whitebox-asymmetric.exp +@@ -32,7 +32,7 @@ + + + +- ++ + + + +@@ -45,7 +45,7 @@ + + + +- ++ + + + +diff --git a/pengine/test10/whitebox-fail1.exp b/pengine/test10/whitebox-fail1.exp +index 5741955..b298df5 100644 +--- a/pengine/test10/whitebox-fail1.exp ++++ b/pengine/test10/whitebox-fail1.exp +@@ -173,7 +173,7 @@ + + + +- ++ + + + +@@ -189,7 +189,7 @@ + + + +- ++ + + + +@@ -198,7 +198,7 @@ + + + +- ++ + + + +diff --git a/pengine/test10/whitebox-fail2.exp b/pengine/test10/whitebox-fail2.exp +index 5741955..b298df5 100644 +--- a/pengine/test10/whitebox-fail2.exp ++++ b/pengine/test10/whitebox-fail2.exp +@@ -173,7 +173,7 @@ + + + +- ++ + + + +@@ -189,7 +189,7 @@ + + + +- ++ + + + +@@ -198,7 +198,7 @@ + + + +- ++ + + + +diff --git a/pengine/test10/whitebox-fail3.exp b/pengine/test10/whitebox-fail3.exp +index 1b8d144..c5a6474 100644 +--- a/pengine/test10/whitebox-fail3.exp ++++ b/pengine/test10/whitebox-fail3.exp +@@ -151,7 +151,7 @@ + + + +- ++ + + + +@@ -164,7 +164,7 @@ + + + +- ++ + + + +@@ -180,7 +180,7 @@ + + + +- ++ + + + +diff --git a/pengine/test10/whitebox-move.exp b/pengine/test10/whitebox-move.exp +index 8dbdda0..60262b6 100644 +--- a/pengine/test10/whitebox-move.exp ++++ b/pengine/test10/whitebox-move.exp +@@ -168,7 +168,7 @@ + + + +- ++ + + + +@@ -181,7 +181,7 @@ + + + +- ++ + + + +@@ -197,7 +197,7 @@ + + + +- ++ + + + +diff --git a/pengine/test10/whitebox-orphan-ms.dot b/pengine/test10/whitebox-orphan-ms.dot +new file mode 100644 +index 0000000..f037179 +--- /dev/null ++++ b/pengine/test10/whitebox-orphan-ms.dot +@@ -0,0 +1,69 @@ ++ digraph "g" { ++"FencingFail_start_0 18node1" [ style=bold color="green" fontcolor="black"] ++"FencingFail_stop_0 18node3" -> "FencingFail_start_0 18node1" [ style = bold] ++"FencingFail_stop_0 18node3" -> "all_stopped" [ style = bold] ++"FencingFail_stop_0 18node3" [ style=bold color="green" fontcolor="black"] ++"all_stopped" [ style=bold color="green" fontcolor="orange"] ++"container1_delete_0 18node1" -> "container1_start_0 " [ style = dashed] ++"container1_delete_0 18node1" [ style=bold color="green" fontcolor="black"] ++"container1_delete_0 18node2" -> "container1_start_0 " [ style = dashed] ++"container1_delete_0 18node2" [ style=bold color="green" fontcolor="black"] ++"container1_delete_0 18node3" -> "container1_start_0 " [ style = dashed] ++"container1_delete_0 18node3" [ style=bold color="green" fontcolor="black"] ++"container1_start_0 " [ style=dashed color="red" fontcolor="black"] ++"container1_stop_0 18node1" -> "all_stopped" [ style = bold] ++"container1_stop_0 18node1" -> "container1_delete_0 18node1" [ style = bold] ++"container1_stop_0 18node1" -> "container1_delete_0 18node2" [ style = bold] ++"container1_stop_0 18node1" -> "container1_delete_0 18node3" [ style = bold] ++"container1_stop_0 18node1" -> "container1_start_0 " [ style = dashed] ++"container1_stop_0 18node1" [ style=bold color="green" fontcolor="black"] ++"container2_delete_0 18node1" [ style=bold color="green" fontcolor="black"] ++"container2_delete_0 18node2" [ style=bold color="green" fontcolor="black"] ++"container2_delete_0 18node3" [ style=bold color="green" fontcolor="black"] ++"container2_stop_0 18node1" -> "all_stopped" [ style = bold] ++"container2_stop_0 18node1" -> "container2_delete_0 18node1" [ style = bold] ++"container2_stop_0 18node1" -> "container2_delete_0 18node2" [ style = bold] ++"container2_stop_0 18node1" -> "container2_delete_0 18node3" [ style = bold] ++"container2_stop_0 18node1" [ style=bold color="green" fontcolor="black"] ++"lxc-ms_delete_0 18node1" [ style=bold color="green" fontcolor="black"] ++"lxc-ms_delete_0 18node2" [ style=bold color="green" fontcolor="black"] ++"lxc-ms_delete_0 18node3" [ style=bold color="green" fontcolor="black"] ++"lxc-ms_demote_0 lxc1" -> "lxc-ms_stop_0 lxc1" [ style = bold] ++"lxc-ms_demote_0 lxc1" -> "lxc-ms_stop_0 lxc2" [ style = bold] ++"lxc-ms_demote_0 lxc1" -> "lxc1_stop_0 18node1" [ style = bold] ++"lxc-ms_demote_0 lxc1" [ style=bold color="green" fontcolor="black"] ++"lxc-ms_demote_0 lxc2" -> "lxc-ms_stop_0 lxc1" [ style = bold] ++"lxc-ms_demote_0 lxc2" -> "lxc-ms_stop_0 lxc2" [ style = bold] ++"lxc-ms_demote_0 lxc2" -> "lxc2_stop_0 18node1" [ style = bold] ++"lxc-ms_demote_0 lxc2" [ style=bold color="green" fontcolor="black"] ++"lxc-ms_stop_0 lxc1" -> "all_stopped" [ style = bold] ++"lxc-ms_stop_0 lxc1" -> "lxc-ms_delete_0 18node1" [ style = bold] ++"lxc-ms_stop_0 lxc1" -> "lxc-ms_delete_0 18node2" [ style = bold] ++"lxc-ms_stop_0 lxc1" -> "lxc-ms_delete_0 18node3" [ style = bold] ++"lxc-ms_stop_0 lxc1" -> "lxc1_stop_0 18node1" [ style = bold] ++"lxc-ms_stop_0 lxc1" [ style=bold color="green" fontcolor="black"] ++"lxc-ms_stop_0 lxc2" -> "all_stopped" [ style = bold] ++"lxc-ms_stop_0 lxc2" -> "lxc-ms_delete_0 18node1" [ style = bold] ++"lxc-ms_stop_0 lxc2" -> "lxc-ms_delete_0 18node2" [ style = bold] ++"lxc-ms_stop_0 lxc2" -> "lxc-ms_delete_0 18node3" [ style = bold] ++"lxc-ms_stop_0 lxc2" -> "lxc2_stop_0 18node1" [ style = bold] ++"lxc-ms_stop_0 lxc2" [ style=bold color="green" fontcolor="black"] ++"lxc1_delete_0 18node1" [ style=bold color="green" fontcolor="black"] ++"lxc1_delete_0 18node2" [ style=bold color="green" fontcolor="black"] ++"lxc1_delete_0 18node3" [ style=bold color="green" fontcolor="black"] ++"lxc1_stop_0 18node1" -> "all_stopped" [ style = bold] ++"lxc1_stop_0 18node1" -> "container1_stop_0 18node1" [ style = bold] ++"lxc1_stop_0 18node1" -> "lxc1_delete_0 18node1" [ style = bold] ++"lxc1_stop_0 18node1" -> "lxc1_delete_0 18node2" [ style = bold] ++"lxc1_stop_0 18node1" -> "lxc1_delete_0 18node3" [ style = bold] ++"lxc1_stop_0 18node1" [ style=bold color="green" fontcolor="black"] ++"lxc2_delete_0 18node1" [ style=bold color="green" fontcolor="black"] ++"lxc2_delete_0 18node2" [ style=bold color="green" fontcolor="black"] ++"lxc2_delete_0 18node3" [ style=bold color="green" fontcolor="black"] ++"lxc2_stop_0 18node1" -> "all_stopped" [ style = bold] ++"lxc2_stop_0 18node1" -> "container2_stop_0 18node1" [ style = bold] ++"lxc2_stop_0 18node1" -> "lxc2_delete_0 18node1" [ style = bold] ++"lxc2_stop_0 18node1" -> "lxc2_delete_0 18node2" [ style = bold] ++"lxc2_stop_0 18node1" -> "lxc2_delete_0 18node3" [ style = bold] ++"lxc2_stop_0 18node1" [ style=bold color="green" fontcolor="black"] ++} +diff --git a/pengine/test10/whitebox-orphan-ms.exp b/pengine/test10/whitebox-orphan-ms.exp +new file mode 100644 +index 0000000..d36a9be +--- /dev/null ++++ b/pengine/test10/whitebox-orphan-ms.exp +@@ -0,0 +1,366 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/pengine/test10/whitebox-orphan-ms.pe.dot b/pengine/test10/whitebox-orphan-ms.pe.dot +new file mode 100644 +index 0000000..81c37eb +--- /dev/null ++++ b/pengine/test10/whitebox-orphan-ms.pe.dot +@@ -0,0 +1,69 @@ ++digraph "g" { ++"FencingFail_start_0 18node1" [ style=bold color="green" fontcolor="black"] ++"FencingFail_stop_0 18node3" -> "FencingFail_start_0 18node1" [ style = bold] ++"FencingFail_stop_0 18node3" -> "all_stopped" [ style = bold] ++"FencingFail_stop_0 18node3" [ style=bold color="green" fontcolor="black"] ++"all_stopped" [ style=bold color="green" fontcolor="orange"] ++"container1_delete_0 18node1" -> "container1_start_0 " [ style = dashed] ++"container1_delete_0 18node1" [ style=bold color="green" fontcolor="black"] ++"container1_delete_0 18node2" -> "container1_start_0 " [ style = dashed] ++"container1_delete_0 18node2" [ style=bold color="green" fontcolor="black"] ++"container1_delete_0 18node3" -> "container1_start_0 " [ style = dashed] ++"container1_delete_0 18node3" [ style=bold color="green" fontcolor="black"] ++"container1_start_0 " [ style=dashed color="red" fontcolor="black"] ++"container1_stop_0 18node1" -> "all_stopped" [ style = bold] ++"container1_stop_0 18node1" -> "container1_delete_0 18node1" [ style = bold] ++"container1_stop_0 18node1" -> "container1_delete_0 18node2" [ style = bold] ++"container1_stop_0 18node1" -> "container1_delete_0 18node3" [ style = bold] ++"container1_stop_0 18node1" -> "container1_start_0 " [ style = dashed] ++"container1_stop_0 18node1" [ style=bold color="green" fontcolor="black"] ++"container2_delete_0 18node1" [ style=bold color="green" fontcolor="black"] ++"container2_delete_0 18node2" [ style=bold color="green" fontcolor="black"] ++"container2_delete_0 18node3" [ style=bold color="green" fontcolor="black"] ++"container2_stop_0 18node1" -> "all_stopped" [ style = bold] ++"container2_stop_0 18node1" -> "container2_delete_0 18node1" [ style = bold] ++"container2_stop_0 18node1" -> "container2_delete_0 18node2" [ style = bold] ++"container2_stop_0 18node1" -> "container2_delete_0 18node3" [ style = bold] ++"container2_stop_0 18node1" [ style=bold color="green" fontcolor="black"] ++"lxc-ms_delete_0 18node1" [ style=bold color="green" fontcolor="black"] ++"lxc-ms_delete_0 18node2" [ style=bold color="green" fontcolor="black"] ++"lxc-ms_delete_0 18node3" [ style=bold color="green" fontcolor="black"] ++"lxc-ms_demote_0 lxc1" -> "lxc-ms_stop_0 lxc1" [ style = bold] ++"lxc-ms_demote_0 lxc1" -> "lxc-ms_stop_0 lxc2" [ style = bold] ++"lxc-ms_demote_0 lxc1" -> "lxc1_stop_0 18node1" [ style = bold] ++"lxc-ms_demote_0 lxc1" [ style=bold color="green" fontcolor="black"] ++"lxc-ms_demote_0 lxc2" -> "lxc-ms_stop_0 lxc1" [ style = bold] ++"lxc-ms_demote_0 lxc2" -> "lxc-ms_stop_0 lxc2" [ style = bold] ++"lxc-ms_demote_0 lxc2" -> "lxc2_stop_0 18node1" [ style = bold] ++"lxc-ms_demote_0 lxc2" [ style=bold color="green" fontcolor="black"] ++"lxc-ms_stop_0 lxc1" -> "all_stopped" [ style = bold] ++"lxc-ms_stop_0 lxc1" -> "lxc-ms_delete_0 18node1" [ style = bold] ++"lxc-ms_stop_0 lxc1" -> "lxc-ms_delete_0 18node2" [ style = bold] ++"lxc-ms_stop_0 lxc1" -> "lxc-ms_delete_0 18node3" [ style = bold] ++"lxc-ms_stop_0 lxc1" -> "lxc1_stop_0 18node1" [ style = bold] ++"lxc-ms_stop_0 lxc1" [ style=bold color="green" fontcolor="black"] ++"lxc-ms_stop_0 lxc2" -> "all_stopped" [ style = bold] ++"lxc-ms_stop_0 lxc2" -> "lxc-ms_delete_0 18node1" [ style = bold] ++"lxc-ms_stop_0 lxc2" -> "lxc-ms_delete_0 18node2" [ style = bold] ++"lxc-ms_stop_0 lxc2" -> "lxc-ms_delete_0 18node3" [ style = bold] ++"lxc-ms_stop_0 lxc2" -> "lxc2_stop_0 18node1" [ style = bold] ++"lxc-ms_stop_0 lxc2" [ style=bold color="green" fontcolor="black"] ++"lxc1_delete_0 18node1" [ style=bold color="green" fontcolor="black"] ++"lxc1_delete_0 18node2" [ style=bold color="green" fontcolor="black"] ++"lxc1_delete_0 18node3" [ style=bold color="green" fontcolor="black"] ++"lxc1_stop_0 18node1" -> "all_stopped" [ style = bold] ++"lxc1_stop_0 18node1" -> "container1_stop_0 18node1" [ style = bold] ++"lxc1_stop_0 18node1" -> "lxc1_delete_0 18node1" [ style = bold] ++"lxc1_stop_0 18node1" -> "lxc1_delete_0 18node2" [ style = bold] ++"lxc1_stop_0 18node1" -> "lxc1_delete_0 18node3" [ style = bold] ++"lxc1_stop_0 18node1" [ style=bold color="green" fontcolor="black"] ++"lxc2_delete_0 18node1" [ style=bold color="green" fontcolor="black"] ++"lxc2_delete_0 18node2" [ style=bold color="green" fontcolor="black"] ++"lxc2_delete_0 18node3" [ style=bold color="green" fontcolor="black"] ++"lxc2_stop_0 18node1" -> "all_stopped" [ style = bold] ++"lxc2_stop_0 18node1" -> "container2_stop_0 18node1" [ style = bold] ++"lxc2_stop_0 18node1" -> "lxc2_delete_0 18node1" [ style = bold] ++"lxc2_stop_0 18node1" -> "lxc2_delete_0 18node2" [ style = bold] ++"lxc2_stop_0 18node1" -> "lxc2_delete_0 18node3" [ style = bold] ++"lxc2_stop_0 18node1" [ style=bold color="green" fontcolor="black"] ++} +diff --git a/pengine/test10/whitebox-orphan-ms.scores b/pengine/test10/whitebox-orphan-ms.scores +new file mode 100644 +index 0000000..d968052 +--- /dev/null ++++ b/pengine/test10/whitebox-orphan-ms.scores +@@ -0,0 +1,105 @@ ++Allocation scores: ++clone_color: Connectivity allocation score on 18node1: 0 ++clone_color: Connectivity allocation score on 18node2: 0 ++clone_color: Connectivity allocation score on 18node3: 0 ++clone_color: master-1 allocation score on 18node1: 0 ++clone_color: master-1 allocation score on 18node2: 0 ++clone_color: master-1 allocation score on 18node3: 0 ++clone_color: master-1 allocation score on lxc1: -INFINITY ++clone_color: master-1 allocation score on lxc2: -INFINITY ++clone_color: ping-1:0 allocation score on 18node1: 1 ++clone_color: ping-1:0 allocation score on 18node2: 0 ++clone_color: ping-1:0 allocation score on 18node3: 0 ++clone_color: ping-1:1 allocation score on 18node1: 0 ++clone_color: ping-1:1 allocation score on 18node2: 1 ++clone_color: ping-1:1 allocation score on 18node3: 0 ++clone_color: ping-1:2 allocation score on 18node1: 0 ++clone_color: ping-1:2 allocation score on 18node2: 0 ++clone_color: ping-1:2 allocation score on 18node3: 1 ++clone_color: stateful-1:0 allocation score on 18node1: 11 ++clone_color: stateful-1:0 allocation score on 18node2: 0 ++clone_color: stateful-1:0 allocation score on 18node3: 0 ++clone_color: stateful-1:0 allocation score on lxc1: -INFINITY ++clone_color: stateful-1:0 allocation score on lxc2: -INFINITY ++clone_color: stateful-1:1 allocation score on 18node1: 0 ++clone_color: stateful-1:1 allocation score on 18node2: 6 ++clone_color: stateful-1:1 allocation score on 18node3: 0 ++clone_color: stateful-1:1 allocation score on lxc1: -INFINITY ++clone_color: stateful-1:1 allocation score on lxc2: -INFINITY ++clone_color: stateful-1:2 allocation score on 18node1: 0 ++clone_color: stateful-1:2 allocation score on 18node2: 0 ++clone_color: stateful-1:2 allocation score on 18node3: 6 ++clone_color: stateful-1:2 allocation score on lxc1: -INFINITY ++clone_color: stateful-1:2 allocation score on lxc2: -INFINITY ++group_color: group-1 allocation score on 18node1: 0 ++group_color: group-1 allocation score on 18node2: 0 ++group_color: group-1 allocation score on 18node3: 0 ++group_color: r192.168.122.87 allocation score on 18node1: 0 ++group_color: r192.168.122.87 allocation score on 18node2: 0 ++group_color: r192.168.122.87 allocation score on 18node3: 0 ++group_color: r192.168.122.88 allocation score on 18node1: 0 ++group_color: r192.168.122.88 allocation score on 18node2: 0 ++group_color: r192.168.122.88 allocation score on 18node3: 0 ++group_color: r192.168.122.89 allocation score on 18node1: 0 ++group_color: r192.168.122.89 allocation score on 18node2: 0 ++group_color: r192.168.122.89 allocation score on 18node3: 0 ++native_color: Fencing allocation score on 18node1: 0 ++native_color: Fencing allocation score on 18node2: 0 ++native_color: Fencing allocation score on 18node3: 0 ++native_color: FencingFail allocation score on 18node1: 0 ++native_color: FencingFail allocation score on 18node2: 0 ++native_color: FencingFail allocation score on 18node3: 0 ++native_color: FencingPass allocation score on 18node1: 0 ++native_color: FencingPass allocation score on 18node2: 0 ++native_color: FencingPass allocation score on 18node3: 0 ++native_color: lsb-dummy allocation score on 18node1: 0 ++native_color: lsb-dummy allocation score on 18node2: -INFINITY ++native_color: lsb-dummy allocation score on 18node3: -INFINITY ++native_color: migrator allocation score on 18node1: 1 ++native_color: migrator allocation score on 18node2: 0 ++native_color: migrator allocation score on 18node3: 0 ++native_color: ping-1:0 allocation score on 18node1: 1 ++native_color: ping-1:0 allocation score on 18node2: -INFINITY ++native_color: ping-1:0 allocation score on 18node3: -INFINITY ++native_color: ping-1:1 allocation score on 18node1: 0 ++native_color: ping-1:1 allocation score on 18node2: 1 ++native_color: ping-1:1 allocation score on 18node3: 0 ++native_color: ping-1:2 allocation score on 18node1: 0 ++native_color: ping-1:2 allocation score on 18node2: -INFINITY ++native_color: ping-1:2 allocation score on 18node3: 1 ++native_color: r192.168.122.87 allocation score on 18node1: 11 ++native_color: r192.168.122.87 allocation score on 18node2: -INFINITY ++native_color: r192.168.122.87 allocation score on 18node3: -INFINITY ++native_color: r192.168.122.88 allocation score on 18node1: 0 ++native_color: r192.168.122.88 allocation score on 18node2: -INFINITY ++native_color: r192.168.122.88 allocation score on 18node3: -INFINITY ++native_color: r192.168.122.89 allocation score on 18node1: 0 ++native_color: r192.168.122.89 allocation score on 18node2: -INFINITY ++native_color: r192.168.122.89 allocation score on 18node3: -INFINITY ++native_color: rsc_18node1 allocation score on 18node1: 100 ++native_color: rsc_18node1 allocation score on 18node2: 0 ++native_color: rsc_18node1 allocation score on 18node3: 0 ++native_color: rsc_18node2 allocation score on 18node1: 0 ++native_color: rsc_18node2 allocation score on 18node2: 100 ++native_color: rsc_18node2 allocation score on 18node3: 0 ++native_color: rsc_18node3 allocation score on 18node1: 0 ++native_color: rsc_18node3 allocation score on 18node2: 0 ++native_color: rsc_18node3 allocation score on 18node3: 100 ++native_color: stateful-1:0 allocation score on 18node1: 11 ++native_color: stateful-1:0 allocation score on 18node2: -INFINITY ++native_color: stateful-1:0 allocation score on 18node3: -INFINITY ++native_color: stateful-1:0 allocation score on lxc1: -INFINITY ++native_color: stateful-1:0 allocation score on lxc2: -INFINITY ++native_color: stateful-1:1 allocation score on 18node1: 0 ++native_color: stateful-1:1 allocation score on 18node2: 6 ++native_color: stateful-1:1 allocation score on 18node3: 0 ++native_color: stateful-1:1 allocation score on lxc1: -INFINITY ++native_color: stateful-1:1 allocation score on lxc2: -INFINITY ++native_color: stateful-1:2 allocation score on 18node1: 0 ++native_color: stateful-1:2 allocation score on 18node2: -INFINITY ++native_color: stateful-1:2 allocation score on 18node3: 6 ++native_color: stateful-1:2 allocation score on lxc1: -INFINITY ++native_color: stateful-1:2 allocation score on lxc2: -INFINITY ++stateful-1:0 promotion score on 18node1: 10 ++stateful-1:1 promotion score on 18node2: 5 ++stateful-1:2 promotion score on 18node3: 5 +diff --git a/pengine/test10/whitebox-orphan-ms.summary b/pengine/test10/whitebox-orphan-ms.summary +new file mode 100644 +index 0000000..30c6a3b +--- /dev/null ++++ b/pengine/test10/whitebox-orphan-ms.summary +@@ -0,0 +1,85 @@ ++ ++Current cluster status: ++Online: [ 18node1 18node2 18node3 ] ++Containers: [ lxc1:container1 lxc2:container2 ] ++ ++ Fencing (stonith:fence_xvm): Started 18node2 ++ FencingPass (stonith:fence_dummy): Started 18node3 ++ FencingFail (stonith:fence_dummy): Started 18node3 ++ rsc_18node1 (ocf::heartbeat:IPaddr2): Started 18node1 ++ rsc_18node2 (ocf::heartbeat:IPaddr2): Started 18node2 ++ rsc_18node3 (ocf::heartbeat:IPaddr2): Started 18node3 ++ migrator (ocf::pacemaker:Dummy): Started 18node1 ++ Clone Set: Connectivity [ping-1] ++ Started: [ 18node1 18node2 18node3 ] ++ Master/Slave Set: master-1 [stateful-1] ++ Masters: [ 18node1 ] ++ Slaves: [ 18node2 18node3 ] ++ Resource Group: group-1 ++ r192.168.122.87 (ocf::heartbeat:IPaddr2): Started 18node1 ++ r192.168.122.88 (ocf::heartbeat:IPaddr2): Started 18node1 ++ r192.168.122.89 (ocf::heartbeat:IPaddr2): Started 18node1 ++ lsb-dummy (lsb:/usr/share/pacemaker/tests/cts/LSBDummy): Started 18node1 ++ container2 (ocf::heartbeat:VirtualDomain): ORPHANED Started 18node1 ++ lxc1 (ocf::pacemaker:remote): ORPHANED Started 18node1 ++ lxc-ms (ocf::pacemaker:Stateful): ORPHANED Master [ lxc1 lxc2 ] ++ lxc2 (ocf::pacemaker:remote): ORPHANED Started 18node1 ++ container1 (ocf::heartbeat:VirtualDomain): ORPHANED Started 18node1 ++ ++Transition Summary: ++ * Move FencingFail (Started 18node3 -> 18node1) ++ * Stop container2 (18node1) ++ * Stop lxc1 (18node1) ++ * Demote lxc-ms (Master -> Stopped lxc1) ++ * Stop lxc2 (18node1) ++ * Stop container1 (18node1) ++ ++Executing cluster transition: ++ * Resource action: FencingFail stop on 18node3 ++ * Resource action: lxc-ms demote on lxc2 ++ * Resource action: lxc-ms demote on lxc1 ++ * Resource action: FencingFail start on 18node1 ++ * Resource action: lxc-ms stop on lxc2 ++ * Resource action: lxc-ms stop on lxc1 ++ * Resource action: lxc-ms delete on 18node3 ++ * Resource action: lxc-ms delete on 18node2 ++ * Resource action: lxc-ms delete on 18node1 ++ * Resource action: lxc2 stop on 18node1 ++ * Resource action: lxc2 delete on 18node3 ++ * Resource action: lxc2 delete on 18node2 ++ * Resource action: lxc2 delete on 18node1 ++ * Resource action: container2 stop on 18node1 ++ * Resource action: container2 delete on 18node3 ++ * Resource action: container2 delete on 18node2 ++ * Resource action: container2 delete on 18node1 ++ * Resource action: lxc1 stop on 18node1 ++ * Resource action: lxc1 delete on 18node3 ++ * Resource action: lxc1 delete on 18node2 ++ * Resource action: lxc1 delete on 18node1 ++ * Resource action: container1 stop on 18node1 ++ * Resource action: container1 delete on 18node3 ++ * Resource action: container1 delete on 18node2 ++ * Resource action: container1 delete on 18node1 ++ * Pseudo action: all_stopped ++ ++Revised cluster status: ++Online: [ 18node1 18node2 18node3 ] ++ ++ Fencing (stonith:fence_xvm): Started 18node2 ++ FencingPass (stonith:fence_dummy): Started 18node3 ++ FencingFail (stonith:fence_dummy): Started 18node1 ++ rsc_18node1 (ocf::heartbeat:IPaddr2): Started 18node1 ++ rsc_18node2 (ocf::heartbeat:IPaddr2): Started 18node2 ++ rsc_18node3 (ocf::heartbeat:IPaddr2): Started 18node3 ++ migrator (ocf::pacemaker:Dummy): Started 18node1 ++ Clone Set: Connectivity [ping-1] ++ Started: [ 18node1 18node2 18node3 ] ++ Master/Slave Set: master-1 [stateful-1] ++ Masters: [ 18node1 ] ++ Slaves: [ 18node2 18node3 ] ++ Resource Group: group-1 ++ r192.168.122.87 (ocf::heartbeat:IPaddr2): Started 18node1 ++ r192.168.122.88 (ocf::heartbeat:IPaddr2): Started 18node1 ++ r192.168.122.89 (ocf::heartbeat:IPaddr2): Started 18node1 ++ lsb-dummy (lsb:/usr/share/pacemaker/tests/cts/LSBDummy): Started 18node1 ++ +diff --git a/pengine/test10/whitebox-orphan-ms.xml b/pengine/test10/whitebox-orphan-ms.xml +new file mode 100644 +index 0000000..c9a62fa +--- /dev/null ++++ b/pengine/test10/whitebox-orphan-ms.xml +@@ -0,0 +1,436 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/pengine/test10/whitebox-start.exp b/pengine/test10/whitebox-start.exp +index 4dcfdc4..19cae49 100644 +--- a/pengine/test10/whitebox-start.exp ++++ b/pengine/test10/whitebox-start.exp +@@ -67,7 +67,7 @@ + + + +- ++ + + + +@@ -80,7 +80,7 @@ + + + +- ++ + + + +diff --git a/pengine/test10/whitebox-stop.exp b/pengine/test10/whitebox-stop.exp +index 643c94c..7720235 100644 +--- a/pengine/test10/whitebox-stop.exp ++++ b/pengine/test10/whitebox-stop.exp +@@ -87,7 +87,7 @@ + + + +- ++ + + + diff --git a/SOURCES/pacemaker-fix-setting-remote-node-attributes.patch b/SOURCES/pacemaker-fix-setting-remote-node-attributes.patch new file mode 100644 index 0000000..f87e9d3 --- /dev/null +++ b/SOURCES/pacemaker-fix-setting-remote-node-attributes.patch @@ -0,0 +1,446 @@ +commit d9b95435059189843e1fb7b1f7530fc163fdfc13 +Author: David Vossel +Date: Wed Sep 25 17:02:50 2013 -0400 + + properly set remote node attributes + +diff --git a/crmd/lrm.c b/crmd/lrm.c +index 0254a9f..7157e24 100644 +--- a/crmd/lrm.c ++++ b/crmd/lrm.c +@@ -367,7 +367,7 @@ lrm_state_verify_stopped(lrm_state_t * lrm_state, enum crmd_fsa_state cur_state, + } + + if (counter > 0) { +- do_crm_log(log_level, "%d pending LRM operations at %s%s", counter, when); ++ do_crm_log(log_level, "%d pending LRM operations at %s", counter, when); + + if (cur_state == S_TERMINATE || !is_set(fsa_input_register, R_SENT_RSC_STOP)) { + g_hash_table_iter_init(&gIter, lrm_state->pending_ops); +diff --git a/crmd/membership.c b/crmd/membership.c +index 370d1a2..e2bcd45 100644 +--- a/crmd/membership.c ++++ b/crmd/membership.c +@@ -260,6 +260,13 @@ populate_cib_nodes(enum node_update_flags flags, const char *source) + do_update_node_cib(node, flags, node_list, source); + } + ++ if (crm_remote_peer_cache) { ++ g_hash_table_iter_init(&iter, crm_remote_peer_cache); ++ while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) { ++ do_update_node_cib(node, flags, node_list, source); ++ } ++ } ++ + fsa_cib_update(XML_CIB_TAG_STATUS, node_list, call_options, call_id, NULL); + fsa_register_cib_callback(call_id, FALSE, NULL, crmd_node_update_complete); + last_peer_update = call_id; +diff --git a/crmd/messages.c b/crmd/messages.c +index 9aa69cc..057383a 100644 +--- a/crmd/messages.c ++++ b/crmd/messages.c +@@ -930,7 +930,7 @@ send_msg_via_ipc(xmlNode * msg, const char *sys) + crmd_proxy_send(sys, msg); + + } else { +- crm_err("Unknown Sub-system (%s)... discarding message.", crm_str(sys)); ++ crm_debug("Unknown Sub-system (%s)... discarding message.", crm_str(sys)); + send_ok = FALSE; + } + +diff --git a/crmd/pengine.c b/crmd/pengine.c +index 5546d7e..2f3eba8 100644 +--- a/crmd/pengine.c ++++ b/crmd/pengine.c +@@ -271,6 +271,9 @@ do_pe_invoke_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void + + CRM_LOG_ASSERT(output != NULL); + ++ /* refresh our remote-node cache when the pengine is invoked */ ++ crm_remote_peer_cache_refresh(output); ++ + crm_xml_add(output, XML_ATTR_DC_UUID, fsa_our_uuid); + crm_xml_add_int(output, XML_ATTR_HAVE_QUORUM, fsa_has_quorum); + +diff --git a/crmd/remote_lrmd_ra.c b/crmd/remote_lrmd_ra.c +index d38d7f0..42ea043 100644 +--- a/crmd/remote_lrmd_ra.c ++++ b/crmd/remote_lrmd_ra.c +@@ -333,7 +333,10 @@ remote_lrm_op_callback(lrmd_event_data_t * op) + + } else { + /* make sure we have a clean status section to start with */ ++ lrm_state_reset_tables(lrm_state); + remote_init_cib_status(lrm_state); ++ erase_status_tag(lrm_state->node_name, XML_CIB_TAG_LRM, cib_scope_local); ++ erase_status_tag(lrm_state->node_name, XML_TAG_TRANSIENT_NODEATTRS, cib_scope_local); + + cmd->rc = PCMK_EXECRA_OK; + cmd->op_status = PCMK_LRM_OP_DONE; +@@ -430,15 +433,6 @@ handle_remote_ra_exec(gpointer user_data) + g_list_free_1(first); + + if (!strcmp(cmd->action, "start") || !strcmp(cmd->action, "migrate_from")) { +- xmlNode *status = create_xml_node(NULL, XML_CIB_TAG_STATE); +- +- /* clear node status in cib */ +- crm_xml_add(status, XML_ATTR_ID, lrm_state->node_name); +- lrm_state_reset_tables(lrm_state); +- fsa_cib_delete(XML_CIB_TAG_STATUS, status, cib_quorum_override, rc, NULL); +- crm_info("Forced a remote LRM refresh before connection start: call=%d", rc); +- crm_log_xml_trace(status, "CLEAR LRM"); +- free_xml(status); + + rc = handle_remote_ra_start(lrm_state, cmd, cmd->timeout); + if (rc == 0) { +diff --git a/crmd/te_utils.c b/crmd/te_utils.c +index 54fae04..239af63 100644 +--- a/crmd/te_utils.c ++++ b/crmd/te_utils.c +@@ -390,16 +390,7 @@ abort_transition_graph(int abort_priority, enum transition_action abort_action, + if (safe_str_eq(XML_CIB_TAG_STATE, kind) + || safe_str_eq(XML_CIB_TAG_NODE, kind)) { + +- if (crm_is_true(crm_element_value(search, XML_NODE_IS_REMOTE))) { +- /* Remote node uname and uuids are the same. +- * We also don't want them to be present in the +- * peer cache, so we shouldn't look them up with +- * crm_peer_uname() +- */ +- uname = ID(search); +- } else { +- uname = crm_peer_uname(ID(search)); +- } ++ uname = crm_peer_uname(ID(search)); + break; + } + search = search->parent; +diff --git a/include/crm/cluster.h b/include/crm/cluster.h +index 54b7f58..960c3d0 100644 +--- a/include/crm/cluster.h ++++ b/include/crm/cluster.h +@@ -32,6 +32,7 @@ + + extern gboolean crm_have_quorum; + extern GHashTable *crm_peer_cache; ++extern GHashTable *crm_remote_peer_cache; + extern unsigned long long crm_peer_seq; + + # ifndef CRM_SERVICE +@@ -55,12 +56,16 @@ enum crm_join_phase + }; + + /* *INDENT-ON* */ ++enum crm_node_flags ++{ ++ crm_remote_node = 0x0001, ++}; + + typedef struct crm_peer_node_s { + uint32_t id; /* Only used by corosync derivatives */ + uint64_t born; /* Only used by heartbeat and the legacy plugin */ + uint64_t last_seen; +- uint64_t flags; /* Unused, but might be a good place to specify 'remote' */ ++ uint64_t flags; /* Specified by crm_node_flags enum */ + + int32_t votes; /* Only used by the legacy plugin */ + uint32_t processes; +@@ -124,11 +129,25 @@ enum crm_ais_msg_types { + crm_msg_pe = 8, + crm_msg_stonith_ng = 9, + }; ++ ++/* used with crm_get_peer_full */ ++enum crm_get_peer_flags { ++ CRM_GET_PEER_CLUSTER = 0x0001, ++ CRM_GET_PEER_REMOTE = 0x0002, ++}; + /* *INDENT-ON* */ + + gboolean send_cluster_message(crm_node_t * node, enum crm_ais_msg_types service, + xmlNode * data, gboolean ordered); + ++ ++/* Initialize and refresh the remote peer cache from a cib config */ ++void crm_remote_peer_cache_refresh(xmlNode *cib); ++ ++/* allows filtering of remote and cluster nodes using crm_get_peer_flags */ ++crm_node_t *crm_get_peer_full(unsigned int id, const char *uname, int flags); ++ ++/* only searches cluster nodes */ + crm_node_t *crm_get_peer(unsigned int id, const char *uname); + + guint crm_active_peers(void); +diff --git a/lib/cib/cib_attrs.c b/lib/cib/cib_attrs.c +index 4af077c..d1e1b74 100644 +--- a/lib/cib/cib_attrs.c ++++ b/lib/cib/cib_attrs.c +@@ -430,6 +430,8 @@ get_remote_node_uuid(cib_t * the_cib, const char *uname, char **uuid) + cib_sync_call | cib_scope_local | cib_xpath, NULL); + free(xpath_string); + free(xml_search); ++ xml_search = NULL; ++ xpath_string = NULL; + + if (rc != pcmk_ok) { + len = strlen(REMOTE_NODE_XPATH2) + strlen(uname) + 1; +diff --git a/lib/cluster/cluster.c b/lib/cluster/cluster.c +index 5820c8d..5b743f9 100644 +--- a/lib/cluster/cluster.c ++++ b/lib/cluster/cluster.c +@@ -361,6 +361,11 @@ crm_peer_uname(const char *uuid) + + CRM_CHECK(uuid != NULL, return NULL); + ++ /* remote nodes have the same uname and uuid */ ++ if (g_hash_table_lookup(crm_remote_peer_cache, uuid)) { ++ return uuid; ++ } ++ + /* avoid blocking calls where possible */ + g_hash_table_iter_init(&iter, crm_peer_cache); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) { +diff --git a/lib/cluster/membership.c b/lib/cluster/membership.c +index bc1684e..e3082b4 100644 +--- a/lib/cluster/membership.c ++++ b/lib/cluster/membership.c +@@ -33,9 +33,56 @@ + #include + + GHashTable *crm_peer_cache = NULL; ++GHashTable *crm_remote_peer_cache = NULL; + unsigned long long crm_peer_seq = 0; + gboolean crm_have_quorum = FALSE; + ++static void ++remote_cache_refresh_helper(xmlNode *cib, const char *xpath, const char *field, int flags) ++{ ++ const char *remote = NULL; ++ crm_node_t *node = NULL; ++ xmlXPathObjectPtr xpathObj = NULL; ++ int max = 0; ++ int lpc = 0; ++ ++ xpathObj = xpath_search(cib, xpath); ++ max = numXpathResults(xpathObj); ++ for (lpc = 0; lpc < max; lpc++) { ++ xmlNode *xml = getXpathResult(xpathObj, lpc); ++ ++ CRM_CHECK(xml != NULL, continue); ++ ++ remote = crm_element_value(xml, field); ++ if (remote) { ++ crm_trace("added %s to remote cache", remote); ++ node = calloc(1, sizeof(crm_node_t)); ++ node->flags = flags; ++ CRM_ASSERT(node); ++ node->uname = strdup(remote); ++ node->uuid = strdup(remote); ++ node->state = strdup(CRM_NODE_MEMBER); ++ g_hash_table_replace(crm_remote_peer_cache, node->uname, node); ++ } ++ } ++ freeXpathObject(xpathObj); ++} ++ ++void crm_remote_peer_cache_refresh(xmlNode *cib) ++{ ++ const char *xpath = NULL; ++ ++ g_hash_table_remove_all(crm_remote_peer_cache); ++ ++ /* remote nodes associated with a cluster resource */ ++ xpath = "//" XML_TAG_CIB "//" XML_CIB_TAG_CONFIGURATION "//" XML_CIB_TAG_RESOURCE "//" XML_TAG_META_SETS "//" XML_CIB_TAG_NVPAIR "[@name='remote-node']"; ++ remote_cache_refresh_helper(cib, xpath, "value", crm_remote_node); ++ ++ /* remote nodes seen in the status section */ ++ xpath = "//" XML_TAG_CIB "//" XML_CIB_TAG_STATUS "//" XML_CIB_TAG_STATE "[@remote_node='true']"; ++ remote_cache_refresh_helper(cib, xpath, "id", crm_remote_node); ++} ++ + gboolean + crm_is_peer_active(const crm_node_t * node) + { +@@ -146,6 +193,10 @@ crm_peer_init(void) + if (crm_peer_cache == NULL) { + crm_peer_cache = g_hash_table_new_full(crm_str_hash, g_str_equal, free, destroy_crm_node); + } ++ ++ if (crm_remote_peer_cache == NULL) { ++ crm_remote_peer_cache = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, destroy_crm_node); ++ } + } + + void +@@ -156,6 +207,12 @@ crm_peer_destroy(void) + g_hash_table_destroy(crm_peer_cache); + crm_peer_cache = NULL; + } ++ ++ if (crm_remote_peer_cache != NULL) { ++ crm_trace("Destroying remote peer cache with %d members", g_hash_table_size(crm_remote_peer_cache)); ++ g_hash_table_destroy(crm_remote_peer_cache); ++ crm_remote_peer_cache = NULL; ++ } + } + + void (*crm_status_callback) (enum crm_status_type, crm_node_t *, const void *) = NULL; +@@ -186,6 +243,25 @@ static gboolean crm_hash_find_by_data(gpointer key, gpointer value, gpointer use + return FALSE; + } + ++crm_node_t * ++crm_get_peer_full(unsigned int id, const char *uname, int flags) ++{ ++ crm_node_t *node = NULL; ++ ++ CRM_ASSERT(id > 0 || uname != NULL); ++ ++ crm_peer_init(); ++ ++ if (flags & CRM_GET_PEER_REMOTE) { ++ node = g_hash_table_lookup(crm_remote_peer_cache, uname); ++ } ++ ++ if (node == NULL && (flags & CRM_GET_PEER_CLUSTER)) { ++ node = crm_get_peer(id, uname); ++ } ++ return node; ++} ++ + /* coverity[-alloc] Memory is referenced in one or both hashtables */ + crm_node_t * + crm_get_peer(unsigned int id, const char *uname) +diff --git a/lib/lrmd/lrmd_client.c b/lib/lrmd/lrmd_client.c +index bdaf18c..e577293 100644 +--- a/lib/lrmd/lrmd_client.c ++++ b/lib/lrmd/lrmd_client.c +@@ -89,6 +89,11 @@ typedef struct lrmd_private_s { + gnutls_psk_client_credentials_t psk_cred_c; + + int sock; ++ /* since tls requires a round trip across the network for a ++ * request/reply, there are times where we just want to be able ++ * to send a request from the client and not wait around (or even care ++ * about) what the reply is. */ ++ int expected_late_replies; + GList *pending_notify; + crm_trigger_t *process_notify; + #endif +@@ -241,9 +246,7 @@ lrmd_dispatch_internal(lrmd_t * lrmd, xmlNode * msg) + /* this is proxy business */ + lrmd_internal_proxy_dispatch(lrmd, msg); + return 1; +- } +- +- if (!native->callback) { ++ } else if (!native->callback) { + /* no callback set */ + crm_trace("notify event received but client has not set callback"); + return 1; +@@ -371,7 +374,19 @@ lrmd_tls_dispatch(gpointer userdata) + xml = crm_remote_parse_buffer(native->remote); + } + while (xml) { +- lrmd_dispatch_internal(lrmd, xml); ++ const char *msg_type = crm_element_value(xml, F_LRMD_REMOTE_MSG_TYPE); ++ if (safe_str_eq(msg_type, "notify")) { ++ lrmd_dispatch_internal(lrmd, xml); ++ } else if (safe_str_eq(msg_type, "reply")) { ++ if (native->expected_late_replies > 0) { ++ native->expected_late_replies--; ++ } else { ++ int reply_id = 0; ++ crm_element_value_int(xml, F_LRMD_CALLID, &reply_id); ++ /* if this happens, we want to know about it */ ++ crm_err("Got outdated reply %d", reply_id); ++ } ++ } + free_xml(xml); + xml = crm_remote_parse_buffer(native->remote); + } +@@ -617,7 +632,11 @@ lrmd_tls_recv_reply(lrmd_t * lrmd, int total_timeout, int expected_reply_id, int + free_xml(xml); + xml = NULL; + } else if (reply_id != expected_reply_id) { +- crm_err("Got outdated reply, expected id %d got id %d", expected_reply_id, reply_id); ++ if (native->expected_late_replies > 0) { ++ native->expected_late_replies--; ++ } else { ++ crm_err("Got outdated reply, expected id %d got id %d", expected_reply_id, reply_id); ++ } + free_xml(xml); + xml = NULL; + } +@@ -724,6 +743,12 @@ lrmd_send_xml_no_reply(lrmd_t * lrmd, xmlNode * msg) + #ifdef HAVE_GNUTLS_GNUTLS_H + case CRM_CLIENT_TLS: + rc = lrmd_tls_send(lrmd, msg); ++ if (rc == pcmk_ok) { ++ /* we don't want to wait around for the reply, but ++ * since the request/reply protocol needs to behave the same ++ * as libqb, a reply will eventually come later anyway. */ ++ native->expected_late_replies++; ++ } + break; + #endif + default: +diff --git a/lrmd/ipc_proxy.c b/lrmd/ipc_proxy.c +index bbf9b24..3a51a5b 100644 +--- a/lrmd/ipc_proxy.c ++++ b/lrmd/ipc_proxy.c +@@ -313,6 +313,8 @@ ipc_proxy_remove_provider(crm_client_t *ipc_proxy) + GHashTableIter iter; + crm_client_t *ipc_client = NULL; + char *key = NULL; ++ GList *remove_these = NULL; ++ GListPtr gIter = NULL; + + if (ipc_providers == NULL) { + return; +@@ -326,9 +328,19 @@ ipc_proxy_remove_provider(crm_client_t *ipc_proxy) + if (safe_str_eq(proxy_id, ipc_proxy->id)) { + crm_info("ipc proxy connection for client %s pid %d destroyed because cluster node disconnected.", + ipc_client->id, ipc_client->pid); +- qb_ipcs_disconnect(ipc_client->ipcs); ++ /* we can't remove during the iteration, so copy items ++ * to a list we can destroy later */ ++ remove_these = g_list_append(remove_these, ipc_client); + } + } ++ ++ for (gIter = remove_these; gIter != NULL; gIter = gIter->next) { ++ ipc_client = gIter->data; ++ qb_ipcs_disconnect(ipc_client->ipcs); ++ } ++ ++ /* just frees the list, not the elements in the list */ ++ g_list_free(remove_these); + } + + void +diff --git a/lrmd/lrmd.c b/lrmd/lrmd.c +index a4747cb..b5bbea0 100644 +--- a/lrmd/lrmd.c ++++ b/lrmd/lrmd.c +@@ -1297,6 +1297,7 @@ process_lrmd_message(crm_client_t * client, uint32_t id, xmlNode * request) + do_reply = 1; + } else if (crm_str_eq(op, LRMD_OP_POKE, TRUE)) { + do_notify = 1; ++ do_reply = 1; + } else { + rc = -EOPNOTSUPP; + do_reply = 1; +diff --git a/pengine/allocate.c b/pengine/allocate.c +index cf8f4d4..bfa8e7b 100644 +--- a/pengine/allocate.c ++++ b/pengine/allocate.c +@@ -1578,6 +1578,8 @@ apply_remote_node_ordering(pe_working_set_t *data_set) + container = remote_rsc->container; + if (safe_str_eq(action->task, "monitor") || + safe_str_eq(action->task, "start") || ++ safe_str_eq(action->task, "promote") || ++ safe_str_eq(action->task, "demote") || + safe_str_eq(action->task, CRM_OP_LRM_REFRESH) || + safe_str_eq(action->task, CRM_OP_CLEAR_FAILCOUNT) || + safe_str_eq(action->task, "delete")) { diff --git a/SOURCES/pacemaker-fix_cib_correctly_log_short-form_xml_diffs.patch b/SOURCES/pacemaker-fix_cib_correctly_log_short-form_xml_diffs.patch new file mode 100644 index 0000000..92edab1 --- /dev/null +++ b/SOURCES/pacemaker-fix_cib_correctly_log_short-form_xml_diffs.patch @@ -0,0 +1,41 @@ +commit 5c055e09858a257d50f2669016da01b808557b08 +Author: Andrew Beekhof +Date: Wed Aug 7 13:32:18 2013 +1000 + + Fix: cib: Correctly log short-form xml diffs + +diff --git a/lib/common/xml.c b/lib/common/xml.c +index d467ce4..25096a6 100644 +--- a/lib/common/xml.c ++++ b/lib/common/xml.c +@@ -1063,14 +1063,6 @@ log_data_element(int log_level, const char *file, const char *function, int line + do_crm_log_alias(log_level, file, function, line, "%s: %s", prefix, + "No data to dump as XML"); + return; +- +- } else if (is_set(options, xml_log_option_diff_short) +- && is_not_set(options, xml_log_option_diff_all)) { +- /* Still searching for the actual change */ +- for (a_child = __xml_first_child(data); a_child != NULL; a_child = __xml_next(a_child)) { +- log_data_element(log_level, file, function, line, prefix, a_child, depth + 1, options); +- } +- return; + } + + name = crm_element_name(data); +@@ -1092,6 +1084,15 @@ log_data_element(int log_level, const char *file, const char *function, int line + } + } + ++ if (is_set(options, xml_log_option_diff_short) ++ && is_not_set(options, xml_log_option_diff_all)) { ++ /* Still searching for the actual change */ ++ for (a_child = __xml_first_child(data); a_child != NULL; a_child = __xml_next(a_child)) { ++ log_data_element(log_level, file, function, line, prefix, a_child, depth + 1, options); ++ } ++ return; ++ } ++ + insert_prefix(options, &buffer, &offset, &max, depth); + if(data->type == XML_COMMENT_NODE) { + buffer_print(buffer, max, offset, "