diff --git a/lib/common/ipc_attrd.c b/lib/common/ipc_attrd.c index c645bb5cc0..ecb9df9f31 100644 --- a/lib/common/ipc_attrd.c +++ b/lib/common/ipc_attrd.c @@ -1,322 +1,359 @@ /* * Copyright 2011-2022 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. */ #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include "crmcommon_private.h" static void set_pairs_data(pcmk__attrd_api_reply_t *data, xmlNode *msg_data) { const char *name = NULL; pcmk__attrd_query_pair_t *pair; name = crm_element_value(msg_data, PCMK__XA_ATTR_NAME); for (xmlNode *node = first_named_child(msg_data, XML_CIB_TAG_NODE); node != NULL; node = crm_next_same_xml(node)) { pair = calloc(1, sizeof(pcmk__attrd_query_pair_t)); CRM_ASSERT(pair != NULL); pair->node = crm_element_value(node, PCMK__XA_ATTR_NODE_NAME); pair->name = name; pair->value = crm_element_value(node, PCMK__XA_ATTR_VALUE); data->data.pairs = g_list_prepend(data->data.pairs, pair); } } static bool reply_expected(pcmk_ipc_api_t *api, xmlNode *request) { const char *command = crm_element_value(request, PCMK__XA_TASK); /* Only the query command gets a reply. */ return pcmk__str_any_of(command, PCMK__ATTRD_CMD_QUERY, NULL); } static bool dispatch(pcmk_ipc_api_t *api, xmlNode *reply) { const char *value = NULL; crm_exit_t status = CRM_EX_OK; pcmk__attrd_api_reply_t reply_data = { pcmk__attrd_reply_unknown }; if (pcmk__str_eq((const char *) reply->name, "ack", pcmk__str_none)) { return false; } /* Do some basic validation of the reply */ value = crm_element_value(reply, F_TYPE); if (value == NULL || !pcmk__str_eq(value, T_ATTRD, pcmk__str_none)) { crm_debug("Unrecognizable attrd message: invalid message type '%s'", crm_str(value)); status = CRM_EX_PROTOCOL; goto done; } /* Only the query command gets a reply for now. */ value = crm_element_value(reply, F_SUBTYPE); if (pcmk__str_eq(value, PCMK__ATTRD_CMD_QUERY, pcmk__str_null_matches)) { /* This likely means the client gave us an attribute name that doesn't * exist. */ if (!xmlHasProp(reply, (pcmkXmlStr) PCMK__XA_ATTR_NAME)) { crm_debug("Empty attrd message: no attribute name"); status = ENXIO; goto done; } reply_data.reply_type = pcmk__attrd_reply_query; set_pairs_data(&reply_data, reply); } else { crm_debug("Cannot handle a reply from message type '%s'", crm_str(value)); status = CRM_EX_PROTOCOL; goto done; } done: pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data); /* Free any reply data that was allocated */ if (reply_data.data.pairs) { g_list_free_full(reply_data.data.pairs, free); } return false; } pcmk__ipc_methods_t * pcmk__attrd_api_methods() { pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t)); if (cmds != NULL) { cmds->new_data = NULL; cmds->free_data = NULL; cmds->post_connect = NULL; cmds->reply_expected = reply_expected; cmds->dispatch = dispatch; } return cmds; } /*! * \internal * \brief Create a generic pacemaker-attrd operation * * \param[in] user_name If not NULL, ACL user to set for operation * * \return XML of pacemaker-attrd operation */ static xmlNode * create_attrd_op(const char *user_name) { xmlNode *attrd_op = create_xml_node(NULL, __func__); crm_xml_add(attrd_op, F_TYPE, T_ATTRD); crm_xml_add(attrd_op, F_ORIG, (crm_system_name? crm_system_name: "unknown")); crm_xml_add(attrd_op, PCMK__XA_ATTR_USER, user_name); return attrd_op; } static int send_attrd_request(pcmk_ipc_api_t *api, xmlNode *request) { return pcmk__send_ipc_request(api, request); } int pcmk__attrd_api_clear_failures(pcmk_ipc_api_t *api, const char *node, const char *resource, const char *operation, const char *interval_spec, const char *user_name, uint32_t options) { int rc = pcmk_rc_ok; xmlNode *request = create_attrd_op(user_name); const char *interval_desc = NULL; const char *op_desc = NULL; + const char *target = pcmk__node_attr_target(node); + + if (target != NULL) { + node = target; + } crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_CLEAR_FAILURE); crm_xml_add(request, PCMK__XA_ATTR_NODE_NAME, node); crm_xml_add(request, PCMK__XA_ATTR_RESOURCE, resource); crm_xml_add(request, PCMK__XA_ATTR_OPERATION, operation); crm_xml_add(request, PCMK__XA_ATTR_INTERVAL, interval_spec); crm_xml_add_int(request, PCMK__XA_ATTR_IS_REMOTE, pcmk_is_set(options, pcmk__node_attr_remote)); rc = send_attrd_request(api, request); free_xml(request); if (operation) { interval_desc = interval_spec? interval_spec : "nonrecurring"; op_desc = operation; } else { interval_desc = "all"; op_desc = "operations"; } crm_debug("Asked pacemaker-attrd to clear failure of %s %s for %s on %s: %s (%d)", interval_desc, op_desc, (resource? resource : "all resources"), (node? node : "all nodes"), pcmk_rc_str(rc), rc); return rc; } int pcmk__attrd_api_delete(pcmk_ipc_api_t *api, const char *node, const char *name, uint32_t options) { + const char *target = NULL; + if (name == NULL) { return EINVAL; } + target = pcmk__node_attr_target(node); + + if (target != NULL) { + node = target; + } + /* Make sure the right update option is set. */ options &= ~pcmk__node_attr_delay; options |= pcmk__node_attr_value; return pcmk__attrd_api_update(api, node, name, NULL, NULL, NULL, NULL, options); } int pcmk__attrd_api_purge(pcmk_ipc_api_t *api, const char *node) { int rc = pcmk_rc_ok; xmlNode *request = NULL; const char *display_host = (node ? node : "localhost"); + const char *target = pcmk__node_attr_target(node); + + if (target != NULL) { + node = target; + } request = create_attrd_op(NULL); crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_PEER_REMOVE); crm_xml_add(request, PCMK__XA_ATTR_NODE_NAME, node); rc = send_attrd_request(api, request); free_xml(request); crm_debug("Asked pacemaker-attrd to purge %s: %s (%d)", display_host, pcmk_rc_str(rc), rc); return rc; } int pcmk__attrd_api_query(pcmk_ipc_api_t *api, const char *node, const char *name, uint32_t options) { int rc = pcmk_rc_ok; xmlNode *request = NULL; + const char *target = NULL; if (name == NULL) { return EINVAL; } + target = pcmk__node_attr_target(node); + + if (target != NULL) { + node = target; + } + request = create_attrd_op(NULL); crm_xml_add(request, PCMK__XA_ATTR_NAME, name); crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_QUERY); crm_xml_add(request, PCMK__XA_ATTR_NODE_NAME, node); rc = send_attrd_request(api, request); free_xml(request); if (node) { crm_debug("Queried pacemaker-attrd for %s on %s: %s (%d)", name, node, pcmk_rc_str(rc), rc); } else { crm_debug("Queried pacemaker-attrd for %s: %s (%d)", name, pcmk_rc_str(rc), rc); } return rc; } int pcmk__attrd_api_refresh(pcmk_ipc_api_t *api, const char *node) { int rc = pcmk_rc_ok; xmlNode *request = NULL; const char *display_host = (node ? node : "localhost"); + const char *target = pcmk__node_attr_target(node); + + if (target != NULL) { + node = target; + } request = create_attrd_op(NULL); crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_REFRESH); crm_xml_add(request, PCMK__XA_ATTR_NODE_NAME, node); rc = send_attrd_request(api, request); free_xml(request); crm_debug("Asked pacemaker-attrd to refresh %s: %s (%d)", display_host, pcmk_rc_str(rc), rc); return rc; } int pcmk__attrd_api_update(pcmk_ipc_api_t *api, const char *node, const char *name, const char *value, const char *dampen, const char *set, const char *user_name, uint32_t options) { int rc = pcmk_rc_ok; xmlNode *request = NULL; const char *display_host = (node ? node : "localhost"); + const char *target = NULL; if (name == NULL) { return EINVAL; } + target = pcmk__node_attr_target(node); + + if (target != NULL) { + node = target; + } + request = create_attrd_op(user_name); if (pcmk_is_set(options, pcmk__node_attr_pattern)) { crm_xml_add(request, PCMK__XA_ATTR_PATTERN, name); } else { crm_xml_add(request, PCMK__XA_ATTR_NAME, name); } if (pcmk_all_flags_set(options, pcmk__node_attr_value | pcmk__node_attr_delay)) { crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE_BOTH); } else if (pcmk_is_set(options, pcmk__node_attr_value)) { crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE); } else if (pcmk_is_set(options, pcmk__node_attr_delay)) { crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE_DELAY); } crm_xml_add(request, PCMK__XA_ATTR_VALUE, value); crm_xml_add(request, PCMK__XA_ATTR_DAMPENING, dampen); crm_xml_add(request, PCMK__XA_ATTR_NODE_NAME, node); crm_xml_add(request, PCMK__XA_ATTR_SET, set); crm_xml_add_int(request, PCMK__XA_ATTR_IS_REMOTE, pcmk_is_set(options, pcmk__node_attr_remote)); crm_xml_add_int(request, PCMK__XA_ATTR_IS_PRIVATE, pcmk_is_set(options, pcmk__node_attr_private)); rc = send_attrd_request(api, request); free_xml(request); crm_debug("Asked pacemaker-attrd to update %s on %s: %s (%d)", name, display_host, pcmk_rc_str(rc), rc); return rc; } diff --git a/tools/attrd_updater.c b/tools/attrd_updater.c index deaf1c8e2d..039dc82a10 100644 --- a/tools/attrd_updater.c +++ b/tools/attrd_updater.c @@ -1,465 +1,451 @@ /* * Copyright 2004-2022 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SUMMARY "query and update Pacemaker node attributes" static pcmk__supported_format_t formats[] = { PCMK__SUPPORTED_FORMAT_NONE, PCMK__SUPPORTED_FORMAT_TEXT, PCMK__SUPPORTED_FORMAT_XML, { NULL, NULL, NULL } }; GError *error = NULL; bool printed_values = false; struct { char command; gchar *attr_dampen; gchar *attr_name; gchar *attr_node; gchar *attr_set; char *attr_value; int attr_options; gboolean query_all; } options = { .attr_options = pcmk__node_attr_none, .command = 'Q', }; static gboolean command_cb (const gchar *option_name, const gchar *optarg, gpointer data, GError **err) { pcmk__str_update(&options.attr_value, optarg); if (pcmk__str_any_of(option_name, "--update-both", "-B", NULL)) { options.command = 'B'; } else if (pcmk__str_any_of(option_name, "--delete", "-D", NULL)) { options.command = 'D'; } else if (pcmk__str_any_of(option_name, "--query", "-Q", NULL)) { options.command = 'Q'; } else if (pcmk__str_any_of(option_name, "--refresh", "-R", NULL)) { options.command = 'R'; } else if (pcmk__str_any_of(option_name, "--update", "-U", "-v", NULL)) { options.command = 'U'; } else if (pcmk__str_any_of(option_name, "--update-delay", "-Y", NULL)) { options.command = 'Y'; } return TRUE; } static gboolean private_cb (const gchar *option_name, const gchar *optarg, gpointer data, GError **err) { pcmk__set_node_attr_flags(options.attr_options, pcmk__node_attr_private); return TRUE; } static gboolean section_cb (const gchar *option_name, const gchar *optarg, gpointer data, GError **err) { if (pcmk__str_any_of(optarg, "nodes", "forever", NULL)) { pcmk__set_node_attr_flags(options.attr_options, pcmk__node_attr_perm); } else if (pcmk__str_any_of(optarg, "status", "reboot", NULL)) { pcmk__clear_node_attr_flags(options.attr_options, pcmk__node_attr_perm); } else { g_set_error(err, PCMK__EXITC_ERROR, CRM_EX_USAGE, "Unknown value for --lifetime: %s", optarg); return FALSE; } return TRUE; } #define INDENT " " static GOptionEntry required_entries[] = { { "name", 'n', 0, G_OPTION_ARG_STRING, &options.attr_name, "The attribute's name", "NAME" }, { NULL } }; static GOptionEntry command_entries[] = { { "update", 'U', 0, G_OPTION_ARG_CALLBACK, command_cb, "Update attribute's value in pacemaker-attrd. If this causes the value\n" INDENT "to change, it will also be updated in the cluster configuration.", "VALUE" }, { "update-both", 'B', 0, G_OPTION_ARG_CALLBACK, command_cb, "Update attribute's value and time to wait (dampening) in\n" INDENT "pacemaker-attrd. If this causes the value or dampening to change,\n" INDENT "the attribute will also be written to the cluster configuration,\n" INDENT "so be aware that repeatedly changing the dampening reduces its\n" INDENT "effectiveness.", "VALUE" }, { "update-delay", 'Y', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb, "Update attribute's dampening in pacemaker-attrd (requires\n" INDENT "-d/--delay). If this causes the dampening to change, the\n" INDENT "attribute will also be written to the cluster configuration, so\n" INDENT "be aware that repeatedly changing the dampening reduces its\n" INDENT "effectiveness.", NULL }, { "query", 'Q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb, "Query the attribute's value from pacemaker-attrd", NULL }, { "delete", 'D', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb, "Unset attribute from pacemaker-attrd. At the moment, there is no way\n" INDENT "to remove an attribute. This option will instead set its value\n" INDENT "to the empty string.", NULL }, { "refresh", 'R', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb, "(Advanced) Force the pacemaker-attrd daemon to resend all current\n" INDENT "values to the CIB", NULL }, { NULL } }; static GOptionEntry addl_entries[] = { { "delay", 'd', 0, G_OPTION_ARG_STRING, &options.attr_dampen, "The time to wait (dampening) in seconds for further changes\n" INDENT "before sending to the CIB", "SECONDS" }, { "set", 's', 0, G_OPTION_ARG_STRING, &options.attr_set, "(Advanced) The attribute set in which to place the value", "SET" }, { "node", 'N', 0, G_OPTION_ARG_STRING, &options.attr_node, "Set the attribute for the named node (instead of the local one)", "NODE" }, { "all", 'A', 0, G_OPTION_ARG_NONE, &options.query_all, "Show values of the attribute for all nodes (query only)", NULL }, { "lifetime", 'l', 0, G_OPTION_ARG_CALLBACK, section_cb, "(Not yet implemented) Lifetime of the node attribute (silently\n" INDENT "ignored by cluster)", "SECTION" }, { "private", 'p', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, private_cb, "If this creates a new attribute, never write the attribute to CIB", NULL }, { NULL } }; static GOptionEntry deprecated_entries[] = { { "update", 'v', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, command_cb, NULL, NULL }, { "section", 'S', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, section_cb, NULL, NULL }, { NULL } }; static int send_attrd_query(pcmk__output_t *out, const char *attr_name, const char *attr_node, gboolean query_all); static int send_attrd_update(char command, const char *attr_node, const char *attr_name, const char *attr_value, const char *attr_set, const char *attr_dampen, uint32_t attr_options); static GOptionContext * build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) { GOptionContext *context = NULL; context = pcmk__build_arg_context(args, "text (default), xml", group, NULL); pcmk__add_arg_group(context, "required", "Required Arguments:", "Show required arguments", required_entries); pcmk__add_arg_group(context, "command", "Command:", "Show command options (mutually exclusive)", command_entries); pcmk__add_arg_group(context, "additional", "Additional Options:", "Show additional options", addl_entries); pcmk__add_arg_group(context, "deprecated", "Deprecated Options:", "Show deprecated options", deprecated_entries); return context; } int main(int argc, char **argv) { int rc = pcmk_rc_ok; crm_exit_t exit_code = CRM_EX_OK; pcmk__output_t *out = NULL; GOptionGroup *output_group = NULL; pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY); GOptionContext *context = build_arg_context(args, &output_group); gchar **processed_args = pcmk__cmdline_preproc(argv, "dlnsvBNUS"); pcmk__register_formats(output_group, formats); if (!g_option_context_parse_strv(context, &processed_args, &error)) { exit_code = CRM_EX_USAGE; goto done; } pcmk__cli_init_logging("attrd_updater", args->verbosity); rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s", args->output_ty, pcmk_rc_str(rc)); goto done; } if (args->version) { out->version(out, false); goto done; } if (options.command != 'R' && options.attr_name == NULL) { exit_code = CRM_EX_USAGE; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Command requires --name argument"); goto done; } pcmk__register_lib_messages(out); if (options.command == 'Q') { int rc = send_attrd_query(out, options.attr_name, options.attr_node, options.query_all); exit_code = pcmk_rc2exitc(rc); } else { /* @TODO We don't know whether the specified node is a Pacemaker Remote * node or not, so we can't set pcmk__node_attr_remote when appropriate. * However, it's not a big problem, because pacemaker-attrd will learn * and remember a node's "remoteness". */ - const char *target = pcmk__node_attr_target(options.attr_node); - - int rc = send_attrd_update(options.command, - target == NULL ? options.attr_node : target, + int rc = send_attrd_update(options.command, options.attr_node, options.attr_name, options.attr_value, options.attr_set, options.attr_dampen, options.attr_options); exit_code = pcmk_rc2exitc(rc); } done: g_strfreev(processed_args); pcmk__free_arg_context(context); g_free(options.attr_dampen); g_free(options.attr_name); g_free(options.attr_node); g_free(options.attr_set); free(options.attr_value); pcmk__output_and_clear_error(error, out); if (out != NULL) { out->finish(out, exit_code, true, NULL); pcmk__output_free(out); } crm_exit(exit_code); } /*! * \brief Print the attribute values in a pacemaker-attrd XML query reply * * \param[in] reply List of attribute name/value pairs * \param[in] attr_name Name of attribute that was queried * * \return true if any values were printed */ static void print_attrd_values(pcmk__output_t *out, GList *reply) { for (GList *iter = reply; iter != NULL; iter = iter->next) { pcmk__attrd_query_pair_t *pair = (pcmk__attrd_query_pair_t *) iter->data; out->message(out, "attribute", NULL, NULL, pair->name, pair->value, pair->node); printed_values = true; } } static void attrd_event_cb(pcmk_ipc_api_t *attrd_api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data, void *user_data) { pcmk__output_t *out = (pcmk__output_t *) user_data; pcmk__attrd_api_reply_t *reply = event_data; if (event_type != pcmk_ipc_event_reply || status != CRM_EX_OK) { return; } /* Print the values from the reply. */ if (reply->reply_type == pcmk__attrd_reply_query) { print_attrd_values(out, reply->data.pairs); } } /*! * \brief Submit a query to pacemaker-attrd and print reply * * \param[in] attr_name Name of attribute to be affected by request * \param[in] attr_node Name of host to query for (or NULL for localhost) * \param[in] query_all If TRUE, ignore attr_node and query all nodes instead * * \return Standard Pacemaker return code */ static int send_attrd_query(pcmk__output_t *out, const char *attr_name, const char *attr_node, gboolean query_all) { pcmk_ipc_api_t *attrd_api = NULL; int rc = pcmk_rc_ok; // Create attrd IPC object rc = pcmk_new_ipc_api(&attrd_api, pcmk_ipc_attrd); if (rc != pcmk_rc_ok) { fprintf(stderr, "error: Could not connect to attrd: %s\n", pcmk_rc_str(rc)); return ENOTCONN; } pcmk_register_ipc_callback(attrd_api, attrd_event_cb, out); // Connect to attrd (without main loop) rc = pcmk_connect_ipc(attrd_api, pcmk_ipc_dispatch_sync); if (rc != pcmk_rc_ok) { fprintf(stderr, "error: Could not connect to attrd: %s\n", pcmk_rc_str(rc)); pcmk_free_ipc_api(attrd_api); return rc; } /* Decide which node(s) to query */ if (query_all == TRUE) { attr_node = NULL; - } else { - const char *target = pcmk__node_attr_target(attr_node); - if (target != NULL) { - attr_node = target; - } } rc = pcmk__attrd_api_query(attrd_api, attr_node, attr_name, 0); if (rc != pcmk_rc_ok) { g_set_error(&error, PCMK__RC_ERROR, rc, "Could not query value of %s: %s (%d)", attr_name, pcmk_strerror(rc), rc); } else if (!printed_values) { rc = pcmk_rc_schema_validation; g_set_error(&error, PCMK__RC_ERROR, rc, "Could not query value of %s: attribute does not exist", attr_name); } pcmk_disconnect_ipc(attrd_api); pcmk_free_ipc_api(attrd_api); return rc; } static int send_attrd_update(char command, const char *attr_node, const char *attr_name, const char *attr_value, const char *attr_set, const char *attr_dampen, uint32_t attr_options) { pcmk_ipc_api_t *attrd_api = NULL; int rc = pcmk_rc_ok; xmlNode *reply = NULL; - const char *target = NULL; // Create attrd IPC object rc = pcmk_new_ipc_api(&attrd_api, pcmk_ipc_attrd); if (rc != pcmk_rc_ok) { fprintf(stderr, "error: Could not connect to attrd: %s\n", pcmk_rc_str(rc)); return ENOTCONN; } pcmk_register_ipc_callback(attrd_api, attrd_event_cb, &reply); // Connect to attrd (without main loop) rc = pcmk_connect_ipc(attrd_api, pcmk_ipc_dispatch_sync); if (rc != pcmk_rc_ok) { fprintf(stderr, "error: Could not connect to attrd: %s\n", pcmk_rc_str(rc)); pcmk_free_ipc_api(attrd_api); return rc; } - target = pcmk__node_attr_target(attr_node); - if (target != NULL) { - attr_node = target; - } - switch (command) { case 'B': rc = pcmk__attrd_api_update(attrd_api, attr_node, attr_name, attr_value, attr_dampen, attr_set, NULL, attr_options | pcmk__node_attr_value | pcmk__node_attr_delay); break; case 'D': rc = pcmk__attrd_api_delete(attrd_api, attr_node, attr_name, attr_options); break; case 'R': rc = pcmk__attrd_api_refresh(attrd_api, attr_node); break; case 'U': rc = pcmk__attrd_api_update(attrd_api, attr_node, attr_name, attr_value, NULL, attr_set, NULL, attr_options | pcmk__node_attr_value); break; case 'Y': rc = pcmk__attrd_api_update(attrd_api, attr_node, attr_name, NULL, attr_dampen, attr_set, NULL, attr_options | pcmk__node_attr_delay); break; } pcmk_disconnect_ipc(attrd_api); pcmk_free_ipc_api(attrd_api); if (rc != pcmk_rc_ok) { g_set_error(&error, PCMK__RC_ERROR, rc, "Could not update %s=%s: %s (%d)", attr_name, attr_value, pcmk_rc_str(rc), rc); } return rc; } diff --git a/tools/notifyServicelogEvent.c b/tools/notifyServicelogEvent.c index 3fa1d19dcd..4065d15543 100644 --- a/tools/notifyServicelogEvent.c +++ b/tools/notifyServicelogEvent.c @@ -1,253 +1,247 @@ /* * Original copyright 2009 International Business Machines, IBM, Mark Hamzy * Later changes copyright 2009-2022 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ /* gcc -o notifyServicelogEvent `pkg-config --cflags servicelog-1` `pkg-config --libs servicelog-1` notifyServicelogEvent.c */ #include #include #include #include #include #include #include #include #include /* U64T ~ PRIu64, U64TS ~ SCNu64 */ #ifndef PCMK__CONFIG_H # define PCMK__CONFIG_H # include #endif #include #include #include #include typedef enum { STATUS_GREEN = 1, STATUS_YELLOW, STATUS_RED } STATUS; const char *status2char(STATUS status); STATUS event2status(struct sl_event *event); const char * status2char(STATUS status) { switch (status) { default: case STATUS_GREEN: return "green"; case STATUS_YELLOW: return "yellow"; case STATUS_RED: return "red"; } } STATUS event2status(struct sl_event * event) { STATUS status = STATUS_GREEN; crm_debug("Severity = %d, Disposition = %d", event->severity, event->disposition); /* @TBD */ if (event->severity == SL_SEV_WARNING) { status = STATUS_YELLOW; } if (event->disposition == SL_DISP_UNRECOVERABLE) { status = STATUS_RED; } return status; } static int send_attrd_update(const char *attr_node, const char *attr_name, const char *attr_value, const char *attr_set, const char *attr_dampen, uint32_t attr_options) { pcmk_ipc_api_t *attrd_api = NULL; int rc = pcmk_rc_ok; - const char *target = NULL; // Create attrd IPC object rc = pcmk_new_ipc_api(&attrd_api, pcmk_ipc_attrd); if (rc != pcmk_rc_ok) { fprintf(stderr, "error: Could not connect to attrd: %s\n", pcmk_rc_str(rc)); return ENOTCONN; } // Connect to attrd (without main loop) rc = pcmk_connect_ipc(attrd_api, pcmk_ipc_dispatch_sync); if (rc != pcmk_rc_ok) { fprintf(stderr, "error: Could not connect to attrd: %s\n", pcmk_rc_str(rc)); pcmk_free_ipc_api(attrd_api); return rc; } - target = pcmk__node_attr_target(attr_node); - if (target != NULL) { - attr_node = target; - } - rc = pcmk__attrd_api_update(attrd_api, attr_node, attr_name, attr_value, NULL, NULL, NULL, attr_options | pcmk__node_attr_pattern); pcmk_disconnect_ipc(attrd_api); pcmk_free_ipc_api(attrd_api); if (rc != pcmk_rc_ok) { crm_err("Could not update %s=%s: %s (%d)", attr_name, attr_value, pcmk_rc_str(rc), rc); } return rc; } static pcmk__cli_option_t long_options[] = { // long option, argument type, storage, short option, description, flags { "help", no_argument, NULL, '?', "\tThis text", pcmk__option_default }, { "version", no_argument, NULL, '$', "\tVersion information", pcmk__option_default }, { "-spacer-", no_argument, NULL, '-', "\nUsage: notifyServicelogEvent event_id", pcmk__option_paragraph }, { "-spacer-", no_argument, NULL, '-', "Where event_id is a unique unsigned event identifier which is " "then passed into servicelog", pcmk__option_paragraph }, { 0, 0, 0, 0 } }; int main(int argc, char *argv[]) { int argerr = 0; int flag; int index = 0; int rc = 0; servicelog *slog = NULL; struct sl_event *event = NULL; uint64_t event_id = 0; pcmk__cli_init_logging("notifyServicelogEvent", 0); pcmk__set_cli_options(NULL, "", long_options, "handle events written to servicelog database"); if (argc < 2) { argerr++; } while (1) { flag = pcmk__next_cli_option(argc, argv, &index, NULL); if (flag == -1) break; switch (flag) { case '?': case '$': pcmk__cli_help(flag, CRM_EX_OK); break; default: ++argerr; break; } } if (argc - optind != 1) { ++argerr; } if (argerr) { pcmk__cli_help('?', CRM_EX_USAGE); } openlog("notifyServicelogEvent", LOG_NDELAY, LOG_USER); if (sscanf(argv[optind], "%" U64TS, &event_id) != 1) { crm_err("Error: could not read event_id from args!"); rc = 1; goto done; } if (event_id == 0) { crm_err("Error: event_id is 0!"); rc = 1; goto done; } rc = servicelog_open(&slog, 0); /* flags is one of SL_FLAG_xxx */ if (!slog) { crm_err("Error: servicelog_open failed, rc = %d", rc); rc = 1; goto done; } if (slog) { rc = servicelog_event_get(slog, event_id, &event); } if (rc == 0) { STATUS status = STATUS_GREEN; const char *health_component = "#health-ipmi"; const char *health_status = NULL; crm_debug("Event id = %" U64T ", Log timestamp = %s, Event timestamp = %s", event_id, ctime(&(event->time_logged)), ctime(&(event->time_event))); status = event2status(event); health_status = status2char(status); if (health_status) { int attrd_rc; // @TODO pass pcmk__node_attr_remote when appropriate attrd_rc = send_attrd_update(NULL, health_component, health_status, NULL, NULL, pcmk__node_attr_none); crm_debug("Updating attribute ('%s', '%s') = %d", health_component, health_status, attrd_rc); } else { crm_err("Error: status2char failed, status = %d", status); rc = 1; } } else { crm_err("Error: servicelog_event_get failed, rc = %d", rc); } done: if (event) { servicelog_event_free(event); } if (slog) { servicelog_close(slog); } closelog(); return rc; }