diff --git a/crmd/lrm.c b/crmd/lrm.c index 07e8e702abb..9068652e488 100644 --- a/crmd/lrm.c +++ b/crmd/lrm.c @@ -37,6 +37,8 @@ #define START_DELAY_THRESHOLD 5 * 60 * 1000 #define MAX_LRM_REG_FAILS 30 +#define s_if_plural(i) (((i) == 1)? "" : "s") + struct delete_event_s { int rc; const char *rsc; @@ -372,8 +374,10 @@ do_lrm_control(long long action, if (ret != pcmk_ok) { if (lrm_state->num_lrm_register_fails < MAX_LRM_REG_FAILS) { - crm_warn("Failed to sign on to the LRM %d" - " (%d max) times", lrm_state->num_lrm_register_fails, MAX_LRM_REG_FAILS); + crm_warn("Failed to connect to the LRM %d time%s (%d max)", + lrm_state->num_lrm_register_fails, + s_if_plural(lrm_state->num_lrm_register_fails), + MAX_LRM_REG_FAILS); crm_timer_start(wait_timer); crmd_fsa_stall(FALSE); @@ -382,8 +386,9 @@ do_lrm_control(long long action, } if (ret != pcmk_ok) { - crm_err("Failed to sign on to the LRM %d" " (max) times", - lrm_state->num_lrm_register_fails); + crm_err("Failed to connect to the LRM the max allowed %d time%s", + lrm_state->num_lrm_register_fails, + s_if_plural(lrm_state->num_lrm_register_fails)); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); return; } @@ -425,8 +430,8 @@ lrm_state_verify_stopped(lrm_state_t * lrm_state, enum crmd_fsa_state cur_state, guint nremaining = g_hash_table_size(lrm_state->pending_ops); if (removed || nremaining) { - crm_notice("Stopped %u recurring operations at %s (%u operations remaining)", - removed, when, nremaining); + crm_notice("Stopped %u recurring operation%s at %s (%u remaining)", + removed, s_if_plural(removed), when, nremaining); } } @@ -441,7 +446,8 @@ 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", counter, when); + do_crm_log(log_level, "%d pending LRM operation%s at %s", + counter, s_if_plural(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); @@ -459,7 +465,7 @@ lrm_state_verify_stopped(lrm_state_t * lrm_state, enum crmd_fsa_state cur_state, return rc; } - if (cur_state == S_TERMINATE || is_set(fsa_input_register, R_SHUTDOWN)) { + if (is_set(fsa_input_register, R_SHUTDOWN)) { /* At this point we're not waiting, we're just shutting down */ when = "shutdown"; } @@ -472,7 +478,11 @@ lrm_state_verify_stopped(lrm_state_t * lrm_state, enum crmd_fsa_state cur_state, } counter++; - crm_trace("Found %s active", entry->id); + if (log_level == LOG_ERR) { + crm_info("Found %s active at %s", entry->id, when); + } else { + crm_trace("Found %s active at %s", entry->id, when); + } if (lrm_state->pending_ops) { GHashTableIter hIter; @@ -488,7 +498,8 @@ lrm_state_verify_stopped(lrm_state_t * lrm_state, enum crmd_fsa_state cur_state, } if (counter) { - crm_err("%d resources were active at %s.", counter, when); + crm_err("%d resource%s active at %s", + counter, (counter == 1)? " was" : "s were", when); } return rc; @@ -1489,8 +1500,8 @@ do_lrm_invoke(long long action, lrm_state = lrm_state_find(target_node); if (lrm_state == NULL && is_remote_node) { - crm_err("no lrmd connection for remote node %s found on cluster node %s. Can not process request.", - target_node, fsa_our_uname); + crm_err("Failing action because remote node %s has no connection to cluster node %s", + target_node, fsa_our_uname); /* The action must be recorded here and in the CIB as failed */ synthesize_lrmd_failure(NULL, input->xml, PCMK_OCF_CONNECTION_DIED); @@ -1785,7 +1796,7 @@ do_lrm_invoke(long long action, lrmd_free_rsc_info(rsc); } else { - crm_err("Operation was neither a lrm_query, nor a rsc op. %s", crm_str(crm_op)); + crm_err("Cannot perform operation %s of unknown type", crm_str(crm_op)); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } } @@ -2108,8 +2119,8 @@ do_lrm_rsc_op(lrm_state_t * lrm_state, lrmd_rsc_info_t * rsc, const char *operat lrm_state->pending_ops, stop_recurring_action_by_rsc, &data); if (removed) { - crm_debug("Stopped %u recurring operations in preparation for %s_%s_%d", - removed, rsc->id, operation, op->interval); + crm_debug("Stopped %u recurring operation%s in preparation for %s_%s_%d", + removed, s_if_plural(removed), rsc->id, operation, op->interval); } } diff --git a/crmd/te_actions.c b/crmd/te_actions.c index 01538afdd5a..0b881cbbf74 100644 --- a/crmd/te_actions.c +++ b/crmd/te_actions.c @@ -292,8 +292,6 @@ cib_action_update(crm_action_t * action, int status, int op_rc) int rc = pcmk_ok; - const char *name = NULL; - const char *value = NULL; const char *rsc_id = NULL; const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); @@ -341,15 +339,10 @@ cib_action_update(crm_action_t * action, int status, int op_rc) rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCE); crm_xml_add(rsc, XML_ATTR_ID, rsc_id); - name = XML_ATTR_TYPE; - value = crm_element_value(action_rsc, name); - crm_xml_add(rsc, name, value); - name = XML_AGENT_ATTR_CLASS; - value = crm_element_value(action_rsc, name); - crm_xml_add(rsc, name, value); - name = XML_AGENT_ATTR_PROVIDER; - value = crm_element_value(action_rsc, name); - crm_xml_add(rsc, name, value); + + crm_copy_xml_element(action_rsc, rsc, XML_ATTR_TYPE); + crm_copy_xml_element(action_rsc, rsc, XML_AGENT_ATTR_CLASS); + crm_copy_xml_element(action_rsc, rsc, XML_AGENT_ATTR_PROVIDER); op = convert_graph_action(NULL, action, status, op_rc); op->call_id = -1; diff --git a/doc/Pacemaker_Remote/en-US/Ch-Intro.txt b/doc/Pacemaker_Remote/en-US/Ch-Intro.txt index 72bd15d9d01..caa8da2448e 100644 --- a/doc/Pacemaker_Remote/en-US/Ch-Intro.txt +++ b/doc/Pacemaker_Remote/en-US/Ch-Intro.txt @@ -107,6 +107,9 @@ version): * Support for transient node attributes * Support for clusters with mixed endian architectures +.1.1.10 +* remote-connect-timeout for guest nodes + .1.1.9 * Initial version to include pacemaker_remote * Limited to guest nodes in KVM/LXC environments using only IPv4; diff --git a/include/crm/common/xml.h b/include/crm/common/xml.h index 150055b0593..a9489150e9f 100644 --- a/include/crm/common/xml.h +++ b/include/crm/common/xml.h @@ -210,6 +210,24 @@ crm_element_name(xmlNode *xml) const char *crm_element_value(xmlNode * data, const char *name); +/*! + * \brief Copy an element from one XML object to another + * + * \param[in] obj1 Source XML + * \param[in,out] obj2 Destination XML + * \param[in] element Name of element to copy + * + * \return Pointer to copied value (from source) + */ +static inline const char * +crm_copy_xml_element(xmlNode *obj1, xmlNode *obj2, const char *element) +{ + const char *value = crm_element_value(obj1, element); + + crm_xml_add(obj2, element, value); + return value; +} + void xml_validate(const xmlNode * root); gboolean xml_has_children(const xmlNode * root); diff --git a/tools/Makefile.am b/tools/Makefile.am index b0a2aff3fb3..c88766dd1a3 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -87,7 +87,7 @@ crm_simulate_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/transition/libtransitioner.la \ $(COMMONLIBS) -crm_diff_SOURCES = xml_diff.c +crm_diff_SOURCES = crm_diff.c crm_diff_LDADD = $(COMMONLIBS) crm_mon_SOURCES = crm_mon.c diff --git a/tools/xml_diff.c b/tools/crm_diff.c similarity index 59% rename from tools/xml_diff.c rename to tools/crm_diff.c index cd3cb2915d7..6a65aafa2f7 100644 --- a/tools/xml_diff.c +++ b/tools/crm_diff.c @@ -68,6 +68,155 @@ static struct crm_option long_options[] = { }; /* *INDENT-ON* */ +static void +print_patch(xmlNode *patch) +{ + char *buffer = dump_xml_formatted(patch); + + printf("%s\n", crm_str(buffer)); + free(buffer); + fflush(stdout); +} + +static int +apply_patch(xmlNode *input, xmlNode *patch, gboolean as_cib) +{ + int rc; + xmlNode *output = copy_xml(input); + + rc = xml_apply_patchset(output, patch, as_cib); + if (rc != pcmk_ok) { + fprintf(stderr, "Could not apply patch: %s\n", pcmk_strerror(rc)); + free_xml(output); + return rc; + } + + if (output != NULL) { + const char *version; + char *buffer; + + print_patch(output); + free_xml(output); + + version = crm_element_value(output, XML_ATTR_CRM_VERSION); + buffer = calculate_xml_versioned_digest(output, FALSE, TRUE, version); + crm_trace("Digest: %s\n", crm_str(buffer)); + free(buffer); + } + return pcmk_ok; +} + +static void +log_patch_cib_versions(xmlNode *patch) +{ + int add[] = { 0, 0, 0 }; + int del[] = { 0, 0, 0 }; + + const char *fmt = NULL; + const char *digest = NULL; + + xml_patch_versions(patch, add, del); + fmt = crm_element_value(patch, "format"); + digest = crm_element_value(patch, XML_ATTR_DIGEST); + + if (add[2] != del[2] || add[1] != del[1] || add[0] != del[0]) { + crm_info("Patch: --- %d.%d.%d %s", del[0], del[1], del[2], fmt); + crm_info("Patch: +++ %d.%d.%d %s", add[0], add[1], add[2], digest); + } +} + +static void +strip_patch_cib_version(xmlNode *patch, const char **vfields, size_t nvfields) +{ + int format = 1; + + crm_element_value_int(patch, "format", &format); + if (format == 2) { + xmlNode *version_xml = find_xml_node(patch, "version", FALSE); + + if (version_xml) { + free_xml(version_xml); + } + + } else { + int i = 0; + + const char *tags[] = { + XML_TAG_DIFF_REMOVED, + XML_TAG_DIFF_ADDED, + }; + + for (i = 0; i < DIMOF(tags); i++) { + xmlNode *tmp = NULL; + int lpc; + + tmp = find_xml_node(patch, tags[i], FALSE); + if (tmp) { + for (lpc = 0; lpc < nvfields; lpc++) { + xml_remove_prop(tmp, vfields[lpc]); + } + + tmp = find_xml_node(tmp, XML_TAG_CIB, FALSE); + if (tmp) { + for (lpc = 0; lpc < nvfields; lpc++) { + xml_remove_prop(tmp, vfields[lpc]); + } + } + } + } + } +} + +static int +generate_patch(xmlNode *object_1, xmlNode *object_2, const char *xml_file_2, + gboolean as_cib, gboolean no_version) +{ + xmlNode *output = NULL; + + const char *vfields[] = { + XML_ATTR_GENERATION_ADMIN, + XML_ATTR_GENERATION, + XML_ATTR_NUMUPDATES, + }; + + /* If we're ignoring the version, make the version information + * identical, so it isn't detected as a change. */ + if (no_version) { + int lpc; + + for (lpc = 0; lpc < DIMOF(vfields); lpc++) { + crm_copy_xml_element(object_1, object_2, vfields[lpc]); + } + } + + xml_track_changes(object_2, NULL, object_2, FALSE); + xml_calculate_changes(object_1, object_2); + crm_log_xml_debug(object_2, (xml_file_2? xml_file_2: "target")); + + output = xml_create_patchset(0, object_1, object_2, NULL, FALSE); + + xml_log_changes(LOG_INFO, __FUNCTION__, object_2); + xml_accept_changes(object_2); + + if (output == NULL) { + return pcmk_ok; + } + + patchset_process_digest(output, object_1, object_2, as_cib); + + if (as_cib) { + log_patch_cib_versions(output); + + } else if (no_version) { + strip_patch_cib_version(output, vfields, DIMOF(vfields)); + } + + xml_log_patchset(LOG_NOTICE, __FUNCTION__, output); + print_patch(output); + free_xml(output); + return 1; +} + int main(int argc, char **argv) { @@ -79,9 +228,9 @@ main(int argc, char **argv) gboolean no_version = FALSE; int argerr = 0; int flag; + int rc = pcmk_ok; xmlNode *object_1 = NULL; xmlNode *object_2 = NULL; - xmlNode *output = NULL; const char *xml_file_1 = NULL; const char *xml_file_2 = NULL; @@ -89,8 +238,8 @@ main(int argc, char **argv) crm_log_cli_init("crm_diff"); crm_set_options(NULL, "original_xml operation [options]", long_options, - "A utility for comparing Pacemaker configurations (XML format)\n\n" - "The tool produces a custom (diff-like) output which it can also apply like a patch\n"); + "crm_diff can compare two Pacemaker configurations (in XML format) to\n" + "produce a custom diff-like output, or apply such an output as a patch\n"); if (argc < 2) { crm_help('?', EX_USAGE); @@ -137,7 +286,7 @@ main(int argc, char **argv) crm_help(flag, EX_OK); break; default: - printf("Argument code 0%o (%c)" " is not (?yet?) supported\n", flag, flag); + printf("Argument %c (0%o) is not (yet?) supported\n", flag, flag); ++argerr; break; } @@ -158,6 +307,13 @@ main(int argc, char **argv) crm_help('?', EX_USAGE); } + if (apply && no_version) { + fprintf(stderr, "warning: -u/--no-version ignored with -p/--patch\n"); + } else if (as_cib && no_version) { + fprintf(stderr, "error: -u/--no-version incompatible with -c/--cib\n"); + return 1; + } + if (raw_1) { object_1 = string2xml(xml_file_1); @@ -190,117 +346,12 @@ main(int argc, char **argv) } if (apply) { - int rc; - - output = copy_xml(object_1); - rc = xml_apply_patchset(output, object_2, as_cib); - if(rc != pcmk_ok) { - fprintf(stderr, "Could not apply patch: %s\n", pcmk_strerror(rc)); - return rc; - } + rc = apply_patch(object_1, object_2, as_cib); } else { - xml_track_changes(object_2, NULL, object_2, FALSE); - xml_calculate_changes(object_1, object_2); - crm_log_xml_debug(object_2, xml_file_2?xml_file_2:"target"); - - output = xml_create_patchset(0, object_1, object_2, NULL, FALSE); - - xml_log_changes(LOG_INFO, __FUNCTION__, object_2); - xml_accept_changes(object_2); - - if (output) { - patchset_process_digest(output, object_1, object_2, as_cib); - } - - if(as_cib && output) { - int add[] = { 0, 0, 0 }; - int del[] = { 0, 0, 0 }; - - const char *fmt = NULL; - const char *digest = NULL; - - xml_patch_versions(output, add, del); - fmt = crm_element_value(output, "format"); - digest = crm_element_value(output, XML_ATTR_DIGEST); - - if (add[2] != del[2] || add[1] != del[1] || add[0] != del[0]) { - crm_info("Patch: --- %d.%d.%d %s", del[0], del[1], del[2], fmt); - crm_info("Patch: +++ %d.%d.%d %s", add[0], add[1], add[2], digest); - } - - } else if (output && no_version) { - int format = 1; - - crm_element_value_int(output, "format", &format); - if (format == 2) { - xmlNode *version_xml = find_xml_node(output, "version", FALSE); - - if (version_xml) { - free_xml(version_xml); - } - - } else { - int i = 0; - - const char *tags[] = { - XML_TAG_DIFF_REMOVED, - XML_TAG_DIFF_ADDED, - }; - - const char *vfields[] = { - XML_ATTR_GENERATION_ADMIN, - XML_ATTR_GENERATION, - XML_ATTR_NUMUPDATES, - }; - - for (i = 0; i < DIMOF(tags); i++) { - xmlNode *tmp = NULL; - - tmp = find_xml_node(output, tags[i], FALSE); - if (tmp) { - int lpc = 0; - - for (lpc = 0; lpc < DIMOF(vfields); lpc++) { - xml_remove_prop(tmp, vfields[lpc]); - } - - tmp = find_xml_node(tmp, XML_TAG_CIB, FALSE); - if (tmp) { - for (lpc = 0; lpc < DIMOF(vfields); lpc++) { - xml_remove_prop(tmp, vfields[lpc]); - } - } - } - } - } - } - xml_log_patchset(LOG_NOTICE, __FUNCTION__, output); - } - - if (output != NULL) { - char *buffer = dump_xml_formatted(output); - - fprintf(stdout, "%s\n", crm_str(buffer)); - free(buffer); - - fflush(stdout); - - if (apply) { - const char *version = crm_element_value(output, XML_ATTR_CRM_VERSION); - - buffer = calculate_xml_versioned_digest(output, FALSE, TRUE, version); - crm_trace("Digest: %s\n", crm_str(buffer)); - free(buffer); - } + rc = generate_patch(object_1, object_2, xml_file_2, as_cib, no_version); } free_xml(object_1); free_xml(object_2); - free_xml(output); - - if (apply == FALSE && output != NULL) { - return 1; - } - - return 0; + return rc; } diff --git a/tools/crm_resource_runtime.c b/tools/crm_resource_runtime.c index 42e8b071e01..49815f734e8 100644 --- a/tools/crm_resource_runtime.c +++ b/tools/crm_resource_runtime.c @@ -538,22 +538,19 @@ send_lrm_rsc_op(crm_ipc_t * crmd_channel, const char *op, crm_xml_add(xml_rsc, XML_ATTR_ID, rsc->id); } - value = crm_element_value(rsc->xml, XML_ATTR_TYPE); - crm_xml_add(xml_rsc, XML_ATTR_TYPE, value); + value = crm_copy_xml_element(rsc->xml, xml_rsc, XML_ATTR_TYPE); if (value == NULL) { CMD_ERR("%s has no type! Aborting...", rsc_id); return -ENXIO; } - value = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); - crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, value); + value = crm_copy_xml_element(rsc->xml, xml_rsc, XML_AGENT_ATTR_CLASS); if (value == NULL) { CMD_ERR("%s has no class! Aborting...", rsc_id); return -ENXIO; } - value = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); - crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER, value); + crm_copy_xml_element(rsc->xml, xml_rsc, XML_AGENT_ATTR_PROVIDER); params = create_xml_node(msg_data, XML_TAG_ATTRS); crm_xml_add(params, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);