From 481eae4d5ff23fc7e0edf289aefd48975ecdc10e Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Jan 22 2021 12:12:34 +0000 Subject: Feature: tools: Use formatted output for crm_resource checks. --- diff --git a/cts/cli/regression.tools.exp b/cts/cli/regression.tools.exp index 935dce8..7166714 100644 --- a/cts/cli/regression.tools.exp +++ b/cts/cli/regression.tools.exp @@ -876,9 +876,7 @@ Set 'dummy' option: id=dummy-meta_attributes-target-role set=dummy-meta_attribut * Passed: crm_resource - Create another resource meta attribute =#=#=#= Begin test: Show why a resource is not running =#=#=#= Resource dummy is not running - - * Configuration specifies 'dummy' should remain stopped - +Configuration specifies 'dummy' should remain stopped =#=#=#= End test: Show why a resource is not running - OK (0) =#=#=#= * Passed: crm_resource - Show why a resource is not running =#=#=#= Begin test: Remove another resource meta attribute =#=#=#= diff --git a/tools/crm_resource.c b/tools/crm_resource.c index 76a15dc..3df9419 100644 --- a/tools/crm_resource.c +++ b/tools/crm_resource.c @@ -1868,7 +1868,7 @@ main(int argc, char **argv) goto done; } } - cli_resource_why(out, cib_conn, data_set->resources, rsc, dest); + out->message(out, "resource-why", cib_conn, data_set->resources, rsc, dest); rc = pcmk_rc_ok; } break; diff --git a/tools/crm_resource.h b/tools/crm_resource.h index 4fc7c71..377f7aa 100644 --- a/tools/crm_resource.h +++ b/tools/crm_resource.h @@ -23,6 +23,20 @@ #include #include +enum resource_check_flags { + rsc_remain_stopped = (1 << 0), + rsc_unpromotable = (1 << 1), + rsc_unmanaged = (1 << 2) +}; + +typedef struct resource_checks_s { + pe_resource_t *rsc; + unsigned int flags; + const char *lock_node; +} resource_checks_t; + +resource_checks_t *cli_check_resource(pe_resource_t *rsc, char *role_s, char *managed); + /* ban */ int cli_resource_prefer(pcmk__output_t *out, const char *rsc_id, const char *host, const char *move_lifetime, cib_t * cib_conn, int cib_options, @@ -51,7 +65,7 @@ int cli_resource_print_operations(pcmk__output_t *out, const char *rsc_id, pe_working_set_t * data_set); /* runtime */ -void cli_resource_check(pcmk__output_t *out, cib_t * cib, pe_resource_t *rsc); +int cli_resource_check(pcmk__output_t *out, cib_t * cib, pe_resource_t *rsc); int cli_resource_fail(pcmk__output_t *out, pcmk_ipc_api_t *controld_api, const char *host_uname, const char *rsc_id, pe_working_set_t *data_set); @@ -98,7 +112,7 @@ int cli_resource_delete_attribute(pcmk__output_t *out, pe_resource_t *rsc, int update_working_set_xml(pe_working_set_t *data_set, xmlNode **xml); int wait_till_stable(pcmk__output_t *out, int timeout_ms, cib_t * cib); -void cli_resource_why(pcmk__output_t *out, cib_t *cib_conn, GListPtr resources, - pe_resource_t *rsc, pe_node_t *node); + +bool resource_is_running_on(pe_resource_t *rsc, const char *host); void crm_resource_register_messages(pcmk__output_t *out); diff --git a/tools/crm_resource_print.c b/tools/crm_resource_print.c index 4b3c42d..d2a2cc8 100644 --- a/tools/crm_resource_print.c +++ b/tools/crm_resource_print.c @@ -8,6 +8,7 @@ */ #include +#include #include #include @@ -287,6 +288,261 @@ property_text(pcmk__output_t *out, va_list args) { return pcmk_rc_ok; } +PCMK__OUTPUT_ARGS("resource-check", "resource_checks_t *") +static int +resource_check_default(pcmk__output_t *out, va_list args) { + resource_checks_t *checks = va_arg(args, resource_checks_t *); + + pe_resource_t *parent = uber_parent(checks->rsc); + int rc = pcmk_rc_no_output; + bool printed = false; + + if (checks->flags != 0 || checks->lock_node != NULL) { + printed = true; + out->begin_list(out, NULL, NULL, "Resource Checks"); + } + + if (pcmk_is_set(checks->flags, rsc_remain_stopped)) { + out->list_item(out, "check", "Configuration specifies '%s' should remain stopped", + parent->id); + } + + if (pcmk_is_set(checks->flags, rsc_unpromotable)) { + out->list_item(out, "check", "Configuration specifies '%s' should not be promoted", + parent->id); + } + + if (pcmk_is_set(checks->flags, rsc_unmanaged)) { + out->list_item(out, "check", "Configuration prevents cluster from stopping or starting unmanaged '%s'", + parent->id); + } + + if (checks->lock_node) { + out->list_item(out, "check", "'%s' is locked to node %s due to shutdown", + parent->id, checks->lock_node); + } + + if (printed) { + out->end_list(out); + rc = pcmk_rc_ok; + } + + return rc; +} + +PCMK__OUTPUT_ARGS("resource-check", "resource_checks_t *") +static int +resource_check_xml(pcmk__output_t *out, va_list args) { + resource_checks_t *checks = va_arg(args, resource_checks_t *); + + pe_resource_t *parent = uber_parent(checks->rsc); + int rc = pcmk_rc_no_output; + + xmlNode *node = pcmk__output_create_xml_node(out, "check"); + + xmlSetProp(node, (pcmkXmlStr) "id", (pcmkXmlStr) parent->id); + + if (pcmk_is_set(checks->flags, rsc_remain_stopped)) { + xmlSetProp(node, (pcmkXmlStr) "remain_stopped", (pcmkXmlStr) "true"); + } + + if (pcmk_is_set(checks->flags, rsc_unpromotable)) { + xmlSetProp(node, (pcmkXmlStr) "promotable", (pcmkXmlStr) "false"); + } + + if (pcmk_is_set(checks->flags, rsc_unmanaged)) { + xmlSetProp(node, (pcmkXmlStr) "unmanaged", (pcmkXmlStr) "true"); + } + + if (checks->lock_node) { + xmlSetProp(node, (pcmkXmlStr) "locked-to", (pcmkXmlStr) checks->lock_node); + } + + return rc; +} + +PCMK__OUTPUT_ARGS("resource-why", "cib_t *", "GListPtr", "pe_resource_t *", + "pe_node_t *") +static int +resource_why_default(pcmk__output_t *out, va_list args) +{ + cib_t *cib_conn = va_arg(args, cib_t *); + GListPtr resources = va_arg(args, GListPtr); + pe_resource_t *rsc = va_arg(args, pe_resource_t *); + pe_node_t *node = va_arg(args, pe_node_t *); + + const char *host_uname = (node == NULL)? NULL : node->details->uname; + + out->begin_list(out, NULL, NULL, "Resource Reasons"); + + if ((rsc == NULL) && (host_uname == NULL)) { + GListPtr lpc = NULL; + GListPtr hosts = NULL; + + for (lpc = resources; lpc != NULL; lpc = lpc->next) { + pe_resource_t *rsc = (pe_resource_t *) lpc->data; + rsc->fns->location(rsc, &hosts, TRUE); + + if (hosts == NULL) { + out->list_item(out, "reason", "Resource %s is not running", rsc->id); + } else { + out->list_item(out, "reason", "Resource %s is running", rsc->id); + } + + cli_resource_check(out, cib_conn, rsc); + g_list_free(hosts); + hosts = NULL; + } + + } else if ((rsc != NULL) && (host_uname != NULL)) { + if (resource_is_running_on(rsc, host_uname)) { + out->list_item(out, "reason", "Resource %s is running on host %s", + rsc->id, host_uname); + } else { + out->list_item(out, "reason", "Resource %s is not running on host %s", + rsc->id, host_uname); + } + + cli_resource_check(out, cib_conn, rsc); + + } else if ((rsc == NULL) && (host_uname != NULL)) { + const char* host_uname = node->details->uname; + GListPtr allResources = node->details->allocated_rsc; + GListPtr activeResources = node->details->running_rsc; + GListPtr unactiveResources = pcmk__subtract_lists(allResources, activeResources, (GCompareFunc) strcmp); + GListPtr lpc = NULL; + + for (lpc = activeResources; lpc != NULL; lpc = lpc->next) { + pe_resource_t *rsc = (pe_resource_t *) lpc->data; + out->list_item(out, "reason", "Resource %s is running on host %s", + rsc->id, host_uname); + cli_resource_check(out, cib_conn, rsc); + } + + for(lpc = unactiveResources; lpc != NULL; lpc = lpc->next) { + pe_resource_t *rsc = (pe_resource_t *) lpc->data; + out->list_item(out, "reason", "Resource %s is assigned to host %s but not running", + rsc->id, host_uname); + cli_resource_check(out, cib_conn, rsc); + } + + g_list_free(allResources); + g_list_free(activeResources); + g_list_free(unactiveResources); + + } else if ((rsc != NULL) && (host_uname == NULL)) { + GListPtr hosts = NULL; + + rsc->fns->location(rsc, &hosts, TRUE); + out->list_item(out, "reason", "Resource %s is %srunning", + rsc->id, (hosts? "" : "not ")); + cli_resource_check(out, cib_conn, rsc); + g_list_free(hosts); + } + + out->end_list(out); + return pcmk_rc_ok; +} + +PCMK__OUTPUT_ARGS("resource-why", "cib_t *", "GListPtr", "pe_resource_t *", + "pe_node_t *") +static int +resource_why_xml(pcmk__output_t *out, va_list args) +{ + cib_t *cib_conn = va_arg(args, cib_t *); + GListPtr resources = va_arg(args, GListPtr); + pe_resource_t *rsc = va_arg(args, pe_resource_t *); + pe_node_t *node = va_arg(args, pe_node_t *); + + const char *host_uname = (node == NULL)? NULL : node->details->uname; + + xmlNode *xml_node = pcmk__output_xml_create_parent(out, "reason"); + + if ((rsc == NULL) && (host_uname == NULL)) { + GListPtr lpc = NULL; + GListPtr hosts = NULL; + + pcmk__output_xml_create_parent(out, "resources"); + + for (lpc = resources; lpc != NULL; lpc = lpc->next) { + pe_resource_t *rsc = (pe_resource_t *) lpc->data; + xmlNode *rsc_node = NULL; + + rsc->fns->location(rsc, &hosts, TRUE); + + rsc_node = pcmk__output_xml_create_parent(out, "resource"); + xmlSetProp(rsc_node, (pcmkXmlStr) "id", (pcmkXmlStr) rsc->id); + xmlSetProp(rsc_node, (pcmkXmlStr) "running", + (pcmkXmlStr) pcmk__btoa(hosts != NULL)); + + cli_resource_check(out, cib_conn, rsc); + pcmk__output_xml_pop_parent(out); + g_list_free(hosts); + hosts = NULL; + } + + pcmk__output_xml_pop_parent(out); + + } else if ((rsc != NULL) && (host_uname != NULL)) { + if (resource_is_running_on(rsc, host_uname)) { + xmlSetProp(xml_node, (pcmkXmlStr) "running_on", (pcmkXmlStr) host_uname); + } + + cli_resource_check(out, cib_conn, rsc); + + } else if ((rsc == NULL) && (host_uname != NULL)) { + const char* host_uname = node->details->uname; + GListPtr allResources = node->details->allocated_rsc; + GListPtr activeResources = node->details->running_rsc; + GListPtr unactiveResources = pcmk__subtract_lists(allResources, activeResources, (GCompareFunc) strcmp); + GListPtr lpc = NULL; + + pcmk__output_xml_create_parent(out, "resources"); + + for (lpc = activeResources; lpc != NULL; lpc = lpc->next) { + pe_resource_t *rsc = (pe_resource_t *) lpc->data; + xmlNode *rsc_node = NULL; + + rsc_node = pcmk__output_xml_create_parent(out, "resource"); + xmlSetProp(rsc_node, (pcmkXmlStr) "id", (pcmkXmlStr) rsc->id); + xmlSetProp(rsc_node, (pcmkXmlStr) "running", (pcmkXmlStr) "true"); + xmlSetProp(rsc_node, (pcmkXmlStr) "host", (pcmkXmlStr) host_uname); + + cli_resource_check(out, cib_conn, rsc); + pcmk__output_xml_pop_parent(out); + } + + for(lpc = unactiveResources; lpc != NULL; lpc = lpc->next) { + pe_resource_t *rsc = (pe_resource_t *) lpc->data; + xmlNode *rsc_node = NULL; + + rsc_node = pcmk__output_xml_create_parent(out, "resource"); + xmlSetProp(rsc_node, (pcmkXmlStr) "id", (pcmkXmlStr) rsc->id); + xmlSetProp(rsc_node, (pcmkXmlStr) "running", (pcmkXmlStr) "false"); + xmlSetProp(rsc_node, (pcmkXmlStr) "host", (pcmkXmlStr) host_uname); + + cli_resource_check(out, cib_conn, rsc); + pcmk__output_xml_pop_parent(out); + } + + pcmk__output_xml_pop_parent(out); + g_list_free(allResources); + g_list_free(activeResources); + g_list_free(unactiveResources); + + } else if ((rsc != NULL) && (host_uname == NULL)) { + GListPtr hosts = NULL; + + rsc->fns->location(rsc, &hosts, TRUE); + xmlSetProp(xml_node, (pcmkXmlStr) "running", + (pcmkXmlStr) pcmk__btoa(hosts != NULL)); + cli_resource_check(out, cib_conn, rsc); + g_list_free(hosts); + } + + return pcmk_rc_ok; +} + static void add_resource_name(pcmk__output_t *out, pe_resource_t *rsc) { if (rsc->children == NULL) { @@ -325,6 +581,10 @@ static pcmk__message_entry_t fmt_functions[] = { { "attribute", "text", attribute_text }, { "property", "default", property_default }, { "property", "text", property_text }, + { "resource-check", "default", resource_check_default }, + { "resource-check", "xml", resource_check_xml }, + { "resource-why", "default", resource_why_default }, + { "resource-why", "xml", resource_why_xml }, { "resource-names-list", "default", resource_names }, { NULL, NULL, NULL } diff --git a/tools/crm_resource_runtime.c b/tools/crm_resource_runtime.c index bd377a3..4f8287b 100644 --- a/tools/crm_resource_runtime.c +++ b/tools/crm_resource_runtime.c @@ -43,6 +43,35 @@ do_find_resource(pcmk__output_t *out, const char *rsc, pe_resource_t * the_rsc, return found; } +resource_checks_t * +cli_check_resource(pe_resource_t *rsc, char *role_s, char *managed) +{ + pe_resource_t *parent = uber_parent(rsc); + resource_checks_t *rc = calloc(1, sizeof(resource_checks_t)); + + if (role_s) { + enum rsc_role_e role = text2role(role_s); + + if (role == RSC_ROLE_STOPPED) { + rc->flags |= rsc_remain_stopped; + } else if (pcmk_is_set(parent->flags, pe_rsc_promotable) && + role == RSC_ROLE_SLAVE) { + rc->flags |= rsc_unpromotable; + } + } + + if (managed && !crm_is_true(managed)) { + rc->flags |= rsc_unmanaged; + } + + if (rsc->lock_node) { + rc->lock_node = rsc->lock_node->details->uname; + } + + rc->rsc = rsc; + return rc; +} + int cli_resource_search(pcmk__output_t *out, pe_resource_t *rsc, const char *requested_name, pe_working_set_t *data_set) @@ -878,13 +907,14 @@ cli_cleanup_all(pcmk__output_t *out, pcmk_ipc_api_t *controld_api, return rc; } -void +int cli_resource_check(pcmk__output_t *out, cib_t * cib_conn, pe_resource_t *rsc) { - bool printed = false; char *role_s = NULL; char *managed = NULL; pe_resource_t *parent = uber_parent(rsc); + int rc = pcmk_rc_no_output; + resource_checks_t *checks = NULL; find_resource_attr(out, cib_conn, XML_NVPAIR_ATTR_VALUE, parent->id, NULL, NULL, NULL, XML_RSC_ATTR_MANAGED, &managed); @@ -892,41 +922,16 @@ cli_resource_check(pcmk__output_t *out, cib_t * cib_conn, pe_resource_t *rsc) find_resource_attr(out, cib_conn, XML_NVPAIR_ATTR_VALUE, parent->id, NULL, NULL, NULL, XML_RSC_ATTR_TARGET_ROLE, &role_s); - if(role_s) { - enum rsc_role_e role = text2role(role_s); + checks = cli_check_resource(rsc, role_s, managed); - free(role_s); - if(role == RSC_ROLE_UNKNOWN) { - // Treated as if unset - - } else if(role == RSC_ROLE_STOPPED) { - printf("\n * Configuration specifies '%s' should remain stopped\n", - parent->id); - printed = true; - - } else if (pcmk_is_set(parent->flags, pe_rsc_promotable) - && (role == RSC_ROLE_SLAVE)) { - printf("\n * Configuration specifies '%s' should not be promoted\n", - parent->id); - printed = true; - } + if (checks->flags != 0 || checks->lock_node != NULL) { + rc = out->message(out, "resource-check", checks); } - if (managed && !crm_is_true(managed)) { - printf("%s * Configuration prevents cluster from stopping or starting unmanaged '%s'\n", - (printed? "" : "\n"), parent->id); - printed = true; - } + free(role_s); free(managed); - - if (rsc->lock_node) { - printf("%s * '%s' is locked to node %s due to shutdown\n", - (printed? "" : "\n"), parent->id, rsc->lock_node->details->uname); - } - - if (printed) { - printf("\n"); - } + free(checks); + return rc; } // \return Standard Pacemaker return code @@ -986,7 +991,7 @@ generate_resource_params(pe_resource_t * rsc, pe_working_set_t * data_set) return combined; } -static bool resource_is_running_on(pe_resource_t *rsc, const char *host) +bool resource_is_running_on(pe_resource_t *rsc, const char *host) { bool found = TRUE; GListPtr hIter = NULL; @@ -1977,100 +1982,3 @@ cli_resource_move(pcmk__output_t *out, pe_resource_t *rsc, const char *rsc_id, return rc; } - -static void -cli_resource_why_without_rsc_and_host(pcmk__output_t *out, cib_t *cib_conn, - GListPtr resources) -{ - GListPtr lpc = NULL; - GListPtr hosts = NULL; - - for (lpc = resources; lpc != NULL; lpc = lpc->next) { - pe_resource_t *rsc = (pe_resource_t *) lpc->data; - rsc->fns->location(rsc, &hosts, TRUE); - - if (hosts == NULL) { - printf("Resource %s is not running\n", rsc->id); - } else { - printf("Resource %s is running\n", rsc->id); - } - - cli_resource_check(out, cib_conn, rsc); - g_list_free(hosts); - hosts = NULL; - } - -} - -static void -cli_resource_why_with_rsc_and_host(pcmk__output_t *out, cib_t *cib_conn, - GListPtr resources, pe_resource_t *rsc, - const char *host_uname) -{ - if (resource_is_running_on(rsc, host_uname)) { - printf("Resource %s is running on host %s\n",rsc->id,host_uname); - } else { - printf("Resource %s is not running on host %s\n", rsc->id, host_uname); - } - cli_resource_check(out, cib_conn, rsc); -} - -static void -cli_resource_why_without_rsc_with_host(pcmk__output_t *out, cib_t *cib_conn, - GListPtr resources, pe_node_t *node) -{ - const char* host_uname = node->details->uname; - GListPtr allResources = node->details->allocated_rsc; - GListPtr activeResources = node->details->running_rsc; - GListPtr unactiveResources = pcmk__subtract_lists(allResources,activeResources,(GCompareFunc) strcmp); - GListPtr lpc = NULL; - - for (lpc = activeResources; lpc != NULL; lpc = lpc->next) { - pe_resource_t *rsc = (pe_resource_t *) lpc->data; - printf("Resource %s is running on host %s\n",rsc->id,host_uname); - cli_resource_check(out, cib_conn, rsc); - } - - for(lpc = unactiveResources; lpc != NULL; lpc = lpc->next) { - pe_resource_t *rsc = (pe_resource_t *) lpc->data; - printf("Resource %s is assigned to host %s but not running\n", - rsc->id, host_uname); - cli_resource_check(out, cib_conn, rsc); - } - - g_list_free(allResources); - g_list_free(activeResources); - g_list_free(unactiveResources); -} - -static void -cli_resource_why_with_rsc_without_host(pcmk__output_t *out, cib_t *cib_conn, - GListPtr resources, pe_resource_t *rsc) -{ - GListPtr hosts = NULL; - - rsc->fns->location(rsc, &hosts, TRUE); - printf("Resource %s is %srunning\n", rsc->id, (hosts? "" : "not ")); - cli_resource_check(out, cib_conn, rsc); - g_list_free(hosts); -} - -void cli_resource_why(pcmk__output_t *out, cib_t *cib_conn, GListPtr resources, - pe_resource_t *rsc, pe_node_t *node) -{ - const char *host_uname = (node == NULL)? NULL : node->details->uname; - - if ((rsc == NULL) && (host_uname == NULL)) { - cli_resource_why_without_rsc_and_host(out, cib_conn, resources); - - } else if ((rsc != NULL) && (host_uname != NULL)) { - cli_resource_why_with_rsc_and_host(out, cib_conn, resources, rsc, - host_uname); - - } else if ((rsc == NULL) && (host_uname != NULL)) { - cli_resource_why_without_rsc_with_host(out, cib_conn, resources, node); - - } else if ((rsc != NULL) && (host_uname == NULL)) { - cli_resource_why_with_rsc_without_host(out, cib_conn, resources, rsc); - } -}