From 4fc4140d0c3daa3a8de32adaebf33462c9b3d581 Mon Sep 17 00:00:00 2001 From: Oyvind Albrigtsen Date: Thu, 26 Nov 2020 13:34:21 +0100 Subject: [PATCH 1/7] Refactor: move crm_admin_list() to pcmk__list_nodes() and only print node name for -N -q --- lib/pacemaker/pcmk_cluster_queries.c | 32 ++++++++++++++++++++++++---- lib/pacemaker/pcmk_output.c | 41 +++--------------------------------- 2 files changed, 31 insertions(+), 42 deletions(-) diff --git a/lib/pacemaker/pcmk_cluster_queries.c b/lib/pacemaker/pcmk_cluster_queries.c index c705b7f..1d1e775 100644 --- a/lib/pacemaker/pcmk_cluster_queries.c +++ b/lib/pacemaker/pcmk_cluster_queries.c @@ -395,7 +395,7 @@ int pcmk__list_nodes(pcmk__output_t *out, gboolean BASH_EXPORT) { cib_t *the_cib = cib_new(); - xmlNode *output = NULL; + xmlNode *xml_node = NULL; int rc; if (the_cib == NULL) { @@ -406,11 +406,35 @@ pcmk__list_nodes(pcmk__output_t *out, gboolean BASH_EXPORT) return pcmk_legacy2rc(rc); } - rc = the_cib->cmds->query(the_cib, NULL, &output, + rc = the_cib->cmds->query(the_cib, NULL, &xml_node, cib_scope_local | cib_sync_call); if (rc == pcmk_ok) { - out->message(out, "crmadmin-node-list", output, BASH_EXPORT); - free_xml(output); + int found = 0; + xmlNode *node = NULL; + xmlNode *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node); + + out->begin_list(out, NULL, NULL, "nodes"); + + for (node = first_named_child(nodes, XML_CIB_TAG_NODE); node != NULL; + node = crm_next_same_xml(node)) { + const char *node_type = BASH_EXPORT ? NULL : + crm_element_value(node, XML_ATTR_TYPE); + out->message(out, "crmadmin-node", node_type, + crm_str(crm_element_value(node, XML_ATTR_UNAME)), + crm_str(crm_element_value(node, XML_ATTR_ID)), + BASH_EXPORT); + + found++; + } + // @TODO List Pacemaker Remote nodes that don't have a entry + + out->end_list(out); + + if (found == 0) { + out->info(out, "No nodes configured"); + } + + free_xml(xml_node); } the_cib->cmds->signoff(the_cib); return pcmk_legacy2rc(rc); diff --git a/lib/pacemaker/pcmk_output.c b/lib/pacemaker/pcmk_output.c index bc4b91a..8f5e301 100644 --- a/lib/pacemaker/pcmk_output.c +++ b/lib/pacemaker/pcmk_output.c @@ -469,42 +469,6 @@ dc_xml(pcmk__output_t *out, va_list args) return pcmk_rc_ok; } - -PCMK__OUTPUT_ARGS("crmadmin-node-list", "xmlNodePtr", "gboolean") -static int -crmadmin_node_list(pcmk__output_t *out, va_list args) -{ - xmlNodePtr xml_node = va_arg(args, xmlNodePtr); - gboolean BASH_EXPORT = va_arg(args, gboolean); - - int found = 0; - xmlNode *node = NULL; - xmlNode *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node); - - out->begin_list(out, NULL, NULL, "nodes"); - - for (node = first_named_child(nodes, XML_CIB_TAG_NODE); node != NULL; - node = crm_next_same_xml(node)) { - const char *node_type = BASH_EXPORT ? NULL : - crm_element_value(node, XML_ATTR_TYPE); - out->message(out, "crmadmin-node", node_type, - crm_str(crm_element_value(node, XML_ATTR_UNAME)), - crm_str(crm_element_value(node, XML_ATTR_ID)), - BASH_EXPORT); - - found++; - } - // @TODO List Pacemaker Remote nodes that don't have a entry - - out->end_list(out); - - if (found == 0) { - out->info(out, "No nodes configured"); - } - - return pcmk_rc_ok; -} - PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *", "const char *", "gboolean") static int crmadmin_node_text(pcmk__output_t *out, va_list args) @@ -514,7 +478,9 @@ crmadmin_node_text(pcmk__output_t *out, va_list args) const char *id = va_arg(args, const char *); gboolean BASH_EXPORT = va_arg(args, gboolean); - if (BASH_EXPORT) { + if (out->is_quiet(out)) { + out->info(out, "%s", crm_str(name)); + } else if (BASH_EXPORT) { out->info(out, "export %s=%s", crm_str(name), crm_str(id)); } else { out->info(out, "%s node: %s (%s)", type ? type : "member", @@ -657,7 +623,6 @@ static pcmk__message_entry_t fmt_functions[] = { { "pacemakerd-health", "xml", pacemakerd_health_xml }, { "dc", "default", dc_text }, { "dc", "xml", dc_xml }, - { "crmadmin-node-list", "default", crmadmin_node_list }, { "crmadmin-node", "default", crmadmin_node_text }, { "crmadmin-node", "xml", crmadmin_node_xml }, { "digests", "default", digests_text }, -- 1.8.3.1 From ecc6d582fd18f774ab6c081c4d72a7913a0f419e Mon Sep 17 00:00:00 2001 From: Oyvind Albrigtsen Date: Fri, 4 Dec 2020 09:30:04 +0100 Subject: [PATCH 2/7] Feature/API: crmadmin/pcmk_list_nodes(): list remote/guest nodes and add parameter/variable to choose which node type(s) to list --- include/crm/common/xml_internal.h | 18 +++++++ include/pacemaker.h | 6 +-- include/pcmki/pcmki_cluster_queries.h | 2 +- lib/cluster/membership.c | 17 +------ lib/pacemaker/pcmk_cluster_queries.c | 89 ++++++++++++++++++++++++++++------- tools/crmadmin.c | 9 +++- 6 files changed, 103 insertions(+), 38 deletions(-) diff --git a/include/crm/common/xml_internal.h b/include/crm/common/xml_internal.h index d8694ee..969a57d 100644 --- a/include/crm/common/xml_internal.h +++ b/include/crm/common/xml_internal.h @@ -123,6 +123,24 @@ do { } \ } while (0) +/* XML search strings for guest, remote and pacemaker_remote nodes */ + +/* search string to find CIB resources entries for guest nodes */ +#define XPATH_GUEST_NODE_CONFIG \ + "//" XML_TAG_CIB "//" XML_CIB_TAG_CONFIGURATION "//" XML_CIB_TAG_RESOURCE \ + "//" XML_TAG_META_SETS "//" XML_CIB_TAG_NVPAIR \ + "[@name='" XML_RSC_ATTR_REMOTE_NODE "']" + +/* search string to find CIB resources entries for remote nodes */ +#define XPATH_REMOTE_NODE_CONFIG \ + "//" XML_TAG_CIB "//" XML_CIB_TAG_CONFIGURATION "//" XML_CIB_TAG_RESOURCE \ + "[@type='remote'][@provider='pacemaker']" + +/* search string to find CIB node status entries for pacemaker_remote nodes */ +#define XPATH_REMOTE_NODE_STATUS \ + "//" XML_TAG_CIB "//" XML_CIB_TAG_STATUS "//" XML_CIB_TAG_STATE \ + "[@" XML_NODE_IS_REMOTE "='true']" + enum pcmk__xml_artefact_ns { pcmk__xml_artefact_ns_legacy_rng = 1, pcmk__xml_artefact_ns_legacy_xslt, diff --git a/include/pacemaker.h b/include/pacemaker.h index 51bf585..42d096f 100644 --- a/include/pacemaker.h +++ b/include/pacemaker.h @@ -73,8 +73,6 @@ int pcmk_resource_digests(xmlNodePtr *xml, pe_resource_t *rsc, pe_node_t *node, GHashTable *overrides, pe_working_set_t *data_set); -#ifdef BUILD_PUBLIC_LIBPACEMAKER - /*! * \brief Get nodes list * @@ -82,7 +80,9 @@ int pcmk_resource_digests(xmlNodePtr *xml, pe_resource_t *rsc, * * \return Standard Pacemaker return code */ -int pcmk_list_nodes(xmlNodePtr *xml); +int pcmk_list_nodes(xmlNodePtr *xml, char *node_types); + +#ifdef BUILD_PUBLIC_LIBPACEMAKER /*! * \brief Perform a STONITH action. diff --git a/include/pcmki/pcmki_cluster_queries.h b/include/pcmki/pcmki_cluster_queries.h index eb3b51c..955eea3 100644 --- a/include/pcmki/pcmki_cluster_queries.h +++ b/include/pcmki/pcmki_cluster_queries.h @@ -8,7 +8,7 @@ int pcmk__controller_status(pcmk__output_t *out, char *dest_node, guint message_timeout_ms); int pcmk__designated_controller(pcmk__output_t *out, guint message_timeout_ms); int pcmk__pacemakerd_status(pcmk__output_t *out, char *ipc_name, guint message_timeout_ms); -int pcmk__list_nodes(pcmk__output_t *out, gboolean BASH_EXPORT); +int pcmk__list_nodes(pcmk__output_t *out, char *node_types, gboolean BASH_EXPORT); // remove when parameters removed from tools/crmadmin.c int pcmk__shutdown_controller(pcmk__output_t *out, char *dest_node); diff --git a/lib/cluster/membership.c b/lib/cluster/membership.c index 8bf5764..5841f16 100644 --- a/lib/cluster/membership.c +++ b/lib/cluster/membership.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -235,22 +236,6 @@ is_dirty(gpointer key, gpointer value, gpointer user_data) return pcmk_is_set(((crm_node_t*)value)->flags, crm_node_dirty); } -/* search string to find CIB resources entries for guest nodes */ -#define XPATH_GUEST_NODE_CONFIG \ - "//" XML_TAG_CIB "//" XML_CIB_TAG_CONFIGURATION "//" XML_CIB_TAG_RESOURCE \ - "//" XML_TAG_META_SETS "//" XML_CIB_TAG_NVPAIR \ - "[@name='" XML_RSC_ATTR_REMOTE_NODE "']" - -/* search string to find CIB resources entries for remote nodes */ -#define XPATH_REMOTE_NODE_CONFIG \ - "//" XML_TAG_CIB "//" XML_CIB_TAG_CONFIGURATION "//" XML_CIB_TAG_RESOURCE \ - "[@type='remote'][@provider='pacemaker']" - -/* search string to find CIB node status entries for pacemaker_remote nodes */ -#define XPATH_REMOTE_NODE_STATUS \ - "//" XML_TAG_CIB "//" XML_CIB_TAG_STATUS "//" XML_CIB_TAG_STATE \ - "[@" XML_NODE_IS_REMOTE "='true']" - /*! * \brief Repopulate the remote peer cache based on CIB XML * diff --git a/lib/pacemaker/pcmk_cluster_queries.c b/lib/pacemaker/pcmk_cluster_queries.c index 1d1e775..fc5cfc4 100644 --- a/lib/pacemaker/pcmk_cluster_queries.c +++ b/lib/pacemaker/pcmk_cluster_queries.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -390,9 +391,33 @@ pcmk_pacemakerd_status(xmlNodePtr *xml, char *ipc_name, unsigned int message_tim return rc; } +/* user data for looping through remote node xpath searches */ +struct node_data { + pcmk__output_t *out; + int found; + const char *field; /* XML attribute to check for node name */ + const char *type; + gboolean BASH_EXPORT; +}; + +static void +remote_node_print_helper(xmlNode *result, void *user_data) +{ + struct node_data *data = user_data; + pcmk__output_t *out = data->out; + const char *remote = crm_element_value(result, data->field); + + // node name and node id are the same for remote/guest nodes + out->message(out, "crmadmin-node", data->type, + remote, + remote, + data->BASH_EXPORT); + data->found++; +} + // \return Standard Pacemaker return code int -pcmk__list_nodes(pcmk__output_t *out, gboolean BASH_EXPORT) +pcmk__list_nodes(pcmk__output_t *out, char *node_types, gboolean BASH_EXPORT) { cib_t *the_cib = cib_new(); xmlNode *xml_node = NULL; @@ -409,28 +434,60 @@ pcmk__list_nodes(pcmk__output_t *out, gboolean BASH_EXPORT) rc = the_cib->cmds->query(the_cib, NULL, &xml_node, cib_scope_local | cib_sync_call); if (rc == pcmk_ok) { - int found = 0; xmlNode *node = NULL; xmlNode *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node); + struct node_data data = { + .out = out, + .found = 0, + .BASH_EXPORT = BASH_EXPORT + }; out->begin_list(out, NULL, NULL, "nodes"); - for (node = first_named_child(nodes, XML_CIB_TAG_NODE); node != NULL; - node = crm_next_same_xml(node)) { - const char *node_type = BASH_EXPORT ? NULL : - crm_element_value(node, XML_ATTR_TYPE); - out->message(out, "crmadmin-node", node_type, - crm_str(crm_element_value(node, XML_ATTR_UNAME)), - crm_str(crm_element_value(node, XML_ATTR_ID)), - BASH_EXPORT); + if (!pcmk__str_empty(node_types) && strstr(node_types, "all")) { + node_types = NULL; + } + + if (pcmk__str_empty(node_types) || strstr(node_types, "member")) { + for (node = first_named_child(nodes, XML_CIB_TAG_NODE); node != NULL; + node = crm_next_same_xml(node)) { + const char *node_type = crm_element_value(node, XML_ATTR_TYPE); + //if (node_type == NULL || !strcmp(node_type, "member")) { + if (node_type == NULL) { + out->message(out, "crmadmin-node", node_type, + crm_str(crm_element_value(node, XML_ATTR_UNAME)), + crm_str(crm_element_value(node, XML_ATTR_ID)), + BASH_EXPORT); + data.found++; + } + + } + } + + if (pcmk__str_empty(node_types) || strstr(node_types, "pacemaker_remote")) { + data.field = "id"; + data.type = "pacemaker_remote"; + crm_foreach_xpath_result(xml_node, XPATH_REMOTE_NODE_STATUS, + remote_node_print_helper, &data); + } + + if (pcmk__str_empty(node_types) || strstr(node_types, "guest")) { + data.field = "value"; + data.type = "guest"; + crm_foreach_xpath_result(xml_node, XPATH_GUEST_NODE_CONFIG, + remote_node_print_helper, &data); + } - found++; + if (pcmk__str_empty(node_types) || !pcmk__strcmp(node_types, ",|^remote", pcmk__str_regex)) { + data.field = "id"; + data.type = "remote"; + crm_foreach_xpath_result(xml_node, XPATH_REMOTE_NODE_CONFIG, + remote_node_print_helper, &data); } - // @TODO List Pacemaker Remote nodes that don't have a entry out->end_list(out); - if (found == 0) { + if (data.found == 0) { out->info(out, "No nodes configured"); } @@ -440,9 +497,8 @@ pcmk__list_nodes(pcmk__output_t *out, gboolean BASH_EXPORT) return pcmk_legacy2rc(rc); } -#ifdef BUILD_PUBLIC_LIBPACEMAKER int -pcmk_list_nodes(xmlNodePtr *xml) +pcmk_list_nodes(xmlNodePtr *xml, char *node_types) { pcmk__output_t *out = NULL; int rc = pcmk_rc_ok; @@ -454,11 +510,10 @@ pcmk_list_nodes(xmlNodePtr *xml) pcmk__register_lib_messages(out); - rc = pcmk__list_nodes(out, FALSE); + rc = pcmk__list_nodes(out, node_types, FALSE); pcmk__out_epilogue(out, xml, rc); return rc; } -#endif // remove when parameters removed from tools/crmadmin.c int diff --git a/tools/crmadmin.c b/tools/crmadmin.c index 2d9d663..3f31c69 100644 --- a/tools/crmadmin.c +++ b/tools/crmadmin.c @@ -38,10 +38,12 @@ struct { gint timeout; char *dest_node; char *ipc_name; + char *node_types; gboolean BASH_EXPORT; } options = { .dest_node = NULL, .ipc_name = NULL, + .node_types = NULL, .BASH_EXPORT = FALSE }; @@ -93,6 +95,11 @@ static GOptionEntry additional_options[] = { "\n operation failed", NULL }, + { "node-types", 'T', 0, G_OPTION_ARG_STRING, &options.node_types, + "Node types to list (available options: all, member, pacemaker_remote," + "\n guest, remote) (valid with -N/--nodes)", + NULL + }, { "bash-export", 'B', 0, G_OPTION_ARG_NONE, &options.BASH_EXPORT, "Display nodes as shell commands of the form 'export uname=uuid'" "\n (valid with -N/--nodes)", @@ -264,7 +271,7 @@ main(int argc, char **argv) rc = pcmk__pacemakerd_status(out, options.ipc_name, options.timeout); break; case cmd_list_nodes: - rc = pcmk__list_nodes(out, options.BASH_EXPORT); + rc = pcmk__list_nodes(out, options.node_types, options.BASH_EXPORT); break; case cmd_whois_dc: rc = pcmk__designated_controller(out, options.timeout); -- 1.8.3.1 From f25d4e7aa9de55bb296087e6cbaf1654d01d6b0d Mon Sep 17 00:00:00 2001 From: Oyvind Albrigtsen Date: Thu, 10 Dec 2020 13:58:31 +0100 Subject: [PATCH 3/7] Refactor: use PCMK__XP_ prefix instead of XPATH_ for XML constants --- include/crm/common/xml_internal.h | 6 +++--- lib/cluster/membership.c | 12 ++++++------ lib/pacemaker/pcmk_cluster_queries.c | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/crm/common/xml_internal.h b/include/crm/common/xml_internal.h index 969a57d..4501bee 100644 --- a/include/crm/common/xml_internal.h +++ b/include/crm/common/xml_internal.h @@ -126,18 +126,18 @@ do { /* XML search strings for guest, remote and pacemaker_remote nodes */ /* search string to find CIB resources entries for guest nodes */ -#define XPATH_GUEST_NODE_CONFIG \ +#define PCMK__XP_GUEST_NODE_CONFIG \ "//" XML_TAG_CIB "//" XML_CIB_TAG_CONFIGURATION "//" XML_CIB_TAG_RESOURCE \ "//" XML_TAG_META_SETS "//" XML_CIB_TAG_NVPAIR \ "[@name='" XML_RSC_ATTR_REMOTE_NODE "']" /* search string to find CIB resources entries for remote nodes */ -#define XPATH_REMOTE_NODE_CONFIG \ +#define PCMK__XP_REMOTE_NODE_CONFIG \ "//" XML_TAG_CIB "//" XML_CIB_TAG_CONFIGURATION "//" XML_CIB_TAG_RESOURCE \ "[@type='remote'][@provider='pacemaker']" /* search string to find CIB node status entries for pacemaker_remote nodes */ -#define XPATH_REMOTE_NODE_STATUS \ +#define PCMK__XP_REMOTE_NODE_STATUS \ "//" XML_TAG_CIB "//" XML_CIB_TAG_STATUS "//" XML_CIB_TAG_STATE \ "[@" XML_NODE_IS_REMOTE "='true']" diff --git a/lib/cluster/membership.c b/lib/cluster/membership.c index 5841f16..d70091e 100644 --- a/lib/cluster/membership.c +++ b/lib/cluster/membership.c @@ -257,7 +257,7 @@ crm_remote_peer_cache_refresh(xmlNode *cib) /* Look for guest nodes and remote nodes in the status section */ data.field = "id"; data.has_state = TRUE; - crm_foreach_xpath_result(cib, XPATH_REMOTE_NODE_STATUS, + crm_foreach_xpath_result(cib, PCMK__XP_REMOTE_NODE_STATUS, remote_cache_refresh_helper, &data); /* Look for guest nodes and remote nodes in the configuration section, @@ -268,11 +268,11 @@ crm_remote_peer_cache_refresh(xmlNode *cib) */ data.field = "value"; data.has_state = FALSE; - crm_foreach_xpath_result(cib, XPATH_GUEST_NODE_CONFIG, + crm_foreach_xpath_result(cib, PCMK__XP_GUEST_NODE_CONFIG, remote_cache_refresh_helper, &data); data.field = "id"; data.has_state = FALSE; - crm_foreach_xpath_result(cib, XPATH_REMOTE_NODE_CONFIG, + crm_foreach_xpath_result(cib, PCMK__XP_REMOTE_NODE_CONFIG, remote_cache_refresh_helper, &data); /* Remove all old cache entries that weren't seen in the CIB */ @@ -1232,7 +1232,7 @@ known_node_cache_refresh_helper(xmlNode *xml_node, void *user_data) } -#define XPATH_MEMBER_NODE_CONFIG \ +#define PCMK__XP_MEMBER_NODE_CONFIG \ "//" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_NODES \ "/" XML_CIB_TAG_NODE "[not(@type) or @type='member']" @@ -1243,7 +1243,7 @@ crm_known_peer_cache_refresh(xmlNode *cib) g_hash_table_foreach(crm_known_peer_cache, mark_dirty, NULL); - crm_foreach_xpath_result(cib, XPATH_MEMBER_NODE_CONFIG, + crm_foreach_xpath_result(cib, PCMK__XP_MEMBER_NODE_CONFIG, known_peer_cache_refresh_helper, NULL); /* Remove all old cache entries that weren't seen in the CIB */ diff --git a/lib/pacemaker/pcmk_cluster_queries.c b/lib/pacemaker/pcmk_cluster_queries.c index fc5cfc4..e512f32 100644 --- a/lib/pacemaker/pcmk_cluster_queries.c +++ b/lib/pacemaker/pcmk_cluster_queries.c @@ -467,21 +467,21 @@ pcmk__list_nodes(pcmk__output_t *out, char *node_types, gboolean BASH_EXPORT) if (pcmk__str_empty(node_types) || strstr(node_types, "pacemaker_remote")) { data.field = "id"; data.type = "pacemaker_remote"; - crm_foreach_xpath_result(xml_node, XPATH_REMOTE_NODE_STATUS, + crm_foreach_xpath_result(xml_node, PCMK__XP_REMOTE_NODE_STATUS, remote_node_print_helper, &data); } if (pcmk__str_empty(node_types) || strstr(node_types, "guest")) { data.field = "value"; data.type = "guest"; - crm_foreach_xpath_result(xml_node, XPATH_GUEST_NODE_CONFIG, + crm_foreach_xpath_result(xml_node, PCMK__XP_GUEST_NODE_CONFIG, remote_node_print_helper, &data); } if (pcmk__str_empty(node_types) || !pcmk__strcmp(node_types, ",|^remote", pcmk__str_regex)) { data.field = "id"; data.type = "remote"; - crm_foreach_xpath_result(xml_node, XPATH_REMOTE_NODE_CONFIG, + crm_foreach_xpath_result(xml_node, PCMK__XP_REMOTE_NODE_CONFIG, remote_node_print_helper, &data); } -- 1.8.3.1 From 225d5fabedb1319245a2a3e661df2252e60aca1a Mon Sep 17 00:00:00 2001 From: Oyvind Albrigtsen Date: Fri, 22 Jan 2021 16:34:39 +0100 Subject: [PATCH 4/7] Fix: crmadmin: use cluster instead of member term and remove pacemaker_remote node type --- include/pacemaker.h | 1 + lib/cluster/membership.c | 2 +- lib/pacemaker/pcmk_cluster_queries.c | 10 +--------- lib/pacemaker/pcmk_output.c | 4 ++-- tools/crmadmin.c | 4 ++-- 5 files changed, 7 insertions(+), 14 deletions(-) diff --git a/include/pacemaker.h b/include/pacemaker.h index 42d096f..a6a9d13 100644 --- a/include/pacemaker.h +++ b/include/pacemaker.h @@ -77,6 +77,7 @@ int pcmk_resource_digests(xmlNodePtr *xml, pe_resource_t *rsc, * \brief Get nodes list * * \param[in,out] xml The destination for the result, as an XML tree. + * \param[in] node_types Node type(s) to return (default: all) * * \return Standard Pacemaker return code */ diff --git a/lib/pacemaker/pcmk_cluster_queries.c b/lib/pacemaker/pcmk_cluster_queries.c index e512f32..9f19915 100644 --- a/lib/pacemaker/pcmk_cluster_queries.c +++ b/lib/pacemaker/pcmk_cluster_queries.c @@ -448,11 +448,10 @@ pcmk__list_nodes(pcmk__output_t *out, char *node_types, gboolean BASH_EXPORT) node_types = NULL; } - if (pcmk__str_empty(node_types) || strstr(node_types, "member")) { + if (pcmk__str_empty(node_types) || strstr(node_types, "cluster")) { for (node = first_named_child(nodes, XML_CIB_TAG_NODE); node != NULL; node = crm_next_same_xml(node)) { const char *node_type = crm_element_value(node, XML_ATTR_TYPE); - //if (node_type == NULL || !strcmp(node_type, "member")) { if (node_type == NULL) { out->message(out, "crmadmin-node", node_type, crm_str(crm_element_value(node, XML_ATTR_UNAME)), @@ -464,13 +463,6 @@ pcmk__list_nodes(pcmk__output_t *out, char *node_types, gboolean BASH_EXPORT) } } - if (pcmk__str_empty(node_types) || strstr(node_types, "pacemaker_remote")) { - data.field = "id"; - data.type = "pacemaker_remote"; - crm_foreach_xpath_result(xml_node, PCMK__XP_REMOTE_NODE_STATUS, - remote_node_print_helper, &data); - } - if (pcmk__str_empty(node_types) || strstr(node_types, "guest")) { data.field = "value"; data.type = "guest"; diff --git a/lib/pacemaker/pcmk_output.c b/lib/pacemaker/pcmk_output.c index 8f5e301..655b723 100644 --- a/lib/pacemaker/pcmk_output.c +++ b/lib/pacemaker/pcmk_output.c @@ -483,7 +483,7 @@ crmadmin_node_text(pcmk__output_t *out, va_list args) } else if (BASH_EXPORT) { out->info(out, "export %s=%s", crm_str(name), crm_str(id)); } else { - out->info(out, "%s node: %s (%s)", type ? type : "member", + out->info(out, "%s node: %s (%s)", type ? type : "cluster", crm_str(name), crm_str(id)); } @@ -499,7 +499,7 @@ crmadmin_node_xml(pcmk__output_t *out, va_list args) const char *id = va_arg(args, const char *); pcmk__output_create_xml_node(out, "node", - "type", type ? type : "member", + "type", type ? type : "cluster", "name", crm_str(name), "id", crm_str(id), NULL); diff --git a/tools/crmadmin.c b/tools/crmadmin.c index 3f31c69..d699786 100644 --- a/tools/crmadmin.c +++ b/tools/crmadmin.c @@ -96,8 +96,8 @@ static GOptionEntry additional_options[] = { NULL }, { "node-types", 'T', 0, G_OPTION_ARG_STRING, &options.node_types, - "Node types to list (available options: all, member, pacemaker_remote," - "\n guest, remote) (valid with -N/--nodes)", + "Node types to list (available options: all, cluster, guest, remote)" + "\n (valid with -N/--nodes)", NULL }, { "bash-export", 'B', 0, G_OPTION_ARG_NONE, &options.BASH_EXPORT, -- 1.8.3.1 From ceacef32c70d1760a4dd89c00134373d42457ea2 Mon Sep 17 00:00:00 2001 From: Oyvind Albrigtsen Date: Mon, 25 Jan 2021 16:52:00 +0100 Subject: [PATCH 5/7] Refactor: crmadmin/pcmk__list_nodes(): use crm_foreach_xpath_result() for all types of nodes --- include/crm/common/xml_internal.h | 5 +++++ lib/cluster/membership.c | 4 ---- lib/pacemaker/pcmk_cluster_queries.c | 25 ++++++++----------------- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/include/crm/common/xml_internal.h b/include/crm/common/xml_internal.h index 4501bee..2193b50 100644 --- a/include/crm/common/xml_internal.h +++ b/include/crm/common/xml_internal.h @@ -125,6 +125,11 @@ do { /* XML search strings for guest, remote and pacemaker_remote nodes */ +/* search string to find CIB resources entries for cluster nodes */ +#define PCMK__XP_MEMBER_NODE_CONFIG \ + "//" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_NODES \ + "/" XML_CIB_TAG_NODE "[not(@type) or @type='member']" + /* search string to find CIB resources entries for guest nodes */ #define PCMK__XP_GUEST_NODE_CONFIG \ "//" XML_TAG_CIB "//" XML_CIB_TAG_CONFIGURATION "//" XML_CIB_TAG_RESOURCE \ diff --git a/lib/cluster/membership.c b/lib/cluster/membership.c index 3417836..5d042e2 100644 --- a/lib/cluster/membership.c +++ b/lib/cluster/membership.c @@ -1232,10 +1232,6 @@ known_node_cache_refresh_helper(xmlNode *xml_node, void *user_data) } -#define PCMK__XP_MEMBER_NODE_CONFIG \ - "//" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_NODES \ - "/" XML_CIB_TAG_NODE "[not(@type) or @type='member']" - static void crm_known_peer_cache_refresh(xmlNode *cib) { diff --git a/lib/pacemaker/pcmk_cluster_queries.c b/lib/pacemaker/pcmk_cluster_queries.c index 9f19915..6e6acda 100644 --- a/lib/pacemaker/pcmk_cluster_queries.c +++ b/lib/pacemaker/pcmk_cluster_queries.c @@ -405,12 +405,13 @@ remote_node_print_helper(xmlNode *result, void *user_data) { struct node_data *data = user_data; pcmk__output_t *out = data->out; - const char *remote = crm_element_value(result, data->field); + const char *name = crm_element_value(result, XML_ATTR_UNAME); + const char *id = crm_element_value(result, data->field); // node name and node id are the same for remote/guest nodes out->message(out, "crmadmin-node", data->type, - remote, - remote, + name ? name : id, + id, data->BASH_EXPORT); data->found++; } @@ -434,8 +435,6 @@ pcmk__list_nodes(pcmk__output_t *out, char *node_types, gboolean BASH_EXPORT) rc = the_cib->cmds->query(the_cib, NULL, &xml_node, cib_scope_local | cib_sync_call); if (rc == pcmk_ok) { - xmlNode *node = NULL; - xmlNode *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node); struct node_data data = { .out = out, .found = 0, @@ -449,18 +448,10 @@ pcmk__list_nodes(pcmk__output_t *out, char *node_types, gboolean BASH_EXPORT) } if (pcmk__str_empty(node_types) || strstr(node_types, "cluster")) { - for (node = first_named_child(nodes, XML_CIB_TAG_NODE); node != NULL; - node = crm_next_same_xml(node)) { - const char *node_type = crm_element_value(node, XML_ATTR_TYPE); - if (node_type == NULL) { - out->message(out, "crmadmin-node", node_type, - crm_str(crm_element_value(node, XML_ATTR_UNAME)), - crm_str(crm_element_value(node, XML_ATTR_ID)), - BASH_EXPORT); - data.found++; - } - - } + data.field = "id"; + data.type = "cluster"; + crm_foreach_xpath_result(xml_node, PCMK__XP_MEMBER_NODE_CONFIG, + remote_node_print_helper, &data); } if (pcmk__str_empty(node_types) || strstr(node_types, "guest")) { -- 1.8.3.1 From a56ce0cf463798ac8d7ff945dda3be019cb9297d Mon Sep 17 00:00:00 2001 From: Oyvind Albrigtsen Date: Tue, 26 Jan 2021 11:03:10 +0100 Subject: [PATCH 6/7] Refactor: crmadmin: move new -T functionality to -N parameter --- include/crm/crm.h | 2 +- tools/crmadmin.c | 30 ++++++++++++------------------ 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/include/crm/crm.h b/include/crm/crm.h index 3f22c4b..09643c2 100644 --- a/include/crm/crm.h +++ b/include/crm/crm.h @@ -51,7 +51,7 @@ extern "C" { * >=3.0.13: Fail counts include operation name and interval * >=3.2.0: DC supports PCMK_LRM_OP_INVALID and PCMK_LRM_OP_NOT_CONNECTED */ -# define CRM_FEATURE_SET "3.7.0" +# define CRM_FEATURE_SET "3.7.1" # define EOS '\0' # define DIMOF(a) ((int) (sizeof(a)/sizeof(a[0])) ) diff --git a/tools/crmadmin.c b/tools/crmadmin.c index d699786..9c280aa 100644 --- a/tools/crmadmin.c +++ b/tools/crmadmin.c @@ -36,14 +36,12 @@ static enum { struct { gboolean health; gint timeout; - char *dest_node; + char *optarg; char *ipc_name; - char *node_types; gboolean BASH_EXPORT; } options = { - .dest_node = NULL, + .optarg = NULL, .ipc_name = NULL, - .node_types = NULL, .BASH_EXPORT = FALSE }; @@ -69,9 +67,10 @@ static GOptionEntry command_options[] = { "\n node to examine the logs.", NULL }, - { "nodes", 'N', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb, - "Display the uname of all member nodes", - NULL + { "nodes", 'N', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, command_cb, + "Display the uname of all member nodes [optionally filtered by type (comma-separated)]" + "\n Types: all (default), cluster, guest, remote", + "TYPE" }, { "election", 'E', G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb, "(Advanced) Start an election for the cluster co-ordinator", @@ -95,11 +94,6 @@ static GOptionEntry additional_options[] = { "\n operation failed", NULL }, - { "node-types", 'T', 0, G_OPTION_ARG_STRING, &options.node_types, - "Node types to list (available options: all, cluster, guest, remote)" - "\n (valid with -N/--nodes)", - NULL - }, { "bash-export", 'B', 0, G_OPTION_ARG_NONE, &options.BASH_EXPORT, "Display nodes as shell commands of the form 'export uname=uuid'" "\n (valid with -N/--nodes)", @@ -142,10 +136,10 @@ command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError } if (optarg) { - if (options.dest_node != NULL) { - free(options.dest_node); + if (options.optarg != NULL) { + free(options.optarg); } - options.dest_node = strdup(optarg); + options.optarg = strdup(optarg); } return TRUE; @@ -265,19 +259,19 @@ main(int argc, char **argv) switch (command) { case cmd_health: - rc = pcmk__controller_status(out, options.dest_node, options.timeout); + rc = pcmk__controller_status(out, options.optarg, options.timeout); break; case cmd_pacemakerd_health: rc = pcmk__pacemakerd_status(out, options.ipc_name, options.timeout); break; case cmd_list_nodes: - rc = pcmk__list_nodes(out, options.node_types, options.BASH_EXPORT); + rc = pcmk__list_nodes(out, options.optarg, options.BASH_EXPORT); break; case cmd_whois_dc: rc = pcmk__designated_controller(out, options.timeout); break; case cmd_shutdown: - rc = pcmk__shutdown_controller(out, options.dest_node); + rc = pcmk__shutdown_controller(out, options.optarg); break; case cmd_elect_dc: rc = pcmk__start_election(out); -- 1.8.3.1 From dae5688edaf1b3008b70296421004ebdfbdf4b7b Mon Sep 17 00:00:00 2001 From: Oyvind Albrigtsen Date: Tue, 26 Jan 2021 15:02:39 +0100 Subject: [PATCH 7/7] Test: cts-cli: add crmadmin -N/--nodes tests --- cts/Makefile.am | 1 + cts/cli/crmadmin-cluster-remote-guest-nodes.xml | 483 ++++++++++++++++++++++++ cts/cli/regression.tools.exp | 24 ++ cts/cts-cli.in | 42 ++- 4 files changed, 543 insertions(+), 7 deletions(-) create mode 100644 cts/cli/crmadmin-cluster-remote-guest-nodes.xml diff --git a/cts/Makefile.am b/cts/Makefile.am index de02aed..2a73774 100644 --- a/cts/Makefile.am +++ b/cts/Makefile.am @@ -61,6 +61,7 @@ cts_SCRIPTS = CTSlab.py \ clidir = $(testdir)/cli dist_cli_DATA = cli/constraints.xml \ + cli/crmadmin-cluster-remote-guest-nodes.xml \ cli/crm_diff_new.xml \ cli/crm_diff_old.xml \ cli/crm_mon.xml \ diff --git a/cts/cli/crmadmin-cluster-remote-guest-nodes.xml b/cts/cli/crmadmin-cluster-remote-guest-nodes.xml new file mode 100644 index 0000000..8db656f --- /dev/null +++ b/cts/cli/crmadmin-cluster-remote-guest-nodes.xml @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cts/cli/regression.tools.exp b/cts/cli/regression.tools.exp index 510cc0a..7324053 100644 --- a/cts/cli/regression.tools.exp +++ b/cts/cli/regression.tools.exp @@ -4053,3 +4053,27 @@ Resources colocated with clone: =#=#=#= End test: Show resource digests with overrides - OK (0) =#=#=#= * Passed: crm_resource - Show resource digests with overrides +=#=#=#= Begin test: List all nodes =#=#=#= +11 +=#=#=#= End test: List all nodes - OK (0) =#=#=#= +* Passed: crmadmin - List all nodes +=#=#=#= Begin test: List cluster nodes =#=#=#= +6 +=#=#=#= End test: List cluster nodes - OK (0) =#=#=#= +* Passed: crmadmin - List cluster nodes +=#=#=#= Begin test: List guest nodes =#=#=#= +2 +=#=#=#= End test: List guest nodes - OK (0) =#=#=#= +* Passed: crmadmin - List guest nodes +=#=#=#= Begin test: List remote nodes =#=#=#= +3 +=#=#=#= End test: List remote nodes - OK (0) =#=#=#= +* Passed: crmadmin - List remote nodes +=#=#=#= Begin test: List cluster,remote nodes =#=#=#= +9 +=#=#=#= End test: List cluster,remote nodes - OK (0) =#=#=#= +* Passed: crmadmin - List cluster,remote nodes +=#=#=#= Begin test: List guest,remote nodes =#=#=#= +5 +=#=#=#= End test: List guest,remote nodes - OK (0) =#=#=#= +* Passed: crmadmin - List guest,remote nodes diff --git a/cts/cts-cli.in b/cts/cts-cli.in index 96f5386..8e2dbe5 100755 --- a/cts/cts-cli.in +++ b/cts/cts-cli.in @@ -501,15 +501,15 @@ function test_tools() { desc="Default standby value" cmd="crm_standby -N node1 -G" test_assert $CRM_EX_OK - + desc="Set standby status" cmd="crm_standby -N node1 -v true" test_assert $CRM_EX_OK - + desc="Query standby value" cmd="crm_standby -N node1 -G" test_assert $CRM_EX_OK - + desc="Delete standby value" cmd="crm_standby -N node1 -D" test_assert $CRM_EX_OK @@ -657,7 +657,7 @@ function test_tools() { desc="Drop the status section" cmd="cibadmin -R -o status --xml-text ''" test_assert $CRM_EX_OK 0 - + desc="Create a clone" cmd="cibadmin -C -o resources --xml-text ''" test_assert $CRM_EX_OK 0 @@ -697,7 +697,7 @@ function test_tools() { desc="Update existing resource meta attribute" cmd="crm_resource -r test-clone --meta -p is-managed -v true" test_assert $CRM_EX_OK - + desc="Create a resource meta attribute in the parent" cmd="crm_resource -r test-clone --meta -p is-managed -v true --force" test_assert $CRM_EX_OK @@ -803,6 +803,34 @@ function test_tools() { test_assert $CRM_EX_OK 0 unset CIB_file + + export CIB_file="$test_home/cli/crmadmin-cluster-remote-guest-nodes.xml" + + desc="List all nodes" + cmd="crmadmin -N | wc -l | grep 11" + test_assert $CRM_EX_OK 0 + + desc="List cluster nodes" + cmd="crmadmin -N cluster | wc -l | grep 6" + test_assert $CRM_EX_OK 0 + + desc="List guest nodes" + cmd="crmadmin -N guest | wc -l | grep 2" + test_assert $CRM_EX_OK 0 + + desc="List remote nodes" + cmd="crmadmin -N remote | wc -l | grep 3" + test_assert $CRM_EX_OK 0 + + desc="List cluster,remote nodes" + cmd="crmadmin -N cluster,remote | wc -l | grep 9" + test_assert $CRM_EX_OK 0 + + desc="List guest,remote nodes" + cmd="crmadmin -N guest,remote | wc -l | grep 5" + test_assert $CRM_EX_OK 0 + + unset CIB_file } INVALID_PERIODS=( @@ -822,7 +850,7 @@ INVALID_PERIODS=( "P1Z/2019-02-20 00:00:00Z" # Invalid duration unit "P1YM/2019-02-20 00:00:00Z" # No number for duration unit ) - + function test_dates() { # Ensure invalid period specifications are rejected for spec in '' "${INVALID_PERIODS[@]}"; do @@ -1665,7 +1693,7 @@ for t in $tests; do done rm -rf "${shadow_dir}" - + failed=0 if [ $verbose -eq 1 ]; then -- 1.8.3.1