diff --git a/tools/Makefile.am b/tools/Makefile.am index c822a8c..4609b0f 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -12,7 +12,7 @@ if BUILD_SYSTEMD systemdsystemunit_DATA = crm_mon.service endif -noinst_HEADERS = crm_mon.h crm_resource.h crm_resource_controller.h +noinst_HEADERS = crm_mon.h crm_resource.h pcmkdir = $(datadir)/$(PACKAGE) pcmk_DATA = report.common report.collector @@ -115,7 +115,6 @@ crm_attribute_LDADD = $(top_builddir)/lib/cluster/libcrmcluster.la \ crm_resource_SOURCES = crm_resource.c \ crm_resource_ban.c \ - crm_resource_controller.c \ crm_resource_print.c \ crm_resource_runtime.c crm_resource_LDADD = $(top_builddir)/lib/pengine/libpe_rules.la \ diff --git a/tools/crm_resource.c b/tools/crm_resource.c index 6853ad5..c8c1cfa 100644 --- a/tools/crm_resource.c +++ b/tools/crm_resource.c @@ -11,62 +11,70 @@ #include #include - -#include -#include - #include #include #include - #include #include #include #include #include +#include +#include +#include + bool BE_QUIET = FALSE; bool scope_master = FALSE; int cib_options = cib_sync_call; - -static GMainLoop *mainloop = NULL; +static crm_exit_t exit_code = CRM_EX_OK; // Things that should be cleaned up on exit +static GMainLoop *mainloop = NULL; static cib_t *cib_conn = NULL; -static pcmk_controld_api_t *controld_api = NULL; +static pcmk_ipc_api_t *controld_api = NULL; static pe_working_set_t *data_set = NULL; #define MESSAGE_TIMEOUT_S 60 // Clean up and exit static crm_exit_t -bye(crm_exit_t exit_code) +bye(crm_exit_t ec) { - static bool crm_resource_shutdown_flag = false; - - if (crm_resource_shutdown_flag) { - // Allow usage like "return bye(...);" - return exit_code; - } - crm_resource_shutdown_flag = true; - if (cib_conn != NULL) { cib_t *save_cib_conn = cib_conn; - cib_conn = NULL; + cib_conn = NULL; // Ensure we can't free this twice save_cib_conn->cmds->signoff(save_cib_conn); cib_delete(save_cib_conn); } if (controld_api != NULL) { - pcmk_controld_api_t *save_controld_api = controld_api; + pcmk_ipc_api_t *save_controld_api = controld_api; - controld_api = NULL; - pcmk_free_controld_api(save_controld_api); + controld_api = NULL; // Ensure we can't free this twice + pcmk_free_ipc_api(save_controld_api); + } + if (mainloop != NULL) { + g_main_loop_unref(mainloop); + mainloop = NULL; } pe_free_working_set(data_set); data_set = NULL; - crm_exit(exit_code); - return exit_code; + crm_exit(ec); + return ec; +} + +static void +quit_main_loop(crm_exit_t ec) +{ + exit_code = ec; + if (mainloop != NULL) { + GMainLoop *mloop = mainloop; + + mainloop = NULL; // Don't re-enter this block + pcmk_quit_main_loop(mloop, 10); + g_main_loop_unref(mloop); + } } static gboolean @@ -76,39 +84,54 @@ resource_ipc_timeout(gpointer data) fprintf(stderr, "\nAborting because no messages received in %d seconds\n", MESSAGE_TIMEOUT_S); crm_err("No messages received in %d seconds", MESSAGE_TIMEOUT_S); - bye(CRM_EX_TIMEOUT); + quit_main_loop(CRM_EX_TIMEOUT); return FALSE; } static void -handle_controller_reply(pcmk_controld_api_t *capi, void *api_data, - void *user_data) +controller_event_callback(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type, + crm_exit_t status, void *event_data, void *user_data) { - fprintf(stderr, "."); - if ((capi->replies_expected(capi) == 0) - && mainloop && g_main_loop_is_running(mainloop)) { - fprintf(stderr, " OK\n"); - crm_debug("Got all the replies we expected"); - bye(CRM_EX_OK); - } -} + switch (event_type) { + case pcmk_ipc_event_disconnect: + if (exit_code == CRM_EX_DISCONNECT) { // Unexpected + crm_info("Connection to controller was terminated"); + } + quit_main_loop(exit_code); + break; -static void -handle_controller_drop(pcmk_controld_api_t *capi, void *api_data, - void *user_data) -{ - crm_info("Connection to controller was terminated"); - bye(CRM_EX_DISCONNECT); + case pcmk_ipc_event_reply: + if (status != CRM_EX_OK) { + fprintf(stderr, "\nError: bad reply from controller: %s\n", + crm_exit_str(status)); + pcmk_disconnect_ipc(api); + quit_main_loop(status); + } else { + fprintf(stderr, "."); + if ((pcmk_controld_api_replies_expected(api) == 0) + && mainloop && g_main_loop_is_running(mainloop)) { + fprintf(stderr, " OK\n"); + crm_debug("Got all the replies we expected"); + pcmk_disconnect_ipc(api); + quit_main_loop(CRM_EX_OK); + } + } + break; + + default: + break; + } } static void -start_mainloop(pcmk_controld_api_t *capi) +start_mainloop(pcmk_ipc_api_t *capi) { - if (capi->replies_expected(capi) > 0) { - unsigned int count = capi->replies_expected(capi); + unsigned int count = pcmk_controld_api_replies_expected(capi); + if (count > 0) { fprintf(stderr, "Waiting for %d %s from the controller", count, pcmk__plural_alt(count, "reply", "replies")); + exit_code = CRM_EX_DISCONNECT; // For unexpected disconnects mainloop = g_main_loop_new(NULL, FALSE); g_timeout_add(MESSAGE_TIMEOUT_S * 1000, resource_ipc_timeout, NULL); g_main_loop_run(mainloop); @@ -664,7 +687,6 @@ main(int argc, char **argv) int argerr = 0; int flag; int find_flags = 0; // Flags to use when searching for resource - crm_exit_t exit_code = CRM_EX_OK; crm_log_cli_init("crm_resource"); pcmk__set_cli_options(NULL, "| [options]", long_options, @@ -1151,21 +1173,15 @@ main(int argc, char **argv) // Establish a connection to the controller if needed if (require_crmd) { - char *client_uuid; - pcmk_controld_api_cb_t dispatch_cb = { - handle_controller_reply, NULL - }; - pcmk_controld_api_cb_t destroy_cb = { - handle_controller_drop, NULL - }; - - - client_uuid = pcmk__getpid_s(); - controld_api = pcmk_new_controld_api(crm_system_name, client_uuid); - free(client_uuid); - - rc = controld_api->connect(controld_api, true, &dispatch_cb, - &destroy_cb); + rc = pcmk_new_ipc_api(&controld_api, pcmk_ipc_controld); + if (rc != pcmk_rc_ok) { + CMD_ERR("Error connecting to the controller: %s", pcmk_rc_str(rc)); + rc = pcmk_rc2legacy(rc); + goto bail; + } + pcmk_register_ipc_callback(controld_api, controller_event_callback, + NULL); + rc = pcmk_connect_ipc(controld_api, pcmk_ipc_dispatch_main); if (rc != pcmk_rc_ok) { CMD_ERR("Error connecting to the controller: %s", pcmk_rc_str(rc)); rc = pcmk_rc2legacy(rc); @@ -1525,8 +1541,8 @@ main(int argc, char **argv) NULL, NULL, NULL, NULL, attr_options)); - if (controld_api->reprobe(controld_api, host_uname, - router_node) == pcmk_rc_ok) { + if (pcmk_controld_api_reprobe(controld_api, host_uname, + router_node) == pcmk_rc_ok) { start_mainloop(controld_api); } diff --git a/tools/crm_resource.h b/tools/crm_resource.h index 0bf7bee..cb7f506 100644 --- a/tools/crm_resource.h +++ b/tools/crm_resource.h @@ -21,7 +21,6 @@ #include #include #include -#include "crm_resource_controller.h" extern bool print_pending; @@ -36,8 +35,6 @@ extern char *move_lifetime; extern const char *attr_set_type; -extern pcmk_controld_api_cb_t controld_api_cb; - /* ban */ int cli_resource_prefer(const char *rsc_id, const char *host, cib_t * cib_conn); int cli_resource_ban(const char *rsc_id, const char *host, GListPtr allnodes, cib_t * cib_conn); @@ -63,16 +60,16 @@ int cli_resource_print_operations(const char *rsc_id, const char *host_uname, bo /* runtime */ void cli_resource_check(cib_t * cib, pe_resource_t *rsc); -int cli_resource_fail(pcmk_controld_api_t *controld_api, +int cli_resource_fail(pcmk_ipc_api_t *controld_api, const char *host_uname, const char *rsc_id, pe_working_set_t *data_set); int cli_resource_search(pe_resource_t *rsc, const char *requested_name, pe_working_set_t *data_set); -int cli_resource_delete(pcmk_controld_api_t *controld_api, +int cli_resource_delete(pcmk_ipc_api_t *controld_api, const char *host_uname, pe_resource_t *rsc, const char *operation, const char *interval_spec, bool just_failures, pe_working_set_t *data_set); -int cli_cleanup_all(pcmk_controld_api_t *controld_api, const char *node_name, +int cli_cleanup_all(pcmk_ipc_api_t *controld_api, const char *node_name, const char *operation, const char *interval_spec, pe_working_set_t *data_set); int cli_resource_restart(pe_resource_t *rsc, const char *host, int timeout_ms, diff --git a/tools/crm_resource_controller.c b/tools/crm_resource_controller.c deleted file mode 100644 index 994a7be..0000000 --- a/tools/crm_resource_controller.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - * 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 General Public License version 2 - * or later (GPLv2+) WITHOUT ANY WARRANTY. - */ - -#include -#include -#include -#include "crm_resource.h" - -// API object's private members -struct controller_private { - char *client_name; // Client name to use with IPC - char *client_uuid; // Client UUID to use with IPC - mainloop_io_t *source; // If main loop used, I/O source for IPC - crm_ipc_t *ipc; // IPC connection to controller - int replies_expected; // How many controller replies are expected - pcmk_controld_api_cb_t dispatch_cb; // Caller's registered dispatch callback - pcmk_controld_api_cb_t destroy_cb; // Caller's registered destroy callback -}; - -static void -call_client_callback(pcmk_controld_api_t *api, pcmk_controld_api_cb_t *cb, - void *api_data) -{ - if ((cb != NULL) && (cb->callback != NULL)) { - cb->callback(api, api_data, cb->user_data); - } -} - -/* - * IPC callbacks when used with main loop - */ - -static void -controller_ipc_destroy(gpointer user_data) -{ - pcmk_controld_api_t *api = user_data; - struct controller_private *private = api->private; - - private->ipc = NULL; - private->source = NULL; - call_client_callback(api, &(private->destroy_cb), NULL); -} - -// \return < 0 if connection is no longer required, >= 0 if it is -static int -controller_ipc_dispatch(const char *buffer, ssize_t length, gpointer user_data) -{ - xmlNode *msg = NULL; - pcmk_controld_api_t *api = user_data; - - CRM_CHECK(buffer && api && api->private, return 0); - - msg = string2xml(buffer); - if (msg == NULL) { - crm_warn("Received malformed controller IPC message"); - } else { - struct controller_private *private = api->private; - - crm_log_xml_trace(msg, "controller-reply"); - private->replies_expected--; - call_client_callback(api, &(private->dispatch_cb), - get_message_xml(msg, F_CRM_DATA)); - free_xml(msg); - } - return 0; -} - -/* - * IPC utilities - */ - -// \return Standard Pacemaker return code -static int -send_hello(crm_ipc_t *ipc, const char *client_name, const char *client_uuid) -{ - xmlNode *hello = create_hello_message(client_uuid, client_name, "0", "1"); - int rc = crm_ipc_send(ipc, hello, 0, 0, NULL); - - free_xml(hello); - if (rc < 0) { - rc = pcmk_legacy2rc(rc); - crm_info("Could not send IPC hello to %s: %s " CRM_XS " rc=%s", - CRM_SYSTEM_CRMD /* ipc->name */, - pcmk_rc_str(rc), rc); - return rc; - } - crm_debug("Sent IPC hello to %s", CRM_SYSTEM_CRMD /* ipc->name */); - return pcmk_rc_ok; -} - -// \return Standard Pacemaker return code -static int -send_controller_request(pcmk_controld_api_t *api, const char *op, - xmlNode *msg_data, const char *node) -{ - int rc; - struct controller_private *private = api->private; - xmlNode *cmd = create_request(op, msg_data, node, CRM_SYSTEM_CRMD, - private->client_name, private->client_uuid); - const char *reference = crm_element_value(cmd, XML_ATTR_REFERENCE); - - if ((cmd == NULL) || (reference == NULL)) { - return EINVAL; - } - - //@TODO pass as args? 0=crm_ipc_flags, 0=timeout_ms (default 5s), NULL=reply - crm_log_xml_trace(cmd, "controller-request"); - rc = crm_ipc_send(private->ipc, cmd, 0, 0, NULL); - free_xml(cmd); - if (rc < 0) { - return pcmk_legacy2rc(rc); - } - private->replies_expected++; - return pcmk_rc_ok; -} - -/* - * pcmk_controld_api_t methods - */ - -static int -controller_connect_mainloop(pcmk_controld_api_t *api) -{ - struct controller_private *private = api->private; - struct ipc_client_callbacks callbacks = { - .dispatch = controller_ipc_dispatch, - .destroy = controller_ipc_destroy, - }; - - private->source = mainloop_add_ipc_client(CRM_SYSTEM_CRMD, - G_PRIORITY_DEFAULT, 0, api, - &callbacks); - if (private->source == NULL) { - return ENOTCONN; - } - - private->ipc = mainloop_get_ipc_client(private->source); - if (private->ipc == NULL) { - (void) api->disconnect(api); - return ENOTCONN; - } - - crm_debug("Connected to %s IPC (attaching to main loop)", CRM_SYSTEM_CRMD); - return pcmk_rc_ok; -} - -static int -controller_connect_no_mainloop(pcmk_controld_api_t *api) -{ - struct controller_private *private = api->private; - - private->ipc = crm_ipc_new(CRM_SYSTEM_CRMD, 0); - if (private->ipc == NULL) { - return ENOTCONN; - } - if (!crm_ipc_connect(private->ipc)) { - crm_ipc_close(private->ipc); - crm_ipc_destroy(private->ipc); - private->ipc = NULL; - return errno; - } - /* @TODO caller needs crm_ipc_get_fd(private->ipc); either add method for - * that, or replace use_mainloop with int *fd - */ - crm_debug("Connected to %s IPC", CRM_SYSTEM_CRMD); - return pcmk_rc_ok; -} - -static void -set_callback(pcmk_controld_api_cb_t *dest, pcmk_controld_api_cb_t *source) -{ - if (source) { - dest->callback = source->callback; - dest->user_data = source->user_data; - } -} - -static int -controller_api_connect(pcmk_controld_api_t *api, bool use_mainloop, - pcmk_controld_api_cb_t *dispatch_cb, - pcmk_controld_api_cb_t *destroy_cb) -{ - int rc = pcmk_rc_ok; - struct controller_private *private; - - if (api == NULL) { - return EINVAL; - } - private = api->private; - - set_callback(&(private->dispatch_cb), dispatch_cb); - set_callback(&(private->destroy_cb), destroy_cb); - - if (private->ipc != NULL) { - return pcmk_rc_ok; // already connected - } - - if (use_mainloop) { - rc = controller_connect_mainloop(api); - } else { - rc = controller_connect_no_mainloop(api); - } - if (rc != pcmk_rc_ok) { - return rc; - } - - rc = send_hello(private->ipc, private->client_name, private->client_uuid); - if (rc != pcmk_rc_ok) { - (void) api->disconnect(api); - } - return rc; -} - -static int -controller_api_disconnect(pcmk_controld_api_t *api) -{ - struct controller_private *private = api->private; - - if (private->source != NULL) { - // Attached to main loop - mainloop_del_ipc_client(private->source); - private->source = NULL; - private->ipc = NULL; - - } else if (private->ipc != NULL) { - // Not attached to main loop - crm_ipc_t *ipc = private->ipc; - - private->ipc = NULL; - crm_ipc_close(ipc); - crm_ipc_destroy(ipc); - } - crm_debug("Disconnected from %s IPC", CRM_SYSTEM_CRMD /* ipc->name */); - return pcmk_rc_ok; -} - -//@TODO dispatch function for non-mainloop a la stonith_dispatch() -//@TODO convenience retry-connect function a la stonith_api_connect_retry() - -static unsigned int -controller_api_replies_expected(pcmk_controld_api_t *api) -{ - if (api != NULL) { - struct controller_private *private = api->private; - - return private->replies_expected; - } - return 0; -} - -static xmlNode * -create_reprobe_message_data(const char *target_node, const char *router_node) -{ - xmlNode *msg_data; - - msg_data = create_xml_node(NULL, "data_for_" CRM_OP_REPROBE); - crm_xml_add(msg_data, XML_LRM_ATTR_TARGET, target_node); - if ((router_node != NULL) && safe_str_neq(router_node, target_node)) { - crm_xml_add(msg_data, XML_LRM_ATTR_ROUTER_NODE, router_node); - } - return msg_data; -} - -static int -controller_api_reprobe(pcmk_controld_api_t *api, const char *target_node, - const char *router_node) -{ - int rc = EINVAL; - - if (api != NULL) { - xmlNode *msg_data; - - crm_debug("Sending %s IPC request to reprobe %s via %s", - CRM_SYSTEM_CRMD, crm_str(target_node), crm_str(router_node)); - msg_data = create_reprobe_message_data(target_node, router_node); - rc = send_controller_request(api, CRM_OP_REPROBE, msg_data, - (router_node? router_node : target_node)); - free_xml(msg_data); - } - return rc; -} - -// \return Standard Pacemaker return code -static int -controller_resource_op(pcmk_controld_api_t *api, const char *op, - const char *target_node, const char *router_node, - bool cib_only, const char *rsc_id, - const char *rsc_long_id, const char *standard, - const char *provider, const char *type) -{ - int rc; - char *key; - xmlNode *msg_data, *xml_rsc, *params; - - if (api == NULL) { - return EINVAL; - } - if (router_node == NULL) { - router_node = target_node; - } - - msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); - - /* The controller logs the transition key from resource op requests, so we - * need to have *something* for it. - */ - key = pcmk__transition_key(0, getpid(), 0, - "xxxxxxxx-xrsc-opxx-xcrm-resourcexxxx"); - crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key); - free(key); - - crm_xml_add(msg_data, XML_LRM_ATTR_TARGET, target_node); - if (safe_str_neq(router_node, target_node)) { - crm_xml_add(msg_data, XML_LRM_ATTR_ROUTER_NODE, router_node); - } - - if (cib_only) { - // Indicate that only the CIB needs to be cleaned - crm_xml_add(msg_data, PCMK__XA_MODE, XML_TAG_CIB); - } - - xml_rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE); - crm_xml_add(xml_rsc, XML_ATTR_ID, rsc_id); - crm_xml_add(xml_rsc, XML_ATTR_ID_LONG, rsc_long_id); - crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, standard); - crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER, provider); - crm_xml_add(xml_rsc, XML_ATTR_TYPE, type); - - params = create_xml_node(msg_data, XML_TAG_ATTRS); - crm_xml_add(params, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET); - - // The controller parses the timeout from the request - key = crm_meta_name(XML_ATTR_TIMEOUT); - crm_xml_add(params, key, "60000"); /* 1 minute */ //@TODO pass as arg - free(key); - - rc = send_controller_request(api, op, msg_data, router_node); - free_xml(msg_data); - return rc; -} - -static int -controller_api_fail_resource(pcmk_controld_api_t *api, - const char *target_node, const char *router_node, - const char *rsc_id, const char *rsc_long_id, - const char *standard, const char *provider, - const char *type) -{ - crm_debug("Sending %s IPC request to fail %s (a.k.a. %s) on %s via %s", - CRM_SYSTEM_CRMD, crm_str(rsc_id), crm_str(rsc_long_id), - crm_str(target_node), crm_str(router_node)); - return controller_resource_op(api, CRM_OP_LRM_FAIL, target_node, - router_node, false, rsc_id, rsc_long_id, - standard, provider, type); -} - -static int -controller_api_refresh_resource(pcmk_controld_api_t *api, - const char *target_node, - const char *router_node, - const char *rsc_id, const char *rsc_long_id, - const char *standard, const char *provider, - const char *type, bool cib_only) -{ - crm_debug("Sending %s IPC request to refresh %s (a.k.a. %s) on %s via %s", - CRM_SYSTEM_CRMD, crm_str(rsc_id), crm_str(rsc_long_id), - crm_str(target_node), crm_str(router_node)); - return controller_resource_op(api, CRM_OP_LRM_DELETE, target_node, - router_node, cib_only, rsc_id, rsc_long_id, - standard, provider, type); -} - -pcmk_controld_api_t * -pcmk_new_controld_api(const char *client_name, const char *client_uuid) -{ - struct controller_private *private; - pcmk_controld_api_t *api = calloc(1, sizeof(pcmk_controld_api_t)); - - CRM_ASSERT(api != NULL); - - api->private = calloc(1, sizeof(struct controller_private)); - CRM_ASSERT(api->private != NULL); - private = api->private; - - if (client_name == NULL) { - client_name = crm_system_name? crm_system_name : "client"; - } - private->client_name = strdup(client_name); - CRM_ASSERT(private->client_name != NULL); - - if (client_uuid == NULL) { - private->client_uuid = crm_generate_uuid(); - } else { - private->client_uuid = strdup(client_uuid); - } - CRM_ASSERT(private->client_uuid != NULL); - - api->connect = controller_api_connect; - api->disconnect = controller_api_disconnect; - api->replies_expected = controller_api_replies_expected; - api->reprobe = controller_api_reprobe; - api->fail_resource = controller_api_fail_resource; - api->refresh_resource = controller_api_refresh_resource; - return api; -} - -void -pcmk_free_controld_api(pcmk_controld_api_t *api) -{ - if (api != NULL) { - struct controller_private *private = api->private; - - api->disconnect(api); - free(private->client_name); - free(private->client_uuid); - free(api->private); - free(api); - } -} diff --git a/tools/crm_resource_controller.h b/tools/crm_resource_controller.h deleted file mode 100644 index 50e20b4..0000000 --- a/tools/crm_resource_controller.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * 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. - */ -#ifndef PCMK__CONTROLD_API_H -#define PCMK__CONTROLD_API_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include // bool - -/* This is a demonstration of an abstracted controller IPC API. It is expected - * that this will be improved and moved to libcrmcommon. - * - * @TODO We could consider whether it's reasonable to have a single type for - * all daemons' IPC APIs (e.g. pcmk_ipc_api_t instead of pcmk_*_api_t). They - * could potentially have common connect/disconnect methods and then a void* to - * a group of API-specific methods. - * - * In that case, the callback type would also need to be generic, taking - * (pcmk_ipc_api_t *api, void *api_data, void *user_data), with individual APIs - * having functions for getting useful info from api_data. If all APIs followed - * the call_id model, we could use int call_id instead of api_data. - * - * A major annoyance is that the controller IPC protocol currently does not have - * any way to tie a particular reply to a particular request. The current - * clients (crmadmin, crm_node, and crm_resource) simply know what kind of reply - * to expect for the kind of request they sent. In crm_resource's case, all it - * does is count replies, ignoring their content altogether. - * - * That really forces us to have a single callback for all events rather than a - * per-request callback. That in turn implies that callers can only provide a - * single user data pointer. - * - * @TODO Define protocol version constants to use in hello message. - * @TODO Allow callers to specify timeouts. - * @TODO Define call IDs for controller ops, while somehow maintaining backward - * compatibility, since a client running on a Pacemaker Remote node could - * be older or newer than the controller on the connection's cluster - * node. - * @TODO The controller currently does not respond to hello messages. We should - * establish a common connection handshake protocol for all daemons that - * involves a hello message and acknowledgement. We should support sync - * or async connection (i.e. block until the ack is received, or return - * after the hello is sent and call a connection callback when the hello - * ack is received). - */ - -//! \internal -typedef struct pcmk_controld_api_s pcmk_controld_api_t; - -//! \internal -typedef struct pcmk_controld_api_callback_s { - void (*callback)(pcmk_controld_api_t *api, void *api_data, void *user_data); - void *user_data; -} pcmk_controld_api_cb_t; - -//! \internal -struct pcmk_controld_api_s { - //! \internal - void *private; - - /*! - * \internal - * \brief Connect to the local controller - * - * \param[in] api Controller API instance - * \param[in] use_mainloop If true, attach IPC to main loop - * \param[in] dispatch_cb If not NULL, call this when replies are received - * \param[in] destroy_cb If not NULL, call this if connection drops - * - * \return Standard Pacemaker return code - * \note Only the pointers inside the callback objects need to be - * persistent, not the callback objects themselves. The destroy_cb - * will be called only for unrequested disconnects. - */ - int (*connect)(pcmk_controld_api_t *api, bool use_mainloop, - pcmk_controld_api_cb_t *dispatch_cb, - pcmk_controld_api_cb_t *destroy_cb); - - /*! - * \internal - * \brief Disconnect from the local controller - * - * \param[in] api Controller API instance - * - * \return Standard Pacemaker return code - */ - int (*disconnect)(pcmk_controld_api_t *api); - - /*! - * \internal - * \brief Check number of replies still expected from controller - * - * \param[in] api Controller API instance - * - * \return Number of expected replies - */ - unsigned int (*replies_expected)(pcmk_controld_api_t *api); - - /*! - * \internal - * \brief Send a reprobe controller operation - * - * \param[in] api Controller API instance - * \param[in] target_node Name of node to reprobe - * \param[in] router_node Router node for host - * - * \return Standard Pacemaker return code - */ - int (*reprobe)(pcmk_controld_api_t *api, const char *target_node, - const char *router_node); - - /* @TODO These methods have a lot of arguments. One possibility would be to - * make a struct for agent info (standard/provider/type), which theortically - * could be used throughout pacemaker code. However that would end up being - * really awkward to use generically, since sometimes you need to allocate - * those strings (char *) and other times you only have references into XML - * (const char *). We could make some structs just for this API. - */ - - /*! - * \internal - * \brief Ask the controller to fail a resource - * - * \param[in] api Controller API instance - * \param[in] target_node Name of node resource is on - * \param[in] router_node Router node for target - * \param[in] rsc_id ID of resource to fail - * \param[in] rsc_long_id Long ID of resource (if any) - * \param[in] standard Standard of resource - * \param[in] provider Provider of resource (if any) - * \param[in] type Type of resource to fail - * - * \return Standard Pacemaker return code - */ - int (*fail_resource)(pcmk_controld_api_t *api, const char *target_node, - const char *router_node, const char *rsc_id, - const char *rsc_long_id, const char *standard, - const char *provider, const char *type); - - /*! - * \internal - * \brief Ask the controller to refresh a resource - * - * \param[in] api Controller API instance - * \param[in] target_node Name of node resource is on - * \param[in] router_node Router node for target - * \param[in] rsc_id ID of resource to refresh - * \param[in] rsc_long_id Long ID of resource (if any) - * \param[in] standard Standard of resource - * \param[in] provider Provider of resource (if any) - * \param[in] type Type of resource - * \param[in] cib_only If true, clean resource from CIB only - * - * \return Standard Pacemaker return code - */ - int (*refresh_resource)(pcmk_controld_api_t *api, const char *target_node, - const char *router_node, const char *rsc_id, - const char *rsc_long_id, const char *standard, - const char *provider, const char *type, - bool cib_only); -}; - -/*! - * \internal - * \brief Create new controller IPC API object for clients - * - * \param[in] client_name Client name to use with IPC - * \param[in] client_uuid Client UUID to use with IPC - * - * \return Newly allocated object - * \note This function asserts on errors, so it will never return NULL. - * The caller is responsible for freeing the result with - * pcmk_free_controld_api(). - */ -pcmk_controld_api_t *pcmk_new_controld_api(const char *client_name, - const char *client_uuid); - -/*! - * \internal - * \brief Free a controller IPC API object - * - * \param[in] api Controller IPC API object to free - */ -void pcmk_free_controld_api(pcmk_controld_api_t *api); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tools/crm_resource_runtime.c b/tools/crm_resource_runtime.c index 37789d1..cc2abeb 100644 --- a/tools/crm_resource_runtime.c +++ b/tools/crm_resource_runtime.c @@ -8,6 +8,7 @@ */ #include +#include int resource_verbose = 0; bool do_force = FALSE; @@ -460,7 +461,7 @@ cli_resource_delete_attribute(pe_resource_t *rsc, const char *requested_name, // \return Standard Pacemaker return code static int -send_lrm_rsc_op(pcmk_controld_api_t *controld_api, bool do_fail_resource, +send_lrm_rsc_op(pcmk_ipc_api_t *controld_api, bool do_fail_resource, const char *host_uname, const char *rsc_id, pe_working_set_t *data_set) { @@ -528,14 +529,13 @@ send_lrm_rsc_op(pcmk_controld_api_t *controld_api, bool do_fail_resource, rsc_api_id = rsc->id; } if (do_fail_resource) { - return controld_api->fail_resource(controld_api, host_uname, - router_node, rsc_api_id, rsc_long_id, - rsc_class, rsc_provider, rsc_type); + return pcmk_controld_api_fail(controld_api, host_uname, router_node, + rsc_api_id, rsc_long_id, + rsc_class, rsc_provider, rsc_type); } else { - return controld_api->refresh_resource(controld_api, host_uname, - router_node, rsc_api_id, - rsc_long_id, rsc_class, - rsc_provider, rsc_type, cib_only); + return pcmk_controld_api_refresh(controld_api, host_uname, router_node, + rsc_api_id, rsc_long_id, rsc_class, + rsc_provider, rsc_type, cib_only); } } @@ -558,7 +558,7 @@ rsc_fail_name(pe_resource_t *rsc) // \return Standard Pacemaker return code static int -clear_rsc_history(pcmk_controld_api_t *controld_api, const char *host_uname, +clear_rsc_history(pcmk_ipc_api_t *controld_api, const char *host_uname, const char *rsc_id, pe_working_set_t *data_set) { int rc = pcmk_ok; @@ -574,16 +574,16 @@ clear_rsc_history(pcmk_controld_api_t *controld_api, const char *host_uname, } crm_trace("Processing %d mainloop inputs", - controld_api->replies_expected(controld_api)); + pcmk_controld_api_replies_expected(controld_api)); while (g_main_context_iteration(NULL, FALSE)) { crm_trace("Processed mainloop input, %d still remaining", - controld_api->replies_expected(controld_api)); + pcmk_controld_api_replies_expected(controld_api)); } return rc; } static int -clear_rsc_failures(pcmk_controld_api_t *controld_api, const char *node_name, +clear_rsc_failures(pcmk_ipc_api_t *controld_api, const char *node_name, const char *rsc_id, const char *operation, const char *interval_spec, pe_working_set_t *data_set) { @@ -683,7 +683,7 @@ clear_rsc_fail_attrs(pe_resource_t *rsc, const char *operation, } int -cli_resource_delete(pcmk_controld_api_t *controld_api, const char *host_uname, +cli_resource_delete(pcmk_ipc_api_t *controld_api, const char *host_uname, pe_resource_t *rsc, const char *operation, const char *interval_spec, bool just_failures, pe_working_set_t *data_set) @@ -792,7 +792,7 @@ cli_resource_delete(pcmk_controld_api_t *controld_api, const char *host_uname, } int -cli_cleanup_all(pcmk_controld_api_t *controld_api, const char *node_name, +cli_cleanup_all(pcmk_ipc_api_t *controld_api, const char *node_name, const char *operation, const char *interval_spec, pe_working_set_t *data_set) { @@ -905,7 +905,7 @@ cli_resource_check(cib_t * cib_conn, pe_resource_t *rsc) // \return Standard Pacemaker return code int -cli_resource_fail(pcmk_controld_api_t *controld_api, const char *host_uname, +cli_resource_fail(pcmk_ipc_api_t *controld_api, const char *host_uname, const char *rsc_id, pe_working_set_t *data_set) { crm_notice("Failing %s on %s", rsc_id, host_uname);