diff --git a/include/crm/lrmd_internal.h b/include/crm/lrmd_internal.h index 498a9ba..720e1a3 100644 --- a/include/crm/lrmd_internal.h +++ b/include/crm/lrmd_internal.h @@ -15,6 +15,7 @@ #include // xmlNode #include // crm_ipc_t #include // mainloop_io_t, ipc_client_callbacks +#include // pcmk__output_t #include // pcmk__remote_t #include // lrmd_t, lrmd_event_data_t @@ -66,4 +67,6 @@ void remote_proxy_relay_event(remote_proxy_t *proxy, xmlNode *msg); void remote_proxy_relay_response(remote_proxy_t *proxy, xmlNode *msg, int msg_id); +void lrmd__register_messages(pcmk__output_t *out); + #endif diff --git a/lib/lrmd/Makefile.am b/lib/lrmd/Makefile.am index 41ba7fd..09e40b1 100644 --- a/lib/lrmd/Makefile.am +++ b/lib/lrmd/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2012-2018 the Pacemaker project contributors +# Copyright 2012-2020 the Pacemaker project contributors # # The version control history for this file may have further details. # @@ -18,4 +18,4 @@ liblrmd_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB) liblrmd_la_LIBADD = $(top_builddir)/lib/common/libcrmcommon.la \ $(top_builddir)/lib/services/libcrmservice.la \ $(top_builddir)/lib/fencing/libstonithd.la -liblrmd_la_SOURCES = lrmd_client.c proxy_common.c lrmd_alerts.c +liblrmd_la_SOURCES = lrmd_client.c proxy_common.c lrmd_alerts.c lrmd_output.c diff --git a/lib/lrmd/lrmd_output.c b/lib/lrmd/lrmd_output.c new file mode 100644 index 0000000..7dc0709 --- /dev/null +++ b/lib/lrmd/lrmd_output.c @@ -0,0 +1,145 @@ +/* + * Copyright 2020 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU Lesser General Public License + * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. + */ + +#include +#include + +#include +#include + +static int +default_list(pcmk__output_t *out, lrmd_list_t *list, const char *title) { + lrmd_list_t *iter = NULL; + + out->begin_list(out, NULL, NULL, "%s", title); + + for (iter = list; iter != NULL; iter = iter->next) { + out->list_item(out, NULL, "%s", iter->val); + } + + out->end_list(out); + lrmd_list_freeall(list); + return pcmk_rc_ok; +} + +static int +xml_list(pcmk__output_t *out, lrmd_list_t *list, const char *ele) { + lrmd_list_t *iter = NULL; + + for (iter = list; iter != NULL; iter = iter->next) { + pcmk__output_create_xml_text_node(out, ele, iter->val); + } + + lrmd_list_freeall(list); + return pcmk_rc_ok; +} + +PCMK__OUTPUT_ARGS("alternatives-list", "lrmd_list_t *", "const char *") +static int +lrmd__alternatives_list_xml(pcmk__output_t *out, va_list args) { + lrmd_list_t *list = va_arg(args, lrmd_list_t *); + const char *agent_spec = va_arg(args, const char *); + + xmlNodePtr node = pcmk__output_xml_create_parent(out, "providers"); + + xmlSetProp(node, (pcmkXmlStr) "for", (pcmkXmlStr) agent_spec); + return xml_list(out, list, "provider"); +} + +PCMK__OUTPUT_ARGS("alternatives-list", "lrmd_list_t *", "const char *") +static int +lrmd__alternatives_list(pcmk__output_t *out, va_list args) { + lrmd_list_t *list = va_arg(args, lrmd_list_t *); + const char *agent_spec G_GNUC_UNUSED = va_arg(args, const char *); + + return default_list(out, list, "Providers"); +} + +PCMK__OUTPUT_ARGS("agents-list", "lrmd_list_t *", "const char *", "char *") +static int +lrmd__agents_list_xml(pcmk__output_t *out, va_list args) { + lrmd_list_t *list = va_arg(args, lrmd_list_t *); + const char *agent_spec = va_arg(args, const char *); + char *provider = va_arg(args, char *); + + xmlNodePtr node = pcmk__output_xml_create_parent(out, "agents"); + xmlSetProp(node, (pcmkXmlStr) "standard", (pcmkXmlStr) agent_spec); + + if (!pcmk__str_empty(provider)) { + xmlSetProp(node, (pcmkXmlStr) "provider", (pcmkXmlStr) provider); + } + + return xml_list(out, list, "agent"); +} + +PCMK__OUTPUT_ARGS("agents-list", "lrmd_list_t *", "const char *", "char *") +static int +lrmd__agents_list(pcmk__output_t *out, va_list args) { + lrmd_list_t *list = va_arg(args, lrmd_list_t *); + const char *agent_spec = va_arg(args, const char *); + char *provider = va_arg(args, char *); + + int rc; + char *title = crm_strdup_printf("%s agents", pcmk__str_empty(provider) ? agent_spec : provider); + + rc = default_list(out, list, title); + free(title); + return rc; +} + +PCMK__OUTPUT_ARGS("providers-list", "lrmd_list_t *", "const char *") +static int +lrmd__providers_list_xml(pcmk__output_t *out, va_list args) { + lrmd_list_t *list = va_arg(args, lrmd_list_t *); + const char *agent_spec = va_arg(args, const char *); + + xmlNodePtr node = pcmk__output_xml_create_parent(out, "providers"); + + xmlSetProp(node, (pcmkXmlStr) "standard", (pcmkXmlStr) "ocf"); + + if (agent_spec != NULL) { + xmlSetProp(node, (pcmkXmlStr) "agent", (pcmkXmlStr) agent_spec); + } + + return xml_list(out, list, "provider"); +} + +PCMK__OUTPUT_ARGS("providers-list", "lrmd_list_t *", "const char *") +static int +lrmd__providers_list(pcmk__output_t *out, va_list args) { + lrmd_list_t *list = va_arg(args, lrmd_list_t *); + const char *agent_spec G_GNUC_UNUSED = va_arg(args, const char *); + + return default_list(out, list, "Providers"); +} + +PCMK__OUTPUT_ARGS("standards-list", "lrmd_list_t *") +static int +lrmd__standards_list(pcmk__output_t *out, va_list args) { + lrmd_list_t *list = va_arg(args, lrmd_list_t *); + + return default_list(out, list, "Standards"); +} + +static pcmk__message_entry_t fmt_functions[] = { + { "alternatives-list", "default", lrmd__alternatives_list }, + { "alternatives-list", "xml", lrmd__alternatives_list_xml }, + { "agents-list", "default", lrmd__agents_list }, + { "agents-list", "xml", lrmd__agents_list_xml }, + { "providers-list", "default", lrmd__providers_list }, + { "providers-list", "xml", lrmd__providers_list_xml }, + { "standards-list", "default", lrmd__standards_list }, + + { NULL, NULL, NULL } +}; + +void +lrmd__register_messages(pcmk__output_t *out) { + pcmk__register_messages(out, fmt_functions); +} diff --git a/tools/crm_resource.c b/tools/crm_resource.c index 89e475b..38ea71f 100644 --- a/tools/crm_resource.c +++ b/tools/crm_resource.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -1092,25 +1093,24 @@ static int list_agents(pcmk__output_t *out, const char *agent_spec, crm_exit_t *exit_code) { int rc = pcmk_rc_ok; - lrmd_list_t *list = NULL; - lrmd_list_t *iter = NULL; char *provider = strchr(agent_spec, ':'); lrmd_t *lrmd_conn = lrmd_api_new(); + lrmd_list_t *list = NULL; if (provider) { *provider++ = 0; } + rc = lrmd_conn->cmds->list_agents(lrmd_conn, &list, agent_spec, provider); if (rc > 0) { - for (iter = list; iter != NULL; iter = iter->next) { - printf("%s\n", iter->val); - } - lrmd_list_freeall(list); - rc = pcmk_rc_ok; + rc = out->message(out, "agents-list", list, agent_spec, provider); } else { - *exit_code = CRM_EX_NOSUCH; rc = pcmk_rc_error; + } + + if (rc != pcmk_rc_ok) { + *exit_code = CRM_EX_NOSUCH; if (provider == NULL) { g_set_error(&error, PCMK__EXITC_ERROR, *exit_code, "No agents found for standard '%s'", agent_spec); @@ -1130,19 +1130,41 @@ list_providers(pcmk__output_t *out, const char *agent_spec, crm_exit_t *exit_cod { int rc; const char *text = NULL; - lrmd_list_t *list = NULL; - lrmd_list_t *iter = NULL; lrmd_t *lrmd_conn = lrmd_api_new(); + lrmd_list_t *list = NULL; switch (options.rsc_cmd) { + case cmd_list_alternatives: + rc = lrmd_conn->cmds->list_ocf_providers(lrmd_conn, agent_spec, &list); + + if (rc > 0) { + rc = out->message(out, "alternatives-list", list, agent_spec); + } else { + rc = pcmk_rc_error; + } + + text = "OCF providers"; + break; case cmd_list_standards: rc = lrmd_conn->cmds->list_standards(lrmd_conn, &list); + + if (rc > 0) { + rc = out->message(out, "standards-list", list); + } else { + rc = pcmk_rc_error; + } + text = "standards"; break; case cmd_list_providers: - case cmd_list_alternatives: - rc = lrmd_conn->cmds->list_ocf_providers(lrmd_conn, agent_spec, - &list); + rc = lrmd_conn->cmds->list_ocf_providers(lrmd_conn, agent_spec, &list); + + if (rc > 0) { + rc = out->message(out, "providers-list", list, agent_spec); + } else { + rc = pcmk_rc_error; + } + text = "OCF providers"; break; default: @@ -1152,24 +1174,19 @@ list_providers(pcmk__output_t *out, const char *agent_spec, crm_exit_t *exit_cod return pcmk_rc_error; } - if (rc > 0) { - for (iter = list; iter != NULL; iter = iter->next) { - printf("%s\n", iter->val); - } - lrmd_list_freeall(list); - rc = pcmk_rc_ok; - - } else if (agent_spec != NULL) { - *exit_code = CRM_EX_NOSUCH; - rc = pcmk_rc_error; - g_set_error(&error, PCMK__EXITC_ERROR, *exit_code, - "No %s found for %s", text, agent_spec); + if (rc != pcmk_rc_ok) { + if (agent_spec != NULL) { + *exit_code = CRM_EX_NOSUCH; + rc = pcmk_rc_error; + g_set_error(&error, PCMK__EXITC_ERROR, *exit_code, + "No %s found for %s", text, agent_spec); - } else { - *exit_code = CRM_EX_NOSUCH; - rc = pcmk_rc_error; - g_set_error(&error, PCMK__EXITC_ERROR, *exit_code, - "No %s found", text); + } else { + *exit_code = CRM_EX_NOSUCH; + rc = pcmk_rc_error; + g_set_error(&error, PCMK__EXITC_ERROR, *exit_code, + "No %s found", text); + } } lrmd_api_delete(lrmd_conn); @@ -1618,6 +1635,7 @@ main(int argc, char **argv) pe__register_messages(out); crm_resource_register_messages(out); + lrmd__register_messages(out); if (args->version) { out->version(out, false);