Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F7609508
test.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
18 KB
Referenced Files
None
Subscribers
None
test.c
View Options
/*
* Copyright (c) 2012 David Vossel <dvossel@redhat.com>
*
* 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 <crm_internal.h>
#include <glib.h>
#include <unistd.h>
#include <crm/crm.h>
#include <crm/services.h>
#include <crm/common/mainloop.h>
#include <crm/pengine/status.h>
#include <crm/cib.h>
#include <crm/lrmd.h>
/* *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", 0, 0, 'S', "\t\tUse tls backend for local connection"},
{"listen", 1, 0, 'l', "\tListen for a specific event string"},
{"api-call", 1, 0, 'c', "\tDirectly relates to lrmd api functions"},
{"no-wait", 0, 0, 'w', "\tMake api call and do not wait for result."},
{"is-running", 0, 0, 'R', "\tDetermine if a resource is registered and running."},
{"notify-orig", 0, 0, 'n', "\tOnly notify this client the results of an api action."},
{"notify-changes", 0, 0, 'o', "\tOnly notify client changes to recurring operations."},
{"-spacer-", 1, 0, '-', "\nParameters for api-call option"},
{"action", 1, 0, 'a'},
{"rsc-id", 1, 0, 'r'},
{"cancel-call-id", 1, 0, 'x'},
{"provider", 1, 0, 'P'},
{"class", 1, 0, 'C'},
{"type", 1, 0, 'T'},
{"interval", 1, 0, 'i'},
{"timeout", 1, 0, 't'},
{"start-delay", 1, 0, 's'},
{"param-key", 1, 0, 'k'},
{"param-val", 1, 0, 'v'},
{"-spacer-", 1, 0, '-'},
{0, 0, 0, 0}
};
/* *INDENT-ON* */
cib_t *cib_conn = NULL;
static int exec_call_id = 0;
static int exec_call_opts = 0;
extern void cleanup_alloc_calculations(pe_working_set_t * data_set);
static gboolean start_test(gpointer user_data);
static void try_connect(void);
static struct {
int verbose;
int quiet;
int print;
int interval;
int timeout;
int start_delay;
int cancel_call_id;
int no_wait;
int is_running;
int no_connect;
const char *api_call;
const char *rsc_id;
const char *provider;
const char *class;
const char *type;
const char *action;
const char *listen;
lrmd_key_value_t *params;
} options;
GMainLoop *mainloop = NULL;
lrmd_t *lrmd_conn = NULL;
static char event_buf_v0[1024];
static void
test_exit(int rc)
{
lrmd_api_delete(lrmd_conn);
crm_exit(rc);
}
#define print_result(result) \
if (!options.quiet) { \
result; \
} \
#define report_event(event) \
snprintf(event_buf_v0, sizeof(event_buf_v0), "NEW_EVENT event_type:%s rsc_id:%s action:%s rc:%s op_status:%s", \
lrmd_event_type2str(event->type), \
event->rsc_id, \
event->op_type ? event->op_type : "none", \
services_ocf_exitcode_str(event->rc), \
services_lrm_status_str(event->op_status)); \
crm_info("%s", event_buf_v0);;
static void
test_shutdown(int nsig)
{
lrmd_api_delete(lrmd_conn);
lrmd_conn = NULL;
}
static void
read_events(lrmd_event_data_t * event)
{
report_event(event);
if (options.listen) {
if (safe_str_eq(options.listen, event_buf_v0)) {
print_result(printf("LISTEN EVENT SUCCESSFUL\n"));
test_exit(0);
}
}
if (exec_call_id && (event->call_id == exec_call_id)) {
if (event->op_status == 0 && event->rc == 0) {
print_result(printf("API-CALL SUCCESSFUL for 'exec'\n"));
} else {
print_result(printf("API-CALL FAILURE for 'exec', rc:%d lrmd_op_status:%s\n",
event->rc, services_lrm_status_str(event->op_status)));
test_exit(-1);
}
if (!options.listen) {
test_exit(0);
}
}
}
static gboolean
timeout_err(gpointer data)
{
print_result(printf("LISTEN EVENT FAILURE - timeout occurred, never found.\n"));
test_exit(-1);
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) {
crm_info("lrmd client connection established");
start_test(NULL);
return;
} else {
sleep(1);
try_connect();
crm_notice("lrmd client connection failed");
}
}
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", 3000);
if (!rc) {
return; /* we'll hear back in async callback */
}
sleep(1);
}
print_result(printf("API CONNECTION FAILURE\n"));
test_exit(-1);
}
static gboolean
start_test(gpointer user_data)
{
int rc = 0;
if (!options.no_connect) {
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 (!options.api_call) {
return 0;
}
if (safe_str_eq(options.api_call, "exec")) {
rc = lrmd_conn->cmds->exec(lrmd_conn,
options.rsc_id,
options.action,
NULL,
options.interval,
options.timeout,
options.start_delay, exec_call_opts, options.params);
if (rc > 0) {
exec_call_id = rc;
print_result(printf("API-CALL 'exec' action pending, waiting on response\n"));
}
} else if (safe_str_eq(options.api_call, "register_rsc")) {
rc = lrmd_conn->cmds->register_rsc(lrmd_conn,
options.rsc_id,
options.class, options.provider, options.type, 0);
} else if (safe_str_eq(options.api_call, "get_rsc_info")) {
lrmd_rsc_info_t *rsc_info;
rsc_info = lrmd_conn->cmds->get_rsc_info(lrmd_conn, options.rsc_id, 0);
if (rsc_info) {
print_result(printf("RSC_INFO: id:%s class:%s provider:%s type:%s\n",
rsc_info->id, rsc_info->class,
rsc_info->provider ? rsc_info->provider : "<none>",
rsc_info->type));
lrmd_free_rsc_info(rsc_info);
rc = pcmk_ok;
} else {
rc = -1;
}
} else if (safe_str_eq(options.api_call, "unregister_rsc")) {
rc = lrmd_conn->cmds->unregister_rsc(lrmd_conn, options.rsc_id, 0);
} else if (safe_str_eq(options.api_call, "cancel")) {
rc = lrmd_conn->cmds->cancel(lrmd_conn, options.rsc_id, options.action, options.interval);
} else 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) {
print_result(printf("%s", output));
free(output);
}
} else if (safe_str_eq(options.api_call, "list_agents")) {
lrmd_list_t *list = NULL;
lrmd_list_t *iter = NULL;
rc = lrmd_conn->cmds->list_agents(lrmd_conn, &list, options.class, options.provider);
if (rc > 0) {
print_result(printf("%d agents found\n", rc));
for (iter = list; iter != NULL; iter = iter->next) {
print_result(printf("%s\n", iter->val));
}
lrmd_list_freeall(list);
rc = 0;
} else {
print_result(printf("API_CALL FAILURE - no agents found\n"));
rc = -1;
}
} else if (safe_str_eq(options.api_call, "list_ocf_providers")) {
lrmd_list_t *list = NULL;
lrmd_list_t *iter = NULL;
rc = lrmd_conn->cmds->list_ocf_providers(lrmd_conn, options.type, &list);
if (rc > 0) {
print_result(printf("%d providers found\n", rc));
for (iter = list; iter != NULL; iter = iter->next) {
print_result(printf("%s\n", iter->val));
}
lrmd_list_freeall(list);
rc = 0;
} else {
print_result(printf("API_CALL FAILURE - no providers found\n"));
rc = -1;
}
} else if (safe_str_eq(options.api_call, "list_standards")) {
lrmd_list_t *list = NULL;
lrmd_list_t *iter = NULL;
rc = lrmd_conn->cmds->list_standards(lrmd_conn, &list);
if (rc > 0) {
print_result(printf("%d standards found\n", rc));
for (iter = list; iter != NULL; iter = iter->next) {
print_result(printf("%s\n", iter->val));
}
lrmd_list_freeall(list);
rc = 0;
} else {
print_result(printf("API_CALL FAILURE - no providers found\n"));
rc = -1;
}
} else if (options.api_call) {
print_result(printf("API-CALL FAILURE unknown action '%s'\n", options.action));
test_exit(-1);
}
if (rc < 0) {
print_result(printf("API-CALL FAILURE for '%s' api_rc:%d\n", options.api_call, rc));
test_exit(-1);
}
if (options.api_call && rc == pcmk_ok) {
print_result(printf("API-CALL SUCCESSFUL for '%s'\n", options.api_call));
if (!options.listen) {
test_exit(0);
}
}
if (options.no_wait) {
/* just make the call and exit regardless of anything else. */
test_exit(0);
}
return 0;
}
static resource_t *
find_rsc_or_clone(const char *rsc, pe_working_set_t * data_set)
{
resource_t *the_rsc = pe_find_resource(data_set->resources, rsc);
if (the_rsc == NULL) {
char *as_clone = crm_concat(rsc, "0", ':');
the_rsc = pe_find_resource(data_set->resources, as_clone);
free(as_clone);
}
return the_rsc;
}
static int
generate_params(void)
{
int rc = 0;
pe_working_set_t data_set;
xmlNode *cib_xml_copy = NULL;
resource_t *rsc = NULL;
GHashTable *params = NULL;
GHashTable *meta = NULL;
GHashTableIter iter;
if (options.params) {
return 0;
}
set_working_set_defaults(&data_set);
cib_conn = cib_new();
rc = cib_conn->cmds->signon(cib_conn, "lrmd_test", cib_query);
if (rc != pcmk_ok) {
crm_err("Error signing on to the CIB service: %s\n", pcmk_strerror(rc));
rc = -1;
goto param_gen_bail;
}
cib_xml_copy = get_cib_copy(cib_conn);
if (!cib_xml_copy) {
crm_err("Error retrieving cib copy.");
rc = -1;
goto param_gen_bail;
}
if (cli_config_update(&cib_xml_copy, NULL, FALSE) == FALSE) {
crm_err("Error updating cib configuration");
rc = -1;
goto param_gen_bail;
}
data_set.input = cib_xml_copy;
data_set.now = crm_time_new(NULL);
cluster_status(&data_set);
if (options.rsc_id) {
rsc = find_rsc_or_clone(options.rsc_id, &data_set);
}
if (!rsc) {
crm_err("Resource does not exist in config");
rc = -1;
goto param_gen_bail;
}
params = g_hash_table_new_full(crm_str_hash,
g_str_equal, g_hash_destroy_str, g_hash_destroy_str);
meta = g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str);
get_rsc_attributes(params, rsc, NULL, &data_set);
get_meta_attributes(meta, rsc, NULL, &data_set);
if (params) {
char *key = NULL;
char *value = NULL;
g_hash_table_iter_init(&iter, params);
while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
options.params = lrmd_key_value_add(options.params, key, value);
}
g_hash_table_destroy(params);
}
if (meta) {
char *key = NULL;
char *value = NULL;
g_hash_table_iter_init(&iter, meta);
while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
char *crm_name = crm_meta_name(key);
options.params = lrmd_key_value_add(options.params, crm_name, value);
free(crm_name);
}
g_hash_table_destroy(meta);
}
param_gen_bail:
cleanup_alloc_calculations(&data_set);
return rc;
}
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 'l':
options.listen = optarg;
break;
case 'w':
options.no_wait = 1;
break;
case 'R':
options.is_running = 1;
break;
case 'n':
exec_call_opts = lrmd_opt_notify_orig_only;
break;
case 'o':
exec_call_opts = lrmd_opt_notify_changes_only;
break;
case 'c':
options.api_call = optarg;
break;
case 'a':
options.action = optarg;
break;
case 'r':
options.rsc_id = optarg;
break;
case 'x':
options.cancel_call_id = atoi(optarg);
break;
case 'P':
options.provider = optarg;
break;
case 'C':
options.class = optarg;
break;
case 'T':
options.type = optarg;
break;
case 'i':
options.interval = atoi(optarg);
break;
case 't':
options.timeout = atoi(optarg);
break;
case 's':
options.start_delay = 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':
use_tls = TRUE;
break;
default:
++argerr;
break;
}
}
if (argerr) {
crm_help('?', EX_USAGE);
}
if (optind > argc) {
++argerr;
}
if (!options.listen &&
(safe_str_eq(options.api_call, "metadata") ||
safe_str_eq(options.api_call, "list_agents") ||
safe_str_eq(options.api_call, "list_standards") ||
safe_str_eq(options.api_call, "list_ocf_providers"))) {
options.no_connect = 1;
}
crm_log_init("lrmd_ctest", LOG_INFO, TRUE, options.verbose ? TRUE : FALSE, argc, argv, FALSE);
if (options.is_running) {
if (!options.timeout) {
options.timeout = 30000;
}
options.interval = 0;
if (!options.rsc_id) {
crm_err("rsc-id must be given when is-running is used");
test_exit(-1);
}
if (generate_params()) {
print_result(printf
("Failed to retrieve rsc parameters from cib, can not determine if rsc is running.\n"));
test_exit(-1);
}
options.api_call = "exec";
options.action = "monitor";
exec_call_opts = lrmd_opt_notify_orig_only;
}
/* if we can't perform an api_call or listen for events,
* there is nothing to do */
if (!options.api_call && !options.listen) {
crm_err("Nothing to be done. Please specify 'api-call' and/or 'listen'");
return 0;
}
if (use_tls) {
lrmd_conn = lrmd_remote_api_new(NULL, "localhost", 0);
} else {
lrmd_conn = lrmd_api_new();
}
trig = mainloop_add_trigger(G_PRIORITY_HIGH, start_test, NULL);
mainloop_set_trigger(trig);
mainloop_add_signal(SIGTERM, test_shutdown);
crm_info("Starting");
mainloop = g_main_new(FALSE);
g_main_run(mainloop);
if (cib_conn != NULL) {
cib_conn->cmds->signoff(cib_conn);
cib_delete(cib_conn);
}
test_exit(0);
return 0;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Thu, Oct 16, 12:08 AM (20 h, 59 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2525055
Default Alt Text
test.c (18 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment