diff --git a/lrmd/Makefile.am b/lrmd/Makefile.am index 67f6329bd5..9addd1bd56 100644 --- a/lrmd/Makefile.am +++ b/lrmd/Makefile.am @@ -1,54 +1,63 @@ # Copyright (c) 2012 David Vossel # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # include $(top_srcdir)/Makefile.common testdir = $(datadir)/$(PACKAGE)/tests/lrmd test_SCRIPTS = regression.py lrmdlibdir = $(CRM_DAEMON_DIR) -lrmdlib_PROGRAMS = lrmd lrmd_test +lrmdlib_PROGRAMS = lrmd lrmd_test pacemaker_remote_ctl initdir = $(INITDIR) init_SCRIPTS = pacemaker_remote sbin_PROGRAMS = pacemaker_remoted if BUILD_SYSTEMD systemdunit_DATA = pacemaker_remote.service endif lrmd_SOURCES = main.c lrmd.c lrmd_LDADD = $(top_builddir)/lib/common/libcrmcommon.la \ $(top_builddir)/lib/services/libcrmservice.la \ $(top_builddir)/lib/lrmd/liblrmd.la \ $(top_builddir)/lib/fencing/libstonithd.la ${COMPAT_LIBS} pacemaker_remoted_SOURCES = main.c lrmd.c tls_backend.c ipc_proxy.c pacemaker_remoted_CFLAGS = -DSUPPORT_REMOTE pacemaker_remoted_LDADD = $(lrmd_LDADD) +pacemaker_remote_ctl_SOURCES = remote_ctl.c +pacemaker_remote_ctl_LDADD = $(top_builddir)/lib/common/libcrmcommon.la \ + $(top_builddir)/lib/lrmd/liblrmd.la \ + $(top_builddir)/lib/cib/libcib.la \ + $(top_builddir)/lib/services/libcrmservice.la \ + $(top_builddir)/lib/pengine/libpe_status.la \ + $(top_builddir)/pengine/libpengine.la + + lrmd_test_SOURCES = test.c lrmd_test_LDADD = $(top_builddir)/lib/common/libcrmcommon.la \ $(top_builddir)/lib/lrmd/liblrmd.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/services/libcrmservice.la \ $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/pengine/libpengine.la noinst_HEADERS = lrmd_private.h diff --git a/lrmd/remote_ctl.c b/lrmd/remote_ctl.c new file mode 100644 index 0000000000..d2ab9eb4eb --- /dev/null +++ b/lrmd/remote_ctl.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2015 David Vossel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +/* *INDENT-OFF* */ +static struct crm_option long_options[] = { + {"help", 0, 0, '?'}, + {"verbose", 0, 0, 'V', "\t\tPrint out logs and events to screen"}, + {"quiet", 0, 0, 'Q', "\t\tSuppress all output to screen"}, + {"tls", 1, 0, 'S', "\t\tSet tls host to contact"}, + {"tls-port", 1, 0, 'p', "\t\tUse custom tls port"}, + {"api-call", 1, 0, 'c', "\tDirectly relates to lrmd api functions"}, + {"-spacer-", 1, 0, '-', "\nParameters for api-call option"}, + {"action", 1, 0, 'a'}, + {"rsc-id", 1, 0, 'r'}, + {"provider", 1, 0, 'P'}, + {"class", 1, 0, 'C'}, + {"type", 1, 0, 'T'}, + {"timeout", 1, 0, 't'}, + {"param-key", 1, 0, 'k'}, + {"param-val", 1, 0, 'v'}, + + {"-spacer-", 1, 0, '-'}, + {0, 0, 0, 0} +}; +/* *INDENT-ON* */ + +static int wait_poke = 0; +static int exec_call_id = 0; +static gboolean client_start(gpointer user_data); +static void try_connect(void); + +static struct { + int verbose; + int quiet; + int print; + int interval; + int timeout; + int port; + const char *api_call; + const char *rsc_id; + const char *provider; + const char *class; + const char *type; + const char *action; + const char *listen; + const char *tls_host; + lrmd_key_value_t *params; +} options; + +GMainLoop *mainloop = NULL; +lrmd_t *lrmd_conn = NULL; + +static void +client_exit(int rc) +{ + lrmd_api_delete(lrmd_conn); + exit(rc); +} + +#define print_result(result) \ + if (!options.quiet) { \ + result; \ + } \ + +static void +client_shutdown(int nsig) +{ + lrmd_api_delete(lrmd_conn); + lrmd_conn = NULL; +} + +static void +read_events(lrmd_event_data_t * event) +{ + if (wait_poke && event->type == lrmd_event_poke) { + client_exit(PCMK_OCF_OK); + } + if ((event->call_id == exec_call_id) && (event->type == lrmd_event_exec_complete)) { + if (event->output) { + printf("%s", event->output); + } + + client_exit(event->rc); + } +} + +static gboolean +timeout_err(gpointer data) +{ + print_result(printf("timed out in remote_client\n")); + client_exit(PCMK_OCF_TIMEOUT); + + return FALSE; +} + +static void +connection_events(lrmd_event_data_t * event) +{ + int rc = event->connection_rc; + + if (event->type != lrmd_event_connect) { + /* ignore */ + return; + } + + if (!rc) { + client_start(NULL); + return; + } else { + sleep(1); + try_connect(); + } +} + +static void +try_connect(void) +{ + int tries = 10; + static int num_tries = 0; + int rc = 0; + + lrmd_conn->cmds->set_callback(lrmd_conn, connection_events); + for (; num_tries < tries; num_tries++) { + rc = lrmd_conn->cmds->connect_async(lrmd_conn, "lrmd", 10000); + + if (!rc) { + num_tries++; + return; /* we'll hear back in async callback */ + } + sleep(1); + } + + print_result(printf("Failed to connect to pacemaker remote.\n")); + client_exit(PCMK_OCF_UNKNOWN_ERROR); +} + +static gboolean +client_start(gpointer user_data) +{ + int rc = 0; + + if (!lrmd_conn->cmds->is_connected(lrmd_conn)) { + try_connect(); + /* async connect, this funciton will get called back into. */ + return 0; + } + + lrmd_conn->cmds->set_callback(lrmd_conn, read_events); + + if (options.timeout) { + g_timeout_add(options.timeout, timeout_err, NULL); + } + + if (safe_str_eq(options.api_call, "metadata")) { + char *output = NULL; + + rc = lrmd_conn->cmds->get_metadata(lrmd_conn, + options.class, + options.provider, options.type, &output, 0); + if (rc == pcmk_ok) { + printf("%s", output); + free(output); + client_exit(PCMK_OCF_OK); + } + client_exit(PCMK_OCF_UNKNOWN_ERROR); + + } else if (safe_str_eq(options.api_call, "poke")) { + rc = lrmd_conn->cmds->poke_connection(lrmd_conn); + if (rc != pcmk_ok) { + client_exit(PCMK_OCF_UNKNOWN_ERROR); + } + wait_poke = 1; + } else { + lrmd_rsc_info_t *rsc_info = NULL; + + rsc_info = lrmd_conn->cmds->get_rsc_info(lrmd_conn, options.rsc_id, 0); + if (rsc_info == NULL) { + rc = lrmd_conn->cmds->register_rsc(lrmd_conn, options.rsc_id, + options.class, options.provider, options.type, 0); + + if (rc != 0){ + print_result(printf("failed to register resource %s with pacemaker_remote. rc: %d\n", options.rsc_id, rc)); + client_exit(1); + } + } + lrmd_free_rsc_info(rsc_info); + + rc = lrmd_conn->cmds->exec(lrmd_conn, + options.rsc_id, + options.action, + NULL, + options.interval, + options.timeout, + 0, 0, options.params); + + if (rc > 0) { + exec_call_id = rc; + } else { + print_result(printf("execution of rsc %s failed. rc = %d\n", options.rsc_id, rc)); + client_exit(PCMK_OCF_UNKNOWN_ERROR); + } + } + + return 0; +} + +int +main(int argc, char **argv) +{ + int option_index = 0; + int argerr = 0; + int flag; + char *key = NULL; + char *val = NULL; + gboolean use_tls = FALSE; + crm_trigger_t *trig; + + crm_set_options(NULL, "mode [options]", long_options, + "Inject commands into the lrmd and watch for events\n"); + + while (1) { + flag = crm_get_option(argc, argv, &option_index); + if (flag == -1) + break; + + switch (flag) { + case '?': + crm_help(flag, EX_OK); + break; + case 'V': + options.verbose = 1; + break; + case 'Q': + options.quiet = 1; + options.verbose = 0; + break; + case 'c': + options.api_call = optarg; + break; + case 'a': + options.action = optarg; + break; + case 'r': + options.rsc_id = optarg; + break; + case 'P': + options.provider = optarg; + break; + case 'C': + options.class = optarg; + break; + case 'T': + options.type = optarg; + break; + case 't': + if(optarg) { + options.timeout = atoi(optarg); + } + break; + case 'k': + key = optarg; + if (key && val) { + options.params = lrmd_key_value_add(options.params, key, val); + key = val = NULL; + } + break; + case 'v': + val = optarg; + if (key && val) { + options.params = lrmd_key_value_add(options.params, key, val); + key = val = NULL; + } + break; + case 'S': + options.tls_host = optarg; + use_tls = TRUE; + break; + case 'p': + if(optarg) { + options.port = atoi(optarg); + } + use_tls = TRUE; + break; + default: + ++argerr; + break; + } + } + + if (argerr) { + crm_help('?', EX_USAGE); + } + if (optind > argc) { + ++argerr; + } + + /* if we can't perform an api_call or listen for events, + * there is nothing to do */ + if (!options.api_call ) { + print_result(printf("Nothing to be done. Please specify 'api-call'\n")); + return PCMK_OCF_UNKNOWN_ERROR; + } + + if (!options.timeout ) { + options.timeout = 20000; + } + if (use_tls) { + lrmd_conn = lrmd_remote_api_new(NULL, options.tls_host ? options.tls_host : "localhost", options.port); + } else { + lrmd_conn = lrmd_api_new(); + } + trig = mainloop_add_trigger(G_PRIORITY_HIGH, client_start, NULL); + mainloop_set_trigger(trig); + mainloop_add_signal(SIGTERM, client_shutdown); + + mainloop = g_main_new(FALSE); + g_main_run(mainloop); + + client_exit(0); + return 0; +}