diff --git a/pengine/ptest.c b/pengine/ptest.c index 35da43193f..4e33e31f36 100644 --- a/pengine/ptest.c +++ b/pengine/ptest.c @@ -1,479 +1,479 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU 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 software 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 * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_LIBXML2 # include #endif gboolean use_stdin = FALSE; gboolean do_simulation = FALSE; gboolean inhibit_exit = FALSE; gboolean all_actions = FALSE; extern xmlNode * do_calculations( pe_working_set_t *data_set, xmlNode *xml_input, ha_time_t *now); extern void cleanup_calculations(pe_working_set_t *data_set); char *use_date = NULL; FILE *dot_strm = NULL; #define DOT_PREFIX "PE_DOT: " /* #define DOT_PREFIX "" */ #define dot_write(fmt...) if(dot_strm != NULL) { \ fprintf(dot_strm, fmt); \ fprintf(dot_strm, "\n"); \ } else { \ crm_debug(DOT_PREFIX""fmt); \ } static void init_dotfile(void) { dot_write(" digraph \"g\" {"); /* dot_write(" size = \"30,30\""); */ /* dot_write(" graph ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" bb = \"0,0,398.922306,478.927856\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ /* dot_write(" node ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" shape = \"ellipse\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ /* dot_write(" edge ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ } static char * create_action_name(action_t *action) { char *action_name = NULL; const char *action_host = NULL; if(action->node) { action_host = action->node->details->uname; action_name = crm_concat(action->uuid, action_host, ' '); } else if(action->pseudo) { action_name = crm_strdup(action->uuid); } else { action_host = ""; action_name = crm_concat(action->uuid, action_host, ' '); } if(safe_str_eq(action->task, RSC_CANCEL)) { char *tmp_action_name = action_name; action_name = crm_concat("Cancel", tmp_action_name, ' '); crm_free(tmp_action_name); } return action_name; } gboolean USE_LIVE_CIB = FALSE; static struct crm_option long_options[] = { /* Top-level Options */ {"help", 0, 0, '?', "This text"}, {"version", 0, 0, 'v', "Version information" }, {"verbose", 0, 0, 'V', "Increase debug output\n"}, {"show-scores", 0, 0, 's', "Display resource allocation scores"}, {"simulate", 0, 0, 'S', "\tSimulate the transition's execution to find invalid graphs\n"}, {"live-check", 0, 0, 'L', "Connect to the CIB and use the current contents as input"}, - {"xml-text", 0, 0, 'X', "\tRetrieve XML from the supplied string"}, + {"xml-text", 1, 0, 'X', "Retrieve XML from the supplied string"}, {"xml-file", 1, 0, 'x', "Retrieve XML from the named file"}, - {"xml-pipe", 1, 0, 'p', "Retrieve XML from stdin\n"}, + {"xml-pipe", 0, 0, 'p', "\tRetrieve XML from stdin\n"}, {"save-input", 1, 0, 'I', "\tSave the input to the named file"}, {"save-graph", 1, 0, 'G', "\tSave the transition graph (XML format) to the named file"}, {"save-dotfile",1, 0, 'D', "Save the transition graph (DOT format) to the named file\n"}, {0, 0, 0, 0} }; int main(int argc, char **argv) { gboolean process = TRUE; gboolean all_good = TRUE; enum transition_status graph_rc = -1; crm_graph_t *transition = NULL; ha_time_t *a_date = NULL; cib_t * cib_conn = NULL; xmlNode * cib_object = NULL; int argerr = 0; int flag; char *msg_buffer = NULL; gboolean optional = FALSE; pe_working_set_t data_set; const char *source = NULL; const char *xml_file = NULL; const char *dot_file = NULL; const char *graph_file = NULL; const char *input_file = NULL; /* disable glib's fancy allocators that can't be free'd */ GMemVTable vtable; vtable.malloc = malloc; vtable.realloc = realloc; vtable.free = free; vtable.calloc = calloc; vtable.try_malloc = malloc; vtable.try_realloc = realloc; g_mem_set_vtable(&vtable); crm_log_init("ptest", LOG_CRIT, FALSE, FALSE, 0, NULL); crm_set_options("V?vXD:G:I:Lwx:d:aSs", "[-?Vv] -[Xxp] {other options}", long_options, "Calculate the cluster's response to the supplied cluster state\n"); cl_log_set_facility(LOG_USER); while (1) { int option_index = 0; flag = crm_get_option(argc, argv, &option_index); if (flag == -1) break; switch(flag) { case 'S': do_simulation = TRUE; break; case 'a': all_actions = TRUE; break; case 'w': inhibit_exit = TRUE; break; case 'X': use_stdin = TRUE; break; case 's': show_scores = TRUE; break; case 'x': xml_file = optarg; break; case 'd': use_date = optarg; break; case 'D': dot_file = optarg; break; case 'G': graph_file = optarg; break; case 'I': input_file = optarg; break; case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 'L': USE_LIVE_CIB = TRUE; break; case 'v': case '?': crm_help(flag, 0); break; default: printf("?? getopt returned character code 0%o ??\n", flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) { printf("%s ", argv[optind++]); } printf("\n"); } if (optind > argc) { ++argerr; } if (argerr) { crm_err("%d errors in option parsing", argerr); crm_help('?', 1); } if(USE_LIVE_CIB) { int rc = cib_ok; source = "live cib"; cib_conn = cib_new(); rc = cib_conn->cmds->signon(cib_conn, "ptest", cib_command); if(rc == cib_ok) { crm_info("Reading XML from: live cluster"); cib_object = get_cib_copy(cib_conn); } else { fprintf(stderr, "Live CIB query failed: %s\n", cib_error2string(rc)); return 3; } if(cib_object == NULL) { fprintf(stderr, "Live CIB query failed: empty result\n"); return 3; } } else if(xml_file != NULL) { source = xml_file; cib_object = filename2xml(xml_file); } else if(use_stdin) { source = "stdin"; cib_object = filename2xml(NULL); } if(cib_object == NULL && source) { fprintf(stderr, "Could not parse configuration input from: %s\n", source); return 4; } else if(cib_object == NULL) { fprintf(stderr, "Not configuration specified\n"); crm_help('?', 1); } if(cli_config_update(&cib_object, NULL) == FALSE) { free_xml(cib_object); return cib_STALE; } if(validate_xml(cib_object, NULL, FALSE) != TRUE) { free_xml(cib_object); return cib_dtd_validation; } if(input_file != NULL) { FILE *input_strm = fopen(input_file, "w"); if(input_strm == NULL) { crm_perror(LOG_ERR,"Could not open %s for writing", input_file); } else { msg_buffer = dump_xml_formatted(cib_object); if(fprintf(input_strm, "%s\n", msg_buffer) < 0) { crm_perror(LOG_ERR,"Write to %s failed", input_file); } fflush(input_strm); fclose(input_strm); crm_free(msg_buffer); } } if(use_date != NULL) { a_date = parse_date(&use_date); log_date(LOG_WARNING, "Set fake 'now' to", a_date, ha_log_date|ha_log_time); log_date(LOG_WARNING, "Set fake 'now' to (localtime)", a_date, ha_log_date|ha_log_time|ha_log_local); } if(process) { if(show_scores) { fprintf(stdout, "Allocation scores:\n"); } do_calculations(&data_set, cib_object, a_date); } msg_buffer = dump_xml_formatted(data_set.graph); if(safe_str_eq(graph_file, "-")) { fprintf(stdout, "%s\n", msg_buffer); fflush(stdout); } else if(graph_file != NULL) { FILE *graph_strm = fopen(graph_file, "w"); if(graph_strm == NULL) { crm_perror(LOG_ERR,"Could not open %s for writing", graph_file); } else { if(fprintf(graph_strm, "%s\n\n", msg_buffer) < 0) { crm_perror(LOG_ERR,"Write to %s failed", graph_file); } fflush(graph_strm); fclose(graph_strm); } } crm_free(msg_buffer); if(dot_file != NULL) { dot_strm = fopen(dot_file, "w"); if(dot_strm == NULL) { crm_perror(LOG_ERR,"Could not open %s for writing", dot_file); } } if(dot_strm == NULL) { goto simulate; } init_dotfile(); slist_iter( action, action_t, data_set.actions, lpc, const char *style = "filled"; const char *font = "black"; const char *color = "black"; const char *fill = NULL; char *action_name = create_action_name(action); crm_debug_3("Action %d: %p", action->id, action); if(action->pseudo) { font = "orange"; } style = "dashed"; if(action->dumped) { style = "bold"; color = "green"; } else if(action->rsc != NULL && is_not_set(action->rsc->flags, pe_rsc_managed)) { color = "purple"; if(all_actions == FALSE) { goto dont_write; } } else if(action->optional) { color = "blue"; if(all_actions == FALSE) { goto dont_write; } } else { color = "red"; CRM_CHECK(action->runnable == FALSE, ;); } action->dumped = TRUE; dot_write("\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\" %s%s]", action_name, style, color, font, fill?"fillcolor=":"", fill?fill:""); dont_write: crm_free(action_name); ); slist_iter( action, action_t, data_set.actions, lpc, slist_iter( before, action_wrapper_t, action->actions_before, lpc2, char *before_name = NULL; char *after_name = NULL; const char *style = "dashed"; optional = TRUE; if(before->state == pe_link_dumped) { optional = FALSE; style = "bold"; } else if(action->pseudo && (before->type & pe_order_stonith_stop)) { continue; } else if(before->state == pe_link_dup) { continue; } else if(action->dumped && before->action->dumped) { optional = FALSE; } if(all_actions || optional == FALSE) { before_name = create_action_name(before->action); after_name = create_action_name(action); dot_write("\"%s\" -> \"%s\" [ style = %s]", before_name, after_name, style); crm_free(before_name); crm_free(after_name); } ); ); dot_write("}"); if(dot_strm != NULL) { fflush(dot_strm); fclose(dot_strm); } simulate: if(do_simulation == FALSE) { goto cleanup; } transition = unpack_graph(data_set.graph, "ptest"); transition->batch_limit = 0; print_graph(LOG_DEBUG, transition); do { graph_rc = run_graph(transition); } while(graph_rc == transition_active); if(graph_rc != transition_complete) { crm_crit("Transition failed: %s", transition_status(graph_rc)); print_graph(LOG_ERR, transition); } destroy_graph(transition); CRM_CHECK(graph_rc == transition_complete, all_good = FALSE; crm_err("An invalid transition was produced")); cleanup: cleanup_alloc_calculations(&data_set); crm_log_deinit(); /* required for MallocDebug.app */ if(inhibit_exit) { GMainLoop* mainloop = g_main_new(FALSE); g_main_run(mainloop); } if(all_good) { return 0; } return 5; } diff --git a/tools/cibadmin.c b/tools/cibadmin.c index 94b44b2961..5df4d2efc4 100644 --- a/tools/cibadmin.c +++ b/tools/cibadmin.c @@ -1,594 +1,507 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU 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 software 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 * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include -#ifdef HAVE_GETOPT_H -# include -#endif - int exit_code = cib_ok; int message_timer_id = -1; int message_timeout_ms = 30; GMainLoop *mainloop = NULL; IPC_Channel *crmd_channel = NULL; const char *host = NULL; void usage(const char *cmd, int exit_status); enum cib_errors do_init(void); int do_work(xmlNode *input, int command_options, xmlNode **output); gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data); gboolean admin_message_timeout(gpointer data); void cib_connection_destroy(gpointer user_data); void cibadmin_op_callback(xmlNode *msg, int call_id, int rc, xmlNode *output, void *user_data); int command_options = 0; const char *cib_action = NULL; typedef struct str_list_s { int num_items; char *value; struct str_list_s *next; } str_list_t; -char *this_msg_reference = NULL; char *obj_type = NULL; char *status = NULL; char *migrate_from = NULL; char *migrate_res = NULL; char *subtype = NULL; char *reset = NULL; int request_id = 0; int operation_status = 0; cib_t *the_cib = NULL; - gboolean force_flag = FALSE; -#define OPTARGS "V?o:QDUCEX:t:Srwlsh:MmBfbRx:pP5N:A:unc" +static struct crm_option long_options[] = { + {"help", 0, 0, '?', "This text"}, + {"version", 0, 0, 'v', "Version information" }, + {"verbose", 0, 0, 'V', "Increase debug output\n"}, + + {"xml-text", 1, 0, 'X', "Retrieve XML from the supplied string"}, + {"xml-file", 1, 0, 'x', "Retrieve XML from the named file"}, + {"xml-pipe", 0, 0, 'p', "\tRetrieve XML from stdin\n"}, + + {"timeout", 1, 0, 't', "Time (in seconds) to wait before declaring the operation failed"}, + {"xpath", 1, 0, 'A', "A valid XPath to use instead of -o"}, + {"obj_type", 1, 0, 'o', "Limit the scope of the operation to a specific section of the CIB." + "\n\t\t\t\tValid values are: nodes, resources, constraints, crm_config, rsc_defaults, op_defaults, status"}, + {"node", 0, 0, 'N', "\t(Advanced) Send command to the specified host\n"}, + + {"force", 0, 0, 'f'}, + {"sync-call", 0, 0, 's', "\tWait for call to complete before returning"}, + {"local", 0, 0, 'l', "\tCommand takes effect locally. Should only be used for queries"}, + {"allow-create",0, 0, 'c', "(Advanced) Allow the target of a -M operation to be created if they do not exist"}, + {"no-children", 0, 0, 'n', "(Advanced)\n"}, + {"no-bcast", 0, 0, 'b', NULL, 1}, + + {"upgrade", 0, 0, 'u', "\tUpgrade the configuration to the latest syntax"}, + {"query", 0, 0, 'Q', "\tQuery the contents of the CIB"}, + {"erase", 0, 0, 'E', "\tErase the contents of the whole CIB"}, + {"create", 0, 0, 'C', "\tCreate an object in the CIB. Will fail if the object already exists."}, + {"modify", 0, 0, 'M', "\tFind the object somewhere in the CIB's XML tree and update it. Fails if the object does not exist unless -c is specified"}, + {"replace", 0, 0, 'R', "\tRecursivly replace an object in the CIB"}, + {"delete", 0, 0, 'D', "\tDelete the first object matching the supplied criteria, Eg. " + "\n\t\t\t\tThe tagname and all attributes must match in order for the element to be deleted\n"}, + {"md5-sum", 0, 0, '5', "\tCalculate a CIB digest"}, + {"patch", 0, 0, 'P', "\tSupply an update in the form of an xml diff (as produced by crm_diff)"}, + {"bump", 0, 0, 'B', "\tIncrease the CIB's epoch value by 1"}, + {"sync", 0, 0, 'S', "\tForce a refresh of the CIB to all nodes"}, + {"make-slave", 0, 0, 'r', NULL, 1}, + {"make-master", 0, 0, 'w', NULL, 1}, + {"is-master", 0, 0, 'm', NULL, 1}, + + /* Legacy options */ + {"host", 0, 0, 'h', NULL, 1}, + {"force-quorum", 0, 0, 'f', NULL, 1}, + {F_CRM_DATA, 1, 0, 'X', NULL, 1}, + {CIB_OP_ERASE, 0, 0, 'E', NULL, 1}, + {CIB_OP_QUERY, 0, 0, 'Q', NULL, 1}, + {CIB_OP_CREATE, 0, 0, 'C', NULL, 1}, + {CIB_OP_REPLACE, 0, 0, 'R', NULL, 1}, + {CIB_OP_UPDATE, 0, 0, 'U', NULL, 1}, + {CIB_OP_MODIFY, 0, 0, 'M', NULL, 1}, + {CIB_OP_DELETE, 0, 0, 'D', NULL, 1}, + {CIB_OP_BUMP, 0, 0, 'B', NULL, 1}, + {CIB_OP_SYNC, 0, 0, 'S', NULL, 1}, + {CIB_OP_SLAVE, 0, 0, 'r', NULL, 1}, + {CIB_OP_MASTER, 0, 0, 'w', NULL, 1}, + {CIB_OP_ISMASTER,0, 0, 'm', NULL, 1}, + + {0, 0, 0, 0} +}; int main(int argc, char **argv) { int argerr = 0; int flag; const char *source = NULL; char *admin_input_xml = NULL; char *admin_input_file = NULL; gboolean dangerous_cmd = FALSE; gboolean admin_input_stdin = FALSE; xmlNode *output = NULL; xmlNode *input = NULL; -#ifdef HAVE_GETOPT_H int option_index = 0; - static struct option long_options[] = { - /* Top-level Options */ - /* legacy names */ - {CIB_OP_ERASE, 0, 0, 'E'}, - {CIB_OP_QUERY, 0, 0, 'Q'}, - {CIB_OP_CREATE, 0, 0, 'C'}, - {CIB_OP_REPLACE, 0, 0, 'R'}, - {CIB_OP_UPDATE, 0, 0, 'U'}, - {CIB_OP_MODIFY, 0, 0, 'M'}, - {CIB_OP_DELETE, 0, 0, 'D'}, - {CIB_OP_BUMP, 0, 0, 'B'}, - {CIB_OP_SYNC, 0, 0, 'S'}, - {CIB_OP_SLAVE, 0, 0, 'r'}, - {CIB_OP_MASTER, 0, 0, 'w'}, - {CIB_OP_ISMASTER,0, 0, 'm'}, - - {"upgrade", 0, 0, 'u'}, - {"erase", 0, 0, 'E'}, - {"query", 0, 0, 'Q'}, - {"create", 0, 0, 'C'}, - {"replace", 0, 0, 'R'}, - {"modify", 0, 0, 'M'}, - {"delete", 0, 0, 'D'}, - {"bump", 0, 0, 'B'}, - {"sync", 0, 0, 'S'}, - {"make-slave", 0, 0, 'r'}, - {"make-master", 0, 0, 'w'}, - {"is-master", 0, 0, 'm'}, - {"patch", 0, 0, 'P'}, - {"xpath", 1, 0, 'A'}, - - {"md5-sum", 0, 0, '5'}, - - {"file-mode", 1, 0, 0}, - - {"force-quorum",0, 0, 'f'}, - {"force", 0, 0, 'f'}, - {"local", 0, 0, 'l'}, - {"sync-call", 0, 0, 's'}, - {"allow-create",0, 0, 'c'}, - {"no-children", 0, 0, 'n'}, - {"no-bcast", 0, 0, 'b'}, - {"host", 0, 0, 'h'}, /* legacy */ - {"node", 0, 0, 'N'}, - {F_CRM_DATA, 1, 0, 'X'}, /* legacy */ - {"xml-text", 1, 0, 'X'}, - {"xml-file", 1, 0, 'x'}, - {"xml-pipe", 0, 0, 'p'}, - {"verbose", 0, 0, 'V'}, - {"help", 0, 0, '?'}, - {"reference", 1, 0, 0}, - {"timeout", 1, 0, 't'}, - - /* common options */ - {"obj_type", 1, 0, 'o'}, - - {0, 0, 0, 0} - }; -#endif - crm_log_init("cibadmin", LOG_CRIT, FALSE, FALSE, argc, argv); - + crm_set_options("V?vo:QDUCEX:t:Srwlsh:MmBfbRx:pP5N:A:unc", NULL, long_options, + "Provides direct access to the cluster configuration." + "\n Allows the configuration, or sections of it, to be queried, modified, replaced and deleted." + "\n Where necessary, XML data will be obtained using -X, -x, or -p options\n"); + if(argc < 2) { - usage(crm_system_name, LSB_EXIT_EINVAL); + crm_help('?',LSB_EXIT_EINVAL); } while (1) { -#ifdef HAVE_GETOPT_H - flag = getopt_long(argc, argv, OPTARGS, - long_options, &option_index); -#else - flag = getopt(argc, argv, OPTARGS); -#endif + flag = crm_get_option(argc, argv, &option_index); if (flag == -1) break; switch(flag) { -#ifdef HAVE_GETOPT_H - case 0: - if (safe_str_eq("reference", long_options[option_index].name)) { - this_msg_reference = crm_strdup(optarg); - - } else if (safe_str_eq("file-mode", long_options[option_index].name)) { - setenv("CIB_file", optarg, 1); - - } else { - printf("Long option (--%s) is not (yet?) properly supported\n", - long_options[option_index].name); - ++argerr; - } - break; -#endif case 't': message_timeout_ms = atoi(optarg); if(message_timeout_ms < 1) { message_timeout_ms = 30; } break; case 'A': obj_type = crm_strdup(optarg); command_options |= cib_xpath; break; case 'u': cib_action = CIB_OP_UPGRADE; dangerous_cmd = TRUE; break; case 'E': cib_action = CIB_OP_ERASE; dangerous_cmd = TRUE; break; case 'Q': cib_action = CIB_OP_QUERY; break; case 'P': cib_action = CIB_OP_APPLY_DIFF; break; case 'S': cib_action = CIB_OP_SYNC; break; case 'U': case 'M': cib_action = CIB_OP_MODIFY; break; case 'R': cib_action = CIB_OP_REPLACE; break; case 'C': cib_action = CIB_OP_CREATE; break; case 'D': cib_action = CIB_OP_DELETE; break; case '5': cib_action = "md5-sum"; break; case 'c': command_options |= cib_can_create; break; case 'n': command_options |= cib_no_children; break; case 'm': cib_action = CIB_OP_ISMASTER; command_options |= cib_scope_local; break; case 'B': cib_action = CIB_OP_BUMP; break; case 'r': dangerous_cmd = TRUE; cib_action = CIB_OP_SLAVE; break; case 'w': dangerous_cmd = TRUE; cib_action = CIB_OP_MASTER; command_options |= cib_scope_local; break; case 'V': command_options = command_options | cib_verbose; cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case '?': - usage(crm_system_name, LSB_EXIT_OK); + case 'v': + crm_help(flag, LSB_EXIT_OK); break; case 'o': crm_debug_2("Option %c => %s", flag, optarg); obj_type = crm_strdup(optarg); break; case 'X': crm_debug_2("Option %c => %s", flag, optarg); admin_input_xml = crm_strdup(optarg); break; case 'x': crm_debug_2("Option %c => %s", flag, optarg); admin_input_file = crm_strdup(optarg); break; case 'p': admin_input_stdin = TRUE; break; case 'h': host = crm_strdup(optarg); break; case 'l': command_options |= cib_scope_local; break; case 'b': dangerous_cmd = TRUE; command_options |= cib_inhibit_bcast; command_options |= cib_scope_local; break; case 's': command_options |= cib_sync_call; break; case 'f': force_flag = TRUE; command_options |= cib_quorum_override; break; default: printf("Argument code 0%o (%c)" " is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); - usage(crm_system_name, LSB_EXIT_EINVAL); + crm_help('?', LSB_EXIT_EINVAL); } if (optind > argc || cib_action == NULL) { ++argerr; } if (argerr) { - usage(crm_system_name, LSB_EXIT_GENERIC); + crm_help('?', LSB_EXIT_GENERIC); } if(dangerous_cmd && force_flag == FALSE) { fprintf(stderr, "The supplied command is considered dangerous." " To prevent accidental destruction of the cluster," " the --force flag is required in order to proceed.\n"); fflush(stderr); exit(LSB_EXIT_GENERIC); } if(admin_input_file != NULL) { input = filename2xml(admin_input_file); source = admin_input_file; } else if(admin_input_xml != NULL) { source = "input string"; input = string2xml(admin_input_xml); } else if(admin_input_stdin) { source = "STDIN"; input = stdin2xml(); } if(input != NULL) { crm_log_xml_debug(input, "[admin input]"); } else if(source) { fprintf(stderr, "Couldn't parse input from %s.\n", source); return 1; } if(safe_str_eq(cib_action, "md5-sum")) { char *digest = NULL; if(input == NULL) { fprintf(stderr, "Please supply XML to process with -X, -x or -p\n"); exit(1); } digest = calculate_xml_digest(input, FALSE, FALSE); fprintf(stderr, "Digest: "); fprintf(stdout, "%s\n", crm_str(digest)); crm_free(digest); exit(0); } exit_code = do_init(); if(exit_code != cib_ok) { crm_err("Init failed, could not perform requested operations"); fprintf(stderr, "Init failed, could not perform requested operations\n"); return -exit_code; } exit_code = do_work(input, command_options, &output); if (exit_code > 0) { /* wait for the reply by creating a mainloop and running it until * the callbacks are invoked... */ request_id = exit_code; the_cib->cmds->register_callback( the_cib, request_id, message_timeout_ms, FALSE, NULL, "cibadmin_op_callback", cibadmin_op_callback); mainloop = g_main_new(FALSE); crm_debug_3("%s waiting for reply from the local CIB", crm_system_name); crm_info("Starting mainloop"); g_main_run(mainloop); } else if(exit_code < 0) { crm_err("Call failed: %s", cib_error2string(exit_code)); fprintf(stderr, "Call failed: %s\n", cib_error2string(exit_code)); operation_status = exit_code; if(crm_str_eq(cib_action, CIB_OP_UPGRADE, TRUE)) { if(exit_code == cib_dtd_validation) { xmlNode *obj = NULL; int version = 0, rc = 0; rc = the_cib->cmds->query(the_cib, NULL, &obj, command_options); if(rc == cib_ok) { update_validation(&obj, &version, TRUE, FALSE); } } } } if(output != NULL) { char *buffer = dump_xml_formatted(output); fprintf(stdout, "%s\n", crm_str(buffer)); crm_free(buffer); } the_cib->cmds->signoff(the_cib); crm_debug_3("%s exiting normally", crm_system_name); return -exit_code; } int do_work(xmlNode *input, int call_options, xmlNode **output) { /* construct the request */ the_cib->call_timeout = message_timeout_ms; if (strcasecmp(CIB_OP_SYNC, cib_action) == 0) { crm_debug_4("Performing %s op...", cib_action); return the_cib->cmds->sync_from( the_cib, host, obj_type, call_options); } else if (strcasecmp(CIB_OP_SLAVE, cib_action) == 0 && (call_options ^ cib_scope_local) ) { crm_debug_4("Performing %s op on all nodes...", cib_action); return the_cib->cmds->set_slave_all(the_cib, call_options); } else if (strcasecmp(CIB_OP_MASTER, cib_action) == 0) { crm_debug_4("Performing %s op on all nodes...", cib_action); return the_cib->cmds->set_master(the_cib, call_options); } else if(cib_action != NULL) { crm_debug_4("Passing \"%s\" to variant_op...", cib_action); return the_cib->cmds->variant_op( the_cib, cib_action, host, obj_type, input, output, call_options); } else { crm_err("You must specify an operation"); } return cib_operation; } enum cib_errors do_init(void) { enum cib_errors rc = cib_ok; the_cib = cib_new(); rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command); if(rc != cib_ok) { crm_err("Signon to CIB failed: %s", cib_error2string(rc)); fprintf(stderr, "Signon to CIB failed: %s\n", cib_error2string(rc)); } return rc; } - -void -usage(const char *cmd, int exit_status) -{ - FILE *stream; - - stream = exit_status != 0 ? stderr : stdout; - - fprintf(stream, "%s -- Provides direct access to the cluster configuration.\n" - " Allows the configuration, or sections of it, to be queried, modified, replaced and deleted.\n\n", - cmd); - - fprintf(stream, "usage: %s [%s] command\n" - "\twhere necessary, XML data will be obtained using -X," - " -x, or -p options\n", cmd, OPTARGS); - - fprintf(stream, "Options\n"); - fprintf(stream, "\t--%s (-%c) \tobject type being operated on\n", - "obj_type", 'o'); - fprintf(stream, "\t\t\t\tValid values are: nodes, resources, constraints, crm_config, status\n"); - fprintf(stream, "\t--%s (-%c) \tSupply a valid XPath to use instead of an obj_type\n", "xpath", 'A'); - fprintf(stream, "\t--%s (-%c)\t\tturn on debug info." - " additional instance increase verbosity\n", "verbose", 'V'); - fprintf(stream, "\t--%s (-%c)\t\tthis help message\n", "help", '?'); - fprintf(stream, "\nCommands\n"); - fprintf(stream, "\t--%s (-%c)\tErase the contents of the whole CIB\n", "erase", 'E'); - fprintf(stream, "\t--%s (-%c)\t\n", "query", 'Q'); - fprintf(stream, "\t--%s (-%c)\t\n", "create", 'C'); - fprintf(stream, "\t--%s (-%c)\tCalculate an XML file's digest." - " Requires either -X, -x or -p\n", "md5-sum", '5'); - fprintf(stream, "\t--%s (-%c)\tRecursivly replace an object in the CIB\n", "replace",'R'); - fprintf(stream, "\t--%s (-%c)\tFind the object somewhere in the CIB's XML tree and update it\n", "modify", 'M'); - fprintf(stream, "\t--%s (-%c)", "delete", 'D'); - fprintf(stream, "\tDelete the first object matching the supplied criteria\n"); - fprintf(stream, "\t\t\tEg. \n"); - fprintf(stream, "\t\t\tThe tagname and all attributes must match in order for the element to be deleted\n"); - - fprintf(stream, "\t--%s (-%c)\t\n", "bump", 'B'); - fprintf(stream, "\t--%s (-%c)\t\n", "is-master",'m'); - fprintf(stream, "\t--%s (-%c)\t\n", "sync", 'S'); - fprintf(stream, "\nXML data\n"); - fprintf(stream, "\t--%s (-%c) \tRetrieve XML from the supplied string\n", "xml-text", 'X'); - fprintf(stream, "\t--%s (-%c) \tRetrieve XML from the named file\n", "xml-file", 'x'); - fprintf(stream, "\t--%s (-%c)\t\t\tRetrieve XML from STDIN\n", "xml-pipe", 'p'); - fprintf(stream, "\nAdvanced Options\n"); - fprintf(stream, "\t--%s (-%c)\t\t\tsend command to specified host." - " Applies to %s and %s commands only\n", "host", 'h', - "query", "sync"); - fprintf(stream, "\t--%s (-%c)\t\t\tcommand takes effect locally" - " on the specified host\n", "local", 'l'); - fprintf(stream, "\t--%s (-%c)\t\t\tcommand will not be broadcast even if" - " it altered the CIB\n", "no-bcast", 'b'); - fprintf(stream, "\t--%s (-%c)\t\twait for call to complete before" - " returning\n", "sync-call", 's'); - - fflush(stream); - - exit(exit_status); -} - - void cib_connection_destroy(gpointer user_data) { crm_err("Connection to the CIB terminated... exiting"); g_main_quit(mainloop); return; } void cibadmin_op_callback(xmlNode *msg, int call_id, int rc, xmlNode *output, void *user_data) { char *admin_input_xml = NULL; exit_code = rc; if(output != NULL) { admin_input_xml = dump_xml_formatted(output); } if(safe_str_eq(cib_action, CIB_OP_ISMASTER) && rc != cib_ok) { crm_info("CIB on %s is _not_ the master instance", host?host:"localhost"); fprintf(stderr, "CIB on %s is _not_ the master instance\n", host?host:"localhost"); } else if(safe_str_eq(cib_action, CIB_OP_ISMASTER)) { crm_info("CIB on %s _is_ the master instance", host?host:"localhost"); fprintf(stderr, "CIB on %s _is_ the master instance\n", host?host:"localhost"); } else if(rc != 0) { crm_warn("Call %s failed (%d): %s", cib_action, rc, cib_error2string(rc)); fprintf(stderr, "Call %s failed (%d): %s\n", cib_action, rc, cib_error2string(rc)); fprintf(stdout, "%s\n", crm_str(admin_input_xml)); } else if(safe_str_eq(cib_action, CIB_OP_QUERY) && output==NULL) { crm_err("Output expected in query response"); crm_log_xml(LOG_ERR, "no output", msg); } else if(output == NULL) { crm_info("Call passed"); } else { crm_info("Call passed"); fprintf(stdout, "%s\n", crm_str(admin_input_xml)); } crm_free(admin_input_xml); if(call_id == request_id) { g_main_quit(mainloop); } else { crm_info("Message was not the response we were looking for (%d vs. %d", call_id, request_id); } }