diff --git a/daemons/controld/controld_messages.c b/daemons/controld/controld_messages.c index 18a6c17..a443369 100644 --- a/daemons/controld/controld_messages.c +++ b/daemons/controld/controld_messages.c @@ -375,10 +375,11 @@ relay_message(xmlNode * msg, gboolean originated_locally) is_local = 0; } else if (is_for_crm) { - if (safe_str_eq(task, CRM_OP_NODE_INFO)) { + if (safe_str_eq(task, CRM_OP_NODE_INFO) + || safe_str_eq(task, PCMK__CONTROLD_CMD_NODES)) { /* Node info requests do not specify a host, which is normally * treated as "all hosts", because the whole point is that the - * client doesn't know the local node name. Always handle these + * client may not know the local node name. Always handle these * requests locally. */ is_local = 1; @@ -784,6 +785,42 @@ handle_ping(xmlNode *msg) } /*! + * \brief Handle a PCMK__CONTROLD_CMD_NODES message + * + * \return Next FSA input + */ +static enum crmd_fsa_input +handle_node_list(xmlNode *request) +{ + GHashTableIter iter; + crm_node_t *node = NULL; + xmlNode *reply = NULL; + xmlNode *reply_data = NULL; + + // Create message data for reply + reply_data = create_xml_node(NULL, XML_CIB_TAG_NODES); + g_hash_table_iter_init(&iter, crm_peer_cache); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) { + xmlNode *xml = create_xml_node(reply_data, XML_CIB_TAG_NODE); + + crm_xml_add_ll(xml, XML_ATTR_ID, (long long) node->id); // uint32_t + crm_xml_add(xml, XML_ATTR_UNAME, node->uname); + crm_xml_add(xml, XML_NODE_IN_CLUSTER, node->state); + } + + // Create and send reply + reply = create_reply(request, reply_data); + free_xml(reply_data); + if (reply) { + (void) relay_message(reply, TRUE); + free_xml(reply); + } + + // Nothing further to do + return I_NULL; +} + +/*! * \brief Handle a CRM_OP_NODE_INFO request * * \param[in] msg Message XML @@ -1080,6 +1117,9 @@ handle_request(xmlNode *stored_msg, enum crmd_fsa_cause cause) remote_ra_process_maintenance_nodes(xml); + } else if (strcmp(op, PCMK__CONTROLD_CMD_NODES) == 0) { + return handle_node_list(stored_msg); + /*========== (NOT_DC)-Only Actions ==========*/ } else if (!AM_I_DC) { diff --git a/include/crm/common/ipc_controld.h b/include/crm/common/ipc_controld.h index 0ebabfc..b817357 100644 --- a/include/crm/common/ipc_controld.h +++ b/include/crm/common/ipc_controld.h @@ -22,6 +22,7 @@ extern "C" { */ #include // bool +#include // GList #include // xmlNode #include // pcmk_ipc_api_t @@ -32,8 +33,16 @@ enum pcmk_controld_api_reply { pcmk_controld_reply_info, pcmk_controld_reply_resource, pcmk_controld_reply_ping, + pcmk_controld_reply_nodes, }; +// Node information passed with pcmk_controld_reply_nodes +typedef struct { + uint32_t id; + const char *uname; + const char *state; +} pcmk_controld_api_node_t; + /*! * Controller reply passed to event callback * @@ -72,6 +81,9 @@ typedef struct { const char *fsa_state; const char *result; } ping; + + // pcmk_controld_reply_nodes + GList *nodes; // list of pcmk_controld_api_node_t * } data; } pcmk_controld_api_reply_t; @@ -88,6 +100,7 @@ int pcmk_controld_api_refresh(pcmk_ipc_api_t *api, const char *target_node, const char *provider, const char *type, bool cib_only); int pcmk_controld_api_ping(pcmk_ipc_api_t *api, const char *node_name); +int pcmk_controld_api_list_nodes(pcmk_ipc_api_t *api); int pcmk_controld_api_shutdown(pcmk_ipc_api_t *api, const char *node_name); int pcmk_controld_api_start_election(pcmk_ipc_api_t *api); unsigned int pcmk_controld_api_replies_expected(pcmk_ipc_api_t *api); diff --git a/include/crm_internal.h b/include/crm_internal.h index fd56fc6..cf8999f 100644 --- a/include/crm_internal.h +++ b/include/crm_internal.h @@ -122,6 +122,7 @@ pid_t pcmk_locate_sbd(void); #define PCMK__ATTRD_CMD_SYNC_RESPONSE "sync-response" #define PCMK__ATTRD_CMD_CLEAR_FAILURE "clear-failure" +#define PCMK__CONTROLD_CMD_NODES "list-nodes" /* * Environment variables used by Pacemaker diff --git a/lib/common/ipc_controld.c b/lib/common/ipc_controld.c index 22bb733..a733dd3 100644 --- a/lib/common/ipc_controld.c +++ b/lib/common/ipc_controld.c @@ -120,6 +120,28 @@ set_ping_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data) data->data.ping.result = crm_element_value(msg_data, XML_PING_ATTR_STATUS); } +static void +set_nodes_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data) +{ + pcmk_controld_api_node_t *node_info; + + data->reply_type = pcmk_controld_reply_nodes; + for (xmlNode *node = first_named_child(msg_data, XML_CIB_TAG_NODE); + node != NULL; node = crm_next_same_xml(node)) { + + long long id_ll = 0; + + node_info = calloc(1, sizeof(pcmk_controld_api_node_t)); + crm_element_value_ll(node, XML_ATTR_ID, &id_ll); + if (id_ll > 0) { + node_info->id = id_ll; + } + node_info->uname = crm_element_value(node, XML_ATTR_UNAME); + node_info->state = crm_element_value(node, XML_NODE_IN_CLUSTER); + data->data.nodes = g_list_prepend(data->data.nodes, node_info); + } +} + static bool reply_expected(pcmk_ipc_api_t *api, xmlNode *request) { @@ -201,6 +223,9 @@ dispatch(pcmk_ipc_api_t *api, xmlNode *reply) } else if (!strcmp(value, CRM_OP_PING)) { set_ping_data(&reply_data, msg_data); + } else if (!strcmp(value, PCMK__CONTROLD_CMD_NODES)) { + set_nodes_data(&reply_data, msg_data); + } else { crm_debug("Unrecognizable controller message: unknown command '%s'", value); @@ -210,6 +235,11 @@ dispatch(pcmk_ipc_api_t *api, xmlNode *reply) } pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data); + + // Free any reply data that was allocated + if (safe_str_eq(value, PCMK__CONTROLD_CMD_NODES)) { + g_list_free_full(reply_data.data.nodes, free); + } } pcmk__ipc_methods_t * @@ -376,6 +406,29 @@ pcmk_controld_api_ping(pcmk_ipc_api_t *api, const char *node_name) } /*! + * \brief Ask the controller for cluster information + * + * \param[in] api Controller connection + * + * \return Standard Pacemaker return code + * \note Event callback will get a reply of type pcmk_controld_reply_nodes. + */ +int +pcmk_controld_api_list_nodes(pcmk_ipc_api_t *api) +{ + xmlNode *request; + int rc = EINVAL; + + request = create_controller_request(api, PCMK__CONTROLD_CMD_NODES, NULL, + NULL); + if (request != NULL) { + rc = send_controller_request(api, request, true); + free_xml(request); + } + return rc; +} + +/*! * \internal * \brief Ask the controller to shut down *