diff --git a/crm/admin/cibadmin.c b/crm/admin/cibadmin.c index e0e1761130..4285fe638d 100644 --- a/crm/admin/cibadmin.c +++ b/crm/admin/cibadmin.c @@ -1,600 +1,599 @@ /* * 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 #ifdef HAVE_GETOPT_H # include #endif #include /* someone complaining about _ha_msg_mod not being found */ int exit_code = cib_ok; int message_timer_id = -1; int message_timeout_ms = 30*1000; 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(crm_data_t *input, int command_options, crm_data_t **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(const HA_Message *msg, int call_id, int rc, crm_data_t *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:MmBfbdRx:pP5" int main(int argc, char **argv) { int argerr = 0; int flag; char *admin_input_xml = NULL; char *admin_input_file = NULL; gboolean dangerous_cmd = FALSE; gboolean admin_input_stdin = FALSE; crm_data_t *output = NULL; crm_data_t *input = NULL; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {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'}, {"patch", 0, 0, 'P'}, {CIB_OP_DELETE, 0, 0, 'D'}, {CIB_OP_DELETE_ALT, 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'}, {"md5-sum", 0, 0, '5'}, {"force-quorum",0, 0, 'f'}, {"force", 0, 0, 'f'}, {"local", 0, 0, 'l'}, {"sync-call", 0, 0, 's'}, {"no-bcast", 0, 0, 'b'}, {"host", 0, 0, 'h'}, {F_CRM_DATA, 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); if(argc < 2) { usage(crm_system_name, 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 if (flag == -1) break; switch(flag) { #ifdef HAVE_GETOPT_H case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); if (safe_str_eq("reference", long_options[option_index].name)) { this_msg_reference = crm_strdup(optarg); } 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*1000; } 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 'd': cib_action = CIB_OP_DELETE_ALT; 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); 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); } if (optind > argc || cib_action == NULL) { ++argerr; } if (argerr) { usage(crm_system_name, 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); usage(crm_system_name, LSB_EXIT_GENERIC); } if(admin_input_file != NULL) { FILE *xml_strm = fopen(admin_input_file, "r"); input = file2xml(xml_strm, FALSE); if(input == NULL) { fprintf(stderr, "Couldn't parse input file: %s\n", admin_input_file); return 1; } fclose(xml_strm); } else if(admin_input_xml != NULL) { input = string2xml(admin_input_xml); if(input == NULL) { fprintf(stderr, "Couldn't parse input string: %s\n", admin_input_xml); return 1; } } else if(admin_input_stdin) { input = stdin2xml(); if(input == NULL) { fprintf(stderr, "Couldn't parse input from STDIN.\n"); return 1; } } if(input != NULL) { crm_log_xml_debug(input, "[admin input]"); } 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; add_cib_op_callback( request_id, FALSE, NULL, cibadmin_op_callback); mainloop = g_main_new(FALSE); crm_debug("Setting operation timeout to %dms for call %d", message_timeout_ms, request_id); message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); 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(output != NULL) { char *buffer = dump_xml_formatted(output); fprintf(stdout, "%s", crm_str(buffer)); crm_free(buffer); } crm_debug_3("%s exiting normally", crm_system_name); return -exit_code; } int do_work(crm_data_t *input, int call_options, crm_data_t **output) { /* construct the request */ 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); if(strcasecmp(CIB_OP_APPLY_DIFF, cib_action) != 0 && input != NULL && do_id_check(input, NULL, TRUE, FALSE)) { crm_err("ID Check failed."); return cib_id_check; } 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, "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\tValid values are: nodes, resources, constraints, crm_config, status\n"); fprintf(stream, "\t--%s (-%c)\tturn on debug info." " additional instance increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\tthis help message\n", "help", '?'); fprintf(stream, "\nCommands\n"); fprintf(stream, "\t--%s (-%c)\tErase the contents of the whole CIB\n", CIB_OP_ERASE, 'E'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_QUERY, 'Q'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_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", CIB_OP_REPLACE,'R'); fprintf(stream, "\t--%s (-%c)\tRecursivly update an object in the CIB\n", CIB_OP_UPDATE, 'U'); fprintf(stream, "\t--%s (-%c)\tFind the object somewhere in the CIB's XML tree and update is as --"CIB_OP_UPDATE" would\n", CIB_OP_MODIFY, 'M'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_DELETE, 'D'); fprintf(stream, "\t\t\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", CIB_OP_DELETE_ALT, 'd'); fprintf(stream, "\t\t\tDelete the object at specified fully qualified location\n"); fprintf(stream, "\t\t\tEg. ...\n"); fprintf(stream, "\t\t\tRequires -o\n"); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_BUMP, 'B'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_ISMASTER,'m'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_SYNC, 'S'); fprintf(stream, "\nXML data\n"); fprintf(stream, "\t--%s (-%c) \t\tRetrieve XML from the supplied string\n", F_CRM_DATA, '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)\tsend command to specified host." " Applies to %s and %s commands only\n", "host", 'h', CIB_OP_QUERY, CIB_OP_SYNC); fprintf(stream, "\t--%s (-%c)\tcommand takes effect locally" " on the specified host\n", "local", 'l'); fprintf(stream, "\t--%s (-%c)\tcommand will not be broadcast even if" " it altered the CIB\n", "no-bcast", 'b'); fprintf(stream, "\t--%s (-%c)\twait for call to complete before" " returning\n", "sync-call", 's'); fflush(stream); exit(exit_status); } gboolean admin_message_timeout(gpointer data) { if(safe_str_eq(cib_action, CIB_OP_SLAVE)) { exit_code = cib_ok; fprintf(stdout, "CIB service(s) are in slave mode.\n"); } else { exit_code = cib_reply_failed; fprintf(stderr, "No messages received in %d seconds.. aborting\n", (int)message_timeout_ms/1000); crm_err("No messages received in %d seconds", (int)message_timeout_ms/1000); } g_main_quit(mainloop); return FALSE; } void cib_connection_destroy(gpointer user_data) { crm_err("Connection to the CIB terminated... exiting"); g_main_quit(mainloop); return; } void cibadmin_op_callback(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data) { char *admin_input_xml = NULL; crm_info("our callback was invoked"); crm_log_message(LOG_MSG, msg); 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_message(LOG_ERR, 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); } } diff --git a/crm/admin/crm_attribute.c b/crm/admin/crm_attribute.c index c1ce724a74..50e4d6ea57 100644 --- a/crm/admin/crm_attribute.c +++ b/crm/admin/crm_attribute.c @@ -1,495 +1,493 @@ /* * 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 #include #include #include #ifdef HAVE_GETOPT_H # include #endif void usage(const char *cmd, int exit_status); gboolean BE_QUIET = FALSE; gboolean DO_WRITE = TRUE; gboolean DO_DELETE = FALSE; char *dest_node = NULL; char *set_name = NULL; char *attr_id = NULL; char *attr_name = NULL; const char *type = NULL; const char *rsc_id = NULL; const char *dest_uname = NULL; const char *attr_value = NULL; #define OPTARGS "V?GDQU:u:s:n:v:l:t:i:!r:" int main(int argc, char **argv) { gboolean is_done = FALSE; cib_t * the_cib = NULL; enum cib_errors rc = cib_ok; int cib_opts = cib_sync_call; int argerr = 0; int flag; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"quiet", 0, 0, 'Q'}, {"get-value", 0, 0, 'G'}, {"delete-attr", 0, 0, 'D'}, {"node-uname", 1, 0, 'U'}, {"node-uuid", 1, 0, 'u'}, {"set-name", 1, 0, 's'}, {"attr-id", 1, 0, 'i'}, {"attr-name", 1, 0, 'n'}, {"attr-value", 1, 0, 'v'}, {"resource-id", 1, 0, 'r'}, {"lifetime", 1, 0, 'l'}, {"type", 1, 0, 't'}, {"inhibit-policy-engine", 0, 0, '!'}, {0, 0, 0, 0} }; #endif crm_log_init(basename(argv[0]), LOG_ERR, FALSE, FALSE, argc, argv); if(argc < 2) { usage(crm_system_name, 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 if (flag == -1) break; switch(flag) { case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'G': DO_WRITE = FALSE; break; case 'Q': BE_QUIET = TRUE; break; case 'D': DO_DELETE = TRUE; break; case 'U': crm_debug_2("Option %c => %s", flag, optarg); dest_uname = optarg; break; case 'u': crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 's': crm_debug_2("Option %c => %s", flag, optarg); set_name = crm_strdup(optarg); break; case 'l': crm_debug_2("Option %c => %s", flag, optarg); type = optarg; break; case 't': crm_debug_2("Option %c => %s", flag, optarg); type = optarg; break; case 'n': crm_debug_2("Option %c => %s", flag, optarg); attr_name = crm_strdup(optarg); break; case 'i': crm_debug_2("Option %c => %s", flag, optarg); attr_id = crm_strdup(optarg); break; case 'v': crm_debug_2("Option %c => %s", flag, optarg); attr_value = optarg; break; case 'r': crm_debug_2("Option %c => %s", flag, optarg); rsc_id = optarg; break; case '!': crm_warn("Inhibiting notifications for this update"); cib_opts |= cib_inhibit_notify; 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"); } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } the_cib = cib_new(); rc = the_cib->cmds->signon( the_cib, crm_system_name, cib_command_synchronous); if(rc != cib_ok) { fprintf(stderr, "Error signing on to the CIB service: %s\n", cib_error2string(rc)); return rc; } if(safe_str_eq(crm_system_name, "crm_attribute") && type == NULL && dest_uname == NULL) { /* we're updating cluster options - dont populate dest_node */ type = XML_CIB_TAG_CRMCONFIG; } else if(dest_uname == NULL) { struct utsname name; if(uname(&name) < 0) { cl_perror("uname(2) call failed"); return 1; } dest_uname = name.nodename; crm_info("Detected uname: %s", dest_uname); } if(dest_node == NULL && dest_uname != NULL) { rc = query_node_uuid(the_cib, dest_uname, &dest_node); if(rc != cib_ok) { fprintf(stderr,"Could not map uname=%s to a UUID: %s\n", dest_uname, cib_error2string(rc)); return rc; } else { crm_info("Mapped %s to %s", dest_uname, crm_str(dest_node)); } } if(safe_str_eq(crm_system_name, "crm_master")) { int len = 0; if(safe_str_eq(type, "reboot")) { type = XML_CIB_TAG_STATUS; } else { type = XML_CIB_TAG_NODES; } rsc_id = getenv("OCF_RESOURCE_INSTANCE"); if(rsc_id == NULL && dest_node == NULL) { fprintf(stderr, "This program should only ever be " "invoked from inside an OCF resource agent.\n"); fprintf(stderr, "DO NOT INVOKE MANUALLY FROM THE COMMAND LINE.\n"); return 1; } else if(dest_node == NULL) { fprintf(stderr, "Could not determine node UUID.\n"); return 1; } else if(rsc_id == NULL) { fprintf(stderr, "Could not determine resource name.\n"); return 1; } len = 8 + strlen(rsc_id); crm_malloc0(attr_name, len); snprintf(attr_name, len, "master-%s", rsc_id); len = 3 + strlen(type) + strlen(attr_name) + strlen(dest_node); crm_malloc0(attr_id, len); snprintf(attr_id, len, "%s-%s-%s", type, attr_name, dest_node); len = 8 + strlen(dest_node); crm_malloc0(set_name, len); snprintf(set_name, len, "master-%s", dest_node); } else if(safe_str_eq(crm_system_name, "crm_failcount")) { type = XML_CIB_TAG_STATUS; if(rsc_id == NULL) { fprintf(stderr,"Please specify a resource with -r\n"); return 1; } if(dest_node == NULL) { fprintf(stderr,"Please specify a node with -U or -u\n"); return 1; } set_name = NULL; attr_name = crm_concat("fail-count", rsc_id, '-'); } else if(safe_str_eq(crm_system_name, "crm_standby")) { if(dest_node == NULL) { fprintf(stderr,"Please specify a node with -U or -u\n"); return 1; } else if(DO_DELETE) { rc = delete_standby( the_cib, dest_node, type, attr_value); } else if(DO_WRITE) { if(attr_value == NULL) { fprintf(stderr, "Please specify 'true' or 'false' with -v\n"); return 1; } rc = set_standby(the_cib, dest_node, type, attr_value); } else { char *read_value = NULL; char *scope = NULL; if(type) { scope = crm_strdup(type); } rc = query_standby( the_cib, dest_node, &scope, &read_value); if(BE_QUIET == FALSE) { if(attr_id) { fprintf(stdout, "id=%s ", attr_id); } if(attr_name) { fprintf(stdout, "name=%s ", attr_name); } fprintf(stdout, "scope=%s value=%s\n", scope, read_value?read_value:"(null)"); } else if(read_value != NULL) { fprintf(stdout, "%s\n", read_value); } else if(rc == cib_NOTEXISTS) { fprintf(stdout, "off\n"); rc = cib_ok; } crm_free(scope); } is_done = TRUE; } else if (type == NULL) { type = XML_CIB_TAG_NODES; return 1; } if(safe_str_eq(type, XML_CIB_TAG_CRMCONFIG)) { dest_node = NULL; } if(is_done) { } else if(DO_DELETE) { rc = delete_attr(the_cib, cib_opts, type, dest_node, set_name, attr_id, attr_name, attr_value, TRUE); if(rc == cib_NOTEXISTS) { /* Nothing to delete... * which means its not there... * which is what the admin wanted */ rc = cib_ok; } else if(rc != cib_missing_data && safe_str_eq(crm_system_name, "crm_failcount")) { char *now_s = NULL; time_t now = time(NULL); now_s = crm_itoa(now); update_attr(the_cib, cib_sync_call, XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, "last-lrm-refresh", now_s, TRUE); crm_free(now_s); } } else if(DO_WRITE) { CRM_DEV_ASSERT(type != NULL); CRM_DEV_ASSERT(attr_name != NULL); CRM_DEV_ASSERT(attr_value != NULL); rc = update_attr(the_cib, cib_opts, type, dest_node, set_name, attr_id, attr_name, attr_value, TRUE); } else { char *read_value = NULL; rc = read_attr(the_cib, type, dest_node, set_name, attr_id, attr_name, &read_value, TRUE); if(rc == cib_NOTEXISTS && safe_str_eq(crm_system_name, "crm_failcount")) { rc = cib_ok; read_value = crm_strdup("0"); } crm_info("Read %s=%s %s%s", attr_name, crm_str(read_value), set_name?"in ":"", set_name?set_name:""); if(rc == cib_missing_data) { rc = cib_ok; } else if(BE_QUIET == FALSE) { fprintf(stdout, "%s%s %s%s value=%s\n", attr_id?"id=":"", attr_id?attr_id:"", attr_name?"name=":"", attr_name?attr_name:"", read_value?read_value:"(null)"); } else if(read_value != NULL) { fprintf(stdout, "%s\n", read_value); } } the_cib->cmds->signoff(the_cib); if(rc == cib_missing_data) { printf("Please choose from one of the matches above and suppy the 'id' with --attr-id\n"); } else if(rc != cib_ok) { fprintf(stderr, "Error performing operation: %s\n", cib_error2string(rc)); } return rc; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; if(safe_str_eq(cmd, "crm_master")) { fprintf(stream, "usage: %s [-?VQ] -(D|G|v) [-l]\n", cmd); } else if(safe_str_eq(cmd, "crm_standby")) { fprintf(stream, "usage: %s [-?V] -(u|U) -(D|G|v) [-l]\n", cmd); } else if(safe_str_eq(cmd, "crm_failcount")) { fprintf(stream, "usage: %s [-?V] -(u|U) -(D|G|v) -r\n", cmd); } else { fprintf(stream, "usage: %s [-?V] -(D|G|v) [options]\n", cmd); } fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?'); fprintf(stream, "\t--%s (-%c)\t: " "turn on debug info. additional instances increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\t: Print only the value on stdout" " (use with -G)\n", "quiet", 'Q'); fprintf(stream, "\t--%s (-%c)\t: " "Retrieve rather than set the %s\n", "get-value", 'G', safe_str_eq(cmd, "crm_master")?"named attribute":"preference to be promoted"); fprintf(stream, "\t--%s (-%c)\t: " "Delete rather than set the attribute\n", "delete-attr", 'D'); fprintf(stream, "\t--%s (-%c) \t: " "Value to use (ignored with -G)\n", "attr-value", 'v'); fprintf(stream, "\t--%s (-%c) \t: " "The 'id' of the attribute. Advanced use only.\n", "attr-id", 'i'); if(safe_str_eq(cmd, "crm_master")) { fprintf(stream, "\t--%s (-%c) \t: " "How long the preference lasts (reboot|forever)\n", "lifetime", 'l'); exit(exit_status); } else if(safe_str_eq(cmd, "crm_standby")) { fprintf(stream, "\t--%s (-%c) \t: " "UUID of the node to change\n", "node-uuid", 'u'); fprintf(stream, "\t--%s (-%c) \t: " "uname of the node to change\n", "node-uname", 'U'); fprintf(stream, "\t--%s (-%c) \t: " "How long the preference lasts (reboot|forever)\n" "\t If a forever value exists, it is ALWAYS used by the CRM\n" "\t instead of any reboot value\n", "lifetime", 'l'); exit(exit_status); } fprintf(stream, "\t--%s (-%c) \t: " "UUID of the node to change\n", "node-uuid", 'u'); fprintf(stream, "\t--%s (-%c) \t: " "uname of the node to change\n", "node-uname", 'U'); if(safe_str_eq(cmd, "crm_failcount")) { fprintf(stream, "\t--%s (-%c) \t: " "name of the resource to operate on\n", "resource-id", 'r'); } else { fprintf(stream, "\t--%s (-%c) \t: " "Set of attributes in which to read/write the attribute\n", "set-name", 's'); fprintf(stream, "\t--%s (-%c) \t: " "Attribute to set\n", "attr-name", 'n'); fprintf(stream, "\t--%s (-%c) \t: " "Which section of the CIB to set the attribute: (%s|%s|%s)\n", "type", 't', XML_CIB_TAG_NODES, XML_CIB_TAG_STATUS, XML_CIB_TAG_CRMCONFIG); fprintf(stream, "\t -t=%s options: -(U|u) -n [-s]\n", XML_CIB_TAG_NODES); fprintf(stream, "\t -t=%s options: -(U|u) -n [-s]\n", XML_CIB_TAG_STATUS); fprintf(stream, "\t -t=%s options: -n [-s]\n", XML_CIB_TAG_CRMCONFIG); } if(safe_str_neq(crm_system_name, "crm_standby")) { fprintf(stream, "\t--%s (-%c)\t: " "Make a change and prevent the TE/PE from seeing it straight away.\n" "\t You may think you want this option but you don't." " Advanced use only - you have been warned!\n", "inhibit-policy-engine", '!'); } fflush(stream); exit(exit_status); } diff --git a/crm/admin/crm_mon.c b/crm/admin/crm_mon.c index 9a6e2db7f5..4a83aab9bf 100644 --- a/crm/admin/crm_mon.c +++ b/crm/admin/crm_mon.c @@ -1,818 +1,816 @@ /* * 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 #include #include #include #include #include #include #ifdef HAVE_GETOPT_H # include #endif /* GMainLoop *mainloop = NULL; */ #define OPTARGS "V?i:nrh:cdp:s1wX:" void usage(const char *cmd, int exit_status); void blank_screen(void); int print_status(crm_data_t *cib); void print_warn(const char *descr); int print_simple_status(crm_data_t *cib); /* #define printw_at(line, fmt...) move(line, 0); printw(fmt); line++ */ void wait_for_refresh(int offset, const char *prefix, int msec); int print_html_status(crm_data_t *cib, const char *filename, gboolean web_cgi); void make_daemon(gboolean daemonize, const char *pidfile); gboolean mon_timer_popped(gpointer data); void mon_update(const HA_Message*, int, int, crm_data_t*,void*); char *xml_file = NULL; char *as_html_file = NULL; char *pid_file = NULL; gboolean as_console = FALSE; gboolean simple_status = FALSE; gboolean group_by_node = FALSE; gboolean inactive_resources = FALSE; gboolean web_cgi = FALSE; int interval = 15000; gboolean daemonize = FALSE; GMainLoop* mainloop = NULL; guint timer_id = 0; cib_t *cib_conn = NULL; int failed_connections = 0; gboolean one_shot = FALSE; gboolean has_warnings = FALSE; #if CURSES_ENABLED # define print_as(fmt...) if(as_console) { \ printw(fmt); \ } else { \ fprintf(stdout, fmt); \ } #else # define print_as(fmt...) fprintf(stdout, fmt); #endif int main(int argc, char **argv) { int argerr = 0; int flag; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"interval", 1, 0, 'i'}, {"group-by-node", 0, 0, 'n'}, {"inactive", 0, 0, 'r'}, {"as-html", 1, 0, 'h'}, {"web-cgi", 0, 0, 'w'}, {"simple-status", 0, 0, 's'}, {"as-console", 0, 0, 'c'}, {"one-shot", 0, 0, '1'}, {"daemonize", 0, 0, 'd'}, {"pid-file", 0, 0, 'p'}, {"xml-file", 1, 0, 'X'}, {0, 0, 0, 0} }; #endif pid_file = crm_strdup("/tmp/ClusterMon.pid"); crm_log_init(basename(argv[0]), LOG_ERR-1, FALSE, FALSE, 0, NULL); if (strcmp(crm_system_name, "crm_mon.cgi")==0) { web_cgi = TRUE; one_shot = TRUE; } while (1) { #ifdef HAVE_GETOPT_H flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); #else flag = getopt(argc, argv, OPTARGS); #endif if (flag == -1) break; switch(flag) { case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 'i': interval = crm_get_msec(optarg); break; case 'n': group_by_node = TRUE; break; case 'r': inactive_resources = TRUE; break; case 'd': daemonize = TRUE; break; case 'p': pid_file = crm_strdup(optarg); break; case 'X': xml_file = crm_strdup(optarg); one_shot = TRUE; break; case 'h': as_html_file = crm_strdup(optarg); break; case 'w': web_cgi = TRUE; one_shot = TRUE; break; case 'c': #if CURSES_ENABLED as_console = TRUE; #else printf("You need to have curses available at compile time to enable console mode\n"); argerr++; #endif break; case 's': simple_status = TRUE; one_shot = TRUE; break; case '1': one_shot = TRUE; 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"); } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } if(as_html_file == NULL && !web_cgi && !simple_status) { #if CURSES_ENABLED as_console = TRUE; #else printf("Defaulting to one-shot mode\n"); printf("You need to have curses available at compile time to enable console mode\n"); one_shot = TRUE; #endif } if(daemonize) { as_console = FALSE; } if(one_shot) { daemonize = FALSE; as_console = FALSE; } if(daemonize && as_html_file == NULL) { usage(crm_system_name, LSB_EXIT_GENERIC); } make_daemon(daemonize, pid_file); #if CURSES_ENABLED if(as_console) { initscr(); cbreak(); noecho(); } #endif crm_info("Starting %s", crm_system_name); mainloop = g_main_new(FALSE); if(one_shot == FALSE) { timer_id = Gmain_timeout_add( interval, mon_timer_popped, NULL); } else if(xml_file != NULL) { FILE *xml_strm = fopen(xml_file, "r"); crm_data_t *cib_object = NULL; if(strstr(xml_file, ".bz2") != NULL) { cib_object = file2xml(xml_strm, TRUE); } else { cib_object = file2xml(xml_strm, FALSE); } if(xml_strm != NULL) { fclose(xml_strm); } one_shot = TRUE; mon_update(NULL, 0, cib_ok, cib_object, NULL); } mon_timer_popped(NULL); g_main_run(mainloop); return_to_orig_privs(); crm_info("Exiting %s", crm_system_name); #if CURSES_ENABLED if(as_console) { echo(); nocbreak(); endwin(); } #endif return 0; } gboolean mon_timer_popped(gpointer data) { int rc = cib_ok; int options = cib_scope_local; if(timer_id > 0) { Gmain_timeout_remove(timer_id); } if(as_console) { #if CURSES_ENABLED move(0, 0); printw("Updating...\n"); clrtoeol(); refresh(); #endif } else { crm_notice("Updating..."); } if(cib_conn == NULL) { crm_debug_4("Creating CIB connection"); cib_conn = cib_new(); } CRM_DEV_ASSERT(cib_conn != NULL); if(crm_assert_failed) { return FALSE; } else if(cib_conn->state != cib_connected_query){ crm_debug_4("Connecting to the CIB"); #if CURSES_ENABLED if(as_console) { printw("Signing on...\n"); clrtoeol(); refresh(); } #endif if(cib_ok == cib_conn->cmds->signon( cib_conn, crm_system_name, cib_query)) { failed_connections = 0; } else if (simple_status || one_shot) { fprintf(stdout, "Critical: Unable to connect to the CIB\n"); exit(2); } else { failed_connections++; CRM_DEV_ASSERT(cib_conn->cmds->signoff(cib_conn) == cib_ok); wait_for_refresh(0, "Not connected: ", 2*interval); return FALSE; } #if CURSES_ENABLED if(as_console) { printw("Querying...\n"); clrtoeol(); refresh(); } #endif } if(as_console) { blank_screen(); } rc = cib_conn->cmds->query(cib_conn, NULL, NULL, options); add_cib_op_callback(rc, FALSE, NULL, mon_update); return FALSE; } void mon_update(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void*user_data) { const char *prefix = NULL; if(rc == cib_ok) { crm_data_t *cib = NULL; #if CRM_DEPRECATED_SINCE_2_0_4 if( safe_str_eq(crm_element_name(output), XML_TAG_CIB) ) { cib = output; } else { cib = find_xml_node(output,XML_TAG_CIB,TRUE); } #else cib = output; CRM_DEV_ASSERT(safe_str_eq(crm_element_name(cib), XML_TAG_CIB)); #endif if(as_html_file || web_cgi) { print_html_status(cib, as_html_file, web_cgi); } else if (simple_status) { print_simple_status(cib); if (has_warnings) { exit(1); } } else { print_status(cib); } if(one_shot) { exit(LSB_EXIT_OK); } } else if(simple_status) { fprintf(stderr, "Critical: query failed: %s", cib_error2string(rc)); exit(2); } else if(one_shot) { fprintf(stderr, "Query failed: %s", cib_error2string(rc)); exit(LSB_EXIT_OK); } else { CRM_DEV_ASSERT(cib_conn->cmds->signoff(cib_conn) == cib_ok); crm_err("Query failed: %s", cib_error2string(rc)); prefix = "Query failed! "; } wait_for_refresh(0, prefix, interval); } void wait_for_refresh(int offset, const char *prefix, int msec) { int lpc = msec / 1000; if(as_console == FALSE) { timer_id = Gmain_timeout_add(msec, mon_timer_popped, NULL); return; } crm_notice("%sRefresh in %ds...", prefix?prefix:"", lpc); while(lpc > 0) { #if CURSES_ENABLED move(0, 0); /* printw("%sRefresh in \033[01;32m%ds\033[00m...", prefix?prefix:"", lpc); */ printw("%sRefresh in %ds...\n", prefix?prefix:"", lpc); clrtoeol(); refresh(); #endif lpc--; if(lpc == 0) { timer_id = Gmain_timeout_add( 1000, mon_timer_popped, NULL); } else { sleep(1); } } } #define mon_warn(fmt...) do { \ if (!has_warnings) { \ print_as("Warning:"); \ } else { \ print_as(","); \ } \ print_as(fmt); \ has_warnings = TRUE; \ } while(0) int print_simple_status(crm_data_t *cib) { node_t *dc = NULL; int nodes_online = 0; int nodes_standby = 0; pe_working_set_t data_set; set_working_set_defaults(&data_set); data_set.input = cib; cluster_status(&data_set); dc = data_set.dc_node; if(dc == NULL) { mon_warn("No DC "); } slist_iter(node, node_t, data_set.nodes, lpc2, if(node->details->standby) { nodes_standby++; } else if(node->details->online) { nodes_online++; } else { mon_warn("offline node: %s", node->details->uname); } ); if (!has_warnings) { print_as("Ok: %d nodes online", nodes_online); if (nodes_standby > 0) { print_as(", %d standby nodes", nodes_standby); } print_as(", %d resources configured", g_list_length(data_set.resources)); } print_as("\n"); data_set.input = NULL; cleanup_calculations(&data_set); return 0; } int print_status(crm_data_t *cib) { node_t *dc = NULL; static int updates = 0; pe_working_set_t data_set; char *since_epoch = NULL; time_t a_time = time(NULL); int configured_resources = 0; int print_opts = pe_print_ncurses; if(as_console) { blank_screen(); } else { print_opts = pe_print_printf; } updates++; set_working_set_defaults(&data_set); data_set.input = cib; cluster_status(&data_set); dc = data_set.dc_node; print_as("\n\n============\n"); if(a_time == (time_t)-1) { cl_perror("set_node_tstamp(): Invalid time returned"); return 1; } since_epoch = ctime(&a_time); if(since_epoch != NULL) { print_as("Last updated: %s", since_epoch); } if(dc == NULL) { print_as("Current DC: NONE\n"); } else { print_as("Current DC: %s (%s)\n", dc->details->uname, dc->details->id); } slist_iter(rsc, resource_t, data_set.resources, lpc, if(is_not_set(rsc->flags, pe_rsc_orphan)) { configured_resources++; } ); print_as("%d Nodes configured.\n", g_list_length(data_set.nodes)); print_as("%d Resources configured.\n", configured_resources); print_as("============\n\n"); slist_iter(node, node_t, data_set.nodes, lpc2, const char *node_mode = "OFFLINE"; if(node->details->standby) { node_mode = "standby"; } else if(node->details->online) { node_mode = "online"; } print_as("Node: %s (%s): %s\n", node->details->uname, node->details->id, node_mode); if(group_by_node) { slist_iter(rsc, resource_t, node->details->running_rsc, lpc2, rsc->fns->print( rsc, "\t", print_opts|pe_print_rsconly, stdout); ); } ); if(group_by_node == FALSE && inactive_resources) { print_as("\nFull list of resources:\n"); } else if(inactive_resources) { print_as("\nInactive resources:\n"); } if(group_by_node == FALSE || inactive_resources) { print_as("\n"); slist_iter(rsc, resource_t, data_set.resources, lpc2, gboolean is_active = rsc->fns->active(rsc, TRUE); gboolean partially_active = rsc->fns->active(rsc, FALSE); if(is_set(rsc->flags, pe_rsc_orphan) && is_active == FALSE) { continue; } else if(group_by_node == FALSE) { if(partially_active || inactive_resources) { rsc->fns->print(rsc, NULL, print_opts, stdout); } } else if(is_active == FALSE && inactive_resources) { rsc->fns->print(rsc, NULL, print_opts, stdout); } ); } if(xml_has_children(data_set.failed)) { print_as("\nFailed actions:\n"); xml_child_iter(data_set.failed, xml_op, const char *id = ID(xml_op); const char *rc = crm_element_value(xml_op, XML_LRM_ATTR_RC); const char *node = crm_element_value(xml_op, XML_ATTR_UNAME); const char *call = crm_element_value(xml_op, XML_LRM_ATTR_CALLID); const char *status_s = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS); int status = crm_parse_int(status_s, "0"); print_as(" %s (node=%s, call=%s, rc=%s): %s\n", id, node, call, rc, op_status2text(status)); ); } #if CURSES_ENABLED if(as_console) { refresh(); } #endif data_set.input = NULL; cleanup_calculations(&data_set); return 0; } int print_html_status(crm_data_t *cib, const char *filename, gboolean web_cgi) { FILE *stream; node_t *dc = NULL; static int updates = 0; pe_working_set_t data_set; char *filename_tmp = NULL; if (web_cgi) { stream=stdout; fprintf(stream, "Content-type: text/html\n\n"); } else { filename_tmp = crm_concat(filename, "tmp", '.'); stream = fopen(filename_tmp, "w"); cl_perror("Cannot open %s for writing", filename_tmp); if(stream == NULL) { crm_free(filename_tmp); return -1; } } updates++; set_working_set_defaults(&data_set); data_set.input = cib; cluster_status(&data_set); dc = data_set.dc_node; fprintf(stream, ""); fprintf(stream, ""); fprintf(stream, "Cluster status"); /* content="%d;url=http://webdesign.about.com" */ fprintf(stream, "", interval); fprintf(stream, ""); /*** SUMMARY ***/ fprintf(stream, "

Cluster summary

"); { char *now_str = NULL; time_t now = time(NULL); now_str = ctime(&now); now_str[24] = EOS; /* replace the newline */ fprintf(stream, "Last updated: %s
\n", now_str); } if(dc == NULL) { fprintf(stream, "Current DC: NONE
"); } else { fprintf(stream, "Current DC: %s (%s)
", dc->details->uname, dc->details->id); } fprintf(stream, "%d Nodes configured.
", g_list_length(data_set.nodes)); fprintf(stream, "%d Resources configured.
", g_list_length(data_set.resources)); /*** CONFIG ***/ fprintf(stream, "

Config Options

\n"); fprintf(stream, "\n"); fprintf(stream, "\n", data_set.default_resource_stickiness); fprintf(stream, "\n", data_set.stonith_enabled?"enabled":"disabled"); fprintf(stream, "\n", data_set.symmetric_cluster?"":"a-"); fprintf(stream, "\n
Default resource stickiness:%d
STONITH of failed nodes:%s
Cluster is:%ssymmetric
No Quorum Policy:"); switch (data_set.no_quorum_policy) { case no_quorum_freeze: fprintf(stream, "Freeze resources"); break; case no_quorum_stop: fprintf(stream, "Stop ALL resources"); break; case no_quorum_ignore: fprintf(stream, "Ignore"); break; } fprintf(stream, "\n
\n"); /*** NODE LIST ***/ fprintf(stream, "

Node List

\n"); fprintf(stream, "
    \n"); slist_iter(node, node_t, data_set.nodes, lpc2, fprintf(stream, "
  • "); fprintf(stream, "Node: %s (%s): %s", node->details->uname, node->details->id, node->details->online?"online\n":"OFFLINE\n"); if(group_by_node) { fprintf(stream, "
      \n"); slist_iter(rsc, resource_t, node->details->running_rsc, lpc2, fprintf(stream, "
    • "); rsc->fns->print(rsc, NULL, pe_print_html, stream); fprintf(stream, "
    • \n"); ); fprintf(stream, "
    \n"); } fprintf(stream, "
  • \n"); ); fprintf(stream, "
\n"); if(group_by_node && inactive_resources) { fprintf(stream, "

(Partially) Inactive Resources

\n"); } else if(group_by_node == FALSE) { fprintf(stream, "

Resource List

\n"); } if(group_by_node == FALSE || inactive_resources) { slist_iter(rsc, resource_t, data_set.resources, lpc2, if(group_by_node && rsc->fns->active(rsc, TRUE)) { continue; } rsc->fns->print(rsc, NULL, pe_print_html, stream); ); } data_set.input = NULL; cleanup_calculations(&data_set); fprintf(stream, ""); fflush(stream); fclose(stream); if (!web_cgi) { if(rename(filename_tmp, filename) != 0) { cl_perror("Unable to rename %s->%s", filename_tmp, filename); } crm_free(filename_tmp); } return 0; } void blank_screen(void) { #if CURSES_ENABLED int lpc = 0; for(lpc = 0; lpc < LINES; lpc++) { move(lpc, 0); clrtoeol(); } move(0, 0); #endif } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-%s]\n", cmd, OPTARGS); fprintf(stream, "\t--%s (-%c) \t: This text\n", "help", '?'); fprintf(stream, "\t--%s (-%c) \t: Increase the debug output\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c) \t: Update frequency\n", "interval", 'i'); fprintf(stream, "\t--%s (-%c) \t:Group resources by node\n", "group-by-node", 'n'); fprintf(stream, "\t--%s (-%c) \t:Display inactive resources\n", "inactive", 'r'); fprintf(stream, "\t--%s (-%c) \t: Display cluster status on the console\n", "as-console", 'c'); fprintf(stream, "\t--%s (-%c) \t: Display the cluster status once as " "a simple one line output (suitable for nagios)\n", "simple-status", 's'); fprintf(stream, "\t--%s (-%c) \t: Display the cluster status once on " "the console and exit (doesnt use ncurses)\n", "one-shot", '1'); fprintf(stream, "\t--%s (-%c) \t: Write cluster status to the named file\n", "as-html", 'h'); fprintf(stream, "\t--%s (-%c) \t: Web mode with output suitable for cgi\n", "web-cgi", 'w'); fprintf(stream, "\t--%s (-%c) \t: Run in the background as a daemon\n", "daemonize", 'd'); fprintf(stream, "\t--%s (-%c) \t: Daemon pid file location\n", "pid-file", 'p'); fflush(stream); exit(exit_status); } void make_daemon(gboolean daemonize, const char *pidfile) { long pid; const char *devnull = "/dev/null"; if (daemonize == FALSE){ return; } pid = fork(); if (pid < 0) { fprintf(stderr, "%s: could not start daemon\n", crm_system_name); perror("fork"); exit(LSB_EXIT_GENERIC); } else if (pid > 0) { exit(LSB_EXIT_OK); } if (cl_lock_pidfile(pidfile) < 0 ){ pid = cl_read_pidfile(pidfile); fprintf(stderr, "%s: already running [pid %ld].\n", crm_system_name, pid); exit(LSB_EXIT_OK); } umask(022); - close(FD_STDIN); + close(0); + close(1); + close(2); (void)open(devnull, O_RDONLY); /* Stdin: fd 0 */ - close(FD_STDOUT); (void)open(devnull, O_WRONLY); /* Stdout: fd 1 */ - close(FD_STDERR); (void)open(devnull, O_WRONLY); /* Stderr: fd 2 */ } diff --git a/crm/admin/crm_resource.c b/crm/admin/crm_resource.c index 77a96190ed..3c5f337021 100644 --- a/crm/admin/crm_resource.c +++ b/crm/admin/crm_resource.c @@ -1,1329 +1,1327 @@ /* * 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 #include #include #include #include #ifdef HAVE_GETOPT_H # include #endif void usage(const char *cmd, int exit_status); gboolean do_force = FALSE; gboolean BE_QUIET = FALSE; const char *attr_set_type = XML_TAG_ATTR_SETS; char *host_id = NULL; const char *rsc_id = NULL; const char *host_uname = NULL; const char *prop_name = NULL; const char *prop_value = NULL; const char *rsc_type = NULL; const char *prop_id = NULL; const char *prop_set = NULL; char *migrate_lifetime = NULL; char rsc_cmd = 'L'; char *our_pid = NULL; IPC_Channel *crmd_channel = NULL; char *xml_file = NULL; int cib_options = cib_sync_call; #define OPTARGS "V?LRQxDCPp:WMUr:H:v:t:p:g:d:i:s:G:S:fX:lmu:F" #define CMD_ERR(fmt, args...) do { \ crm_warn(fmt, ##args); \ fprintf(stderr, fmt, ##args); \ } while(0) static int do_find_resource(const char *rsc, pe_working_set_t *data_set) { int found = 0; resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); if(the_rsc == NULL) { return cib_NOTEXISTS; } slist_iter(node, node_t, the_rsc->running_on, lpc, crm_debug_3("resource %s is running on: %s", rsc, node->details->uname); if(BE_QUIET) { fprintf(stdout, "%s\n", node->details->uname); } else { fprintf(stdout, "resource %s is running on: %s\n", rsc, node->details->uname); } found++; ); if(BE_QUIET == FALSE && found == 0) { fprintf(stderr, "resource %s is NOT running\n", rsc); } return 0; } static void print_raw_rsc(resource_t *rsc, int level) { int lpc = 0; GListPtr children = NULL; for(; lpc < level; lpc++) { printf(" "); } printf(" * %s\n", rsc->id); children = rsc->fns->children(rsc); slist_iter(child, resource_t, children, lpc, print_raw_rsc(child, level+1); ); } static int do_find_resource_list(pe_working_set_t *data_set, gboolean raw) { int found = 0; slist_iter( rsc, resource_t, data_set->resources, lpc, if(raw) { found++; print_raw_rsc(rsc, 0); continue; } else if(is_set(rsc->flags, pe_rsc_orphan) && rsc->fns->active(rsc, TRUE) == FALSE) { continue; } rsc->fns->print( rsc, NULL, pe_print_printf|pe_print_rsconly, stdout); found++; ); if(found == 0) { printf("NO resources configured\n"); return cib_NOTEXISTS; } return 0; } static int dump_resource(const char *rsc, pe_working_set_t *data_set) { char *rsc_xml = NULL; resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); if(the_rsc == NULL) { return cib_NOTEXISTS; } the_rsc->fns->print(the_rsc, NULL, pe_print_printf, stdout); rsc_xml = dump_xml_formatted(the_rsc->xml); fprintf(stdout, "raw xml:\n%s", rsc_xml); crm_free(rsc_xml); return 0; } static int dump_resource_attr( const char *rsc, const char *attr, pe_working_set_t *data_set) { node_t *current = NULL; resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); const char *value = NULL; if(the_rsc == NULL) { return cib_NOTEXISTS; } if(g_list_length(the_rsc->running_on) == 1) { current = the_rsc->running_on->data; } else if(g_list_length(the_rsc->running_on) > 1) { CMD_ERR("%s is active on more than one node," " returning the default value for %s\n", the_rsc->id, crm_str(value)); } unpack_instance_attributes( the_rsc->xml, attr_set_type, current?current->details->attrs:NULL, the_rsc->parameters, NULL, data_set->now); if(the_rsc->parameters != NULL) { crm_debug("Looking up %s in %s", attr, the_rsc->id); value = g_hash_table_lookup(the_rsc->parameters, attr); } if(value != NULL) { fprintf(stdout, "%s\n", value); return 0; } return cib_NOTEXISTS; } static int set_resource_attr(const char *rsc_id, const char *attr_set, const char *attr_id, const char *attr_name, const char *attr_value, cib_t *cib, pe_working_set_t *data_set) { int rc = cib_ok; int matches = 0; char *local_attr_id = NULL; char *local_attr_set = NULL; crm_data_t *xml_top = NULL; crm_data_t *xml_obj = NULL; crm_data_t *nv_children = NULL; crm_data_t *set_children = NULL; resource_t *rsc = pe_find_resource(data_set->resources, rsc_id); if(rsc == NULL) { return cib_NOTEXISTS; } /* filter by set and type */ matches = find_xml_children( &set_children, rsc->xml, attr_set_type, XML_ATTR_ID, attr_set, FALSE); crm_log_xml_debug(set_children, "search by set:"); crm_debug("%d objects matching tag=%s id=%s", matches, attr_set_type, attr_set?attr_set:""); if(matches == 0) { /* nothing more to search */ crm_debug("No objects matching tag=%s id=%s", attr_set_type, attr_set?attr_set:""); } else if(attr_id == NULL) { matches = find_xml_children( &nv_children, set_children, XML_CIB_TAG_NVPAIR, XML_NVPAIR_ATTR_NAME, attr_name, FALSE); crm_log_xml_debug(nv_children, "search by name:"); } else { matches = find_xml_children( &nv_children, set_children, XML_CIB_TAG_NVPAIR, XML_ATTR_ID, attr_id, FALSE); crm_log_xml_debug(nv_children, "search by id:"); } if(matches > 1) { CMD_ERR("Multiple attributes match name=%s for the resource %s:\n", attr_name, rsc->id); if(set_children == NULL) { free_xml(set_children); set_children = NULL; find_xml_children( &set_children, rsc->xml, attr_set_type, NULL, NULL, FALSE); xml_child_iter( set_children, set, free_xml(nv_children); nv_children = NULL; find_xml_children( &nv_children, set, XML_CIB_TAG_NVPAIR, XML_NVPAIR_ATTR_NAME, attr_name, FALSE); xml_child_iter( nv_children, child, fprintf(stderr," Set: %s,\tValue: %s,\tID: %s\n", ID(set), crm_element_value(child, XML_NVPAIR_ATTR_VALUE), ID(child)); ); ); } else { xml_child_iter( nv_children, child, fprintf(stderr," ID: %s, Value: %s\n", ID(child), crm_element_value(child, XML_NVPAIR_ATTR_VALUE)); ); } if(BE_QUIET == FALSE) { CMD_ERR("\nThe following text can be suppressed with the -Q option:\n"); if(attr_set == NULL) { CMD_ERR(" * To choose an existing entry to change, please supply one of the set names above using the -s option.\n"); } else { CMD_ERR(" * To choose an existing entry to change, please supply one of the IDs above using the -i option.\n"); } CMD_ERR(" * To create a new value with a default ID, please supply a different set name using the -s option.\n"); CMD_ERR("You can also use --query-xml to display the complete resource definition.\n"); } return cib_unknown; } else if(matches == 0) { if(attr_set == NULL) { if(safe_str_eq(attr_set_type, XML_TAG_META_SETS)) { local_attr_set = crm_concat(rsc->id, "meta-options", '-'); } else { local_attr_set = crm_strdup(rsc->id); } attr_set = local_attr_set; } if(attr_id == NULL) { local_attr_id = crm_concat(attr_set, attr_name, '-'); attr_id = local_attr_id; } xml_top = create_xml_node(NULL, crm_element_name(rsc->xml)); crm_xml_add(xml_top, XML_ATTR_ID, rsc->id); xml_obj = create_xml_node(xml_top, attr_set_type); crm_xml_add(xml_obj, XML_ATTR_ID, attr_set); xml_obj = create_xml_node(xml_obj, XML_TAG_ATTRS); xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR); } else { if(attr_id == NULL) { /* extract it */ xml_child_iter(nv_children, child, attr_id = ID(child)); } xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR); xml_top = xml_obj; } crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value); crm_log_xml_debug(xml_top, "Update"); rc = cib->cmds->modify(cib, XML_CIB_TAG_RESOURCES, xml_top, NULL, cib_options); free_xml(xml_top); crm_free(local_attr_id); crm_free(local_attr_set); return rc; } static int delete_resource_attr( const char *rsc_id, const char *attr_set, const char *attr_id, const char *attr_name, cib_t *cib, pe_working_set_t *data_set) { crm_data_t *xml_obj = NULL; crm_data_t *xml_match = NULL; int rc = cib_ok; char *local_attr_id = NULL; resource_t *rsc = pe_find_resource(data_set->resources, rsc_id); if(rsc == NULL) { return cib_NOTEXISTS; } rc = find_attr_details( rsc->xml, NULL, attr_set, attr_id, attr_name, &xml_match, TRUE); if(rc == cib_NOTEXISTS) { return cib_ok; } if(rc != cib_ok) { return rc; } if(attr_id == NULL) { local_attr_id = crm_element_value_copy(xml_match, XML_ATTR_ID); attr_id = local_attr_id; } xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR); crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); crm_log_xml_debug(xml_obj, "Delete"); rc = cib->cmds->delete(cib, XML_CIB_TAG_RESOURCES, xml_obj, NULL, cib_options); free_xml(xml_obj); free_xml(xml_match); crm_free(local_attr_id); return rc; } static int dump_resource_prop( const char *rsc, const char *attr, pe_working_set_t *data_set) { const char *value = NULL; resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); if(the_rsc == NULL) { return cib_NOTEXISTS; } value = crm_element_value(the_rsc->xml, attr); if(value != NULL) { fprintf(stdout, "%s\n", value); return 0; } return cib_NOTEXISTS; } static void resource_ipc_connection_destroy(gpointer user_data) { crm_info("Connection to CRMd was terminated"); exit(1); } static gboolean crmd_msg_callback(IPC_Channel * server, void *private_data) { int lpc = 0; IPC_Message *msg = NULL; ha_msg_input_t *new_input = NULL; gboolean hack_return_good = TRUE; while (server->ch_status != IPC_DISCONNECT && server->ops->is_message_pending(server) == TRUE) { if(new_input != NULL) { delete_ha_msg_input(new_input); new_input = NULL; } if (server->ops->recv(server, &msg) != IPC_OK) { perror("Receive failure:"); return !hack_return_good; } if (msg == NULL) { crm_debug_4("No message this time"); continue; } lpc++; new_input = new_ipc_msg_input(msg); crm_log_message(LOG_MSG, new_input->msg); msg->msg_done(msg); if (validate_crm_message( new_input->msg, crm_system_name, our_pid, XML_ATTR_RESPONSE) == FALSE) { crm_info("Message was not a CRM response. Discarding."); } delete_ha_msg_input(new_input); new_input = NULL; } if (server->ch_status == IPC_DISCONNECT) { crm_debug_2("admin_msg_callback: received HUP"); return !hack_return_good; } return hack_return_good; } static int send_lrm_rsc_op(IPC_Channel *crmd_channel, const char *op, const char *host_uname, const char *rsc_id, gboolean only_failed, pe_working_set_t *data_set) { char *key = NULL; int rc = cib_send_failed; HA_Message *cmd = NULL; crm_data_t *xml_rsc = NULL; const char *value = NULL; HA_Message *params = NULL; crm_data_t *msg_data = NULL; resource_t *rsc = pe_find_resource(data_set->resources, rsc_id); if(rsc == NULL) { CMD_ERR("Resource %s not found\n", rsc_id); return cib_NOTEXISTS; } else if(rsc->variant != pe_native) { CMD_ERR("We can only process primitive resources, not %s\n", rsc_id); return cib_invalid_argument; } else if(host_uname == NULL) { CMD_ERR("Please supply a hostname with -H\n"); return cib_invalid_argument; } key = crm_concat("0:0:crm-resource", our_pid, '-'); msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key); 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_name); value = crm_element_value(rsc->xml, XML_ATTR_TYPE); crm_xml_add(xml_rsc, XML_ATTR_TYPE, value); if(value == NULL) { CMD_ERR("%s has no type! Aborting...\n", rsc_id); return cib_NOTEXISTS; } value = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, value); if(value == NULL) { CMD_ERR("%s has no class! Aborting...\n", rsc_id); return cib_NOTEXISTS; } value = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER, value); params = create_xml_node(msg_data, XML_TAG_ATTRS); crm_xml_add(params, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET); crm_xml_add(params, CRM_META"_"XML_LRM_ATTR_INTERVAL, "60000"); /* 1 minute */ cmd = create_request(op, msg_data, host_uname, CRM_SYSTEM_CRMD, crm_system_name, our_pid); /* crm_log_xml_warn(cmd, "send_lrm_rsc_op"); */ free_xml(msg_data); crm_free(key); if(send_ipc_message(crmd_channel, cmd)) { rc = 0; sleep(1); /* dont exit striaght away, give the crmd time * to process our request */ } else { CMD_ERR("Could not send %s op to the crmd", op); } crm_msg_del(cmd); return rc; } static int delete_lrm_rsc(IPC_Channel *crmd_channel, const char *host_uname, const char *rsc_id, pe_working_set_t *data_set) { return send_lrm_rsc_op(crmd_channel, CRM_OP_LRM_DELETE, host_uname, rsc_id, TRUE, data_set); } static int fail_lrm_rsc(IPC_Channel *crmd_channel, const char *host_uname, const char *rsc_id, pe_working_set_t *data_set) { crm_warn("Failing: %s", rsc_id); return send_lrm_rsc_op(crmd_channel, CRM_OP_LRM_FAIL, host_uname, rsc_id, FALSE, data_set); } static int refresh_lrm(IPC_Channel *crmd_channel, const char *host_uname) { HA_Message *cmd = NULL; int rc = cib_send_failed; cmd = create_request(CRM_OP_LRM_REFRESH, NULL, host_uname, CRM_SYSTEM_CRMD, crm_system_name, our_pid); if(send_ipc_message(crmd_channel, cmd)) { rc = 0; } crm_msg_del(cmd); return rc; } static int migrate_resource( const char *rsc_id, const char *existing_node, const char *preferred_node, cib_t * cib_conn) { char *later_s = NULL; enum cib_errors rc = cib_ok; char *id = NULL; crm_data_t *cib = NULL; crm_data_t *rule = NULL; crm_data_t *expr = NULL; crm_data_t *constraints = NULL; crm_data_t *fragment = NULL; crm_data_t *lifetime = NULL; crm_data_t *can_run = NULL; crm_data_t *dont_run = NULL; fragment = create_cib_fragment(NULL, NULL); cib = fragment; CRM_DEV_ASSERT(safe_str_eq(crm_element_name(cib), XML_TAG_CIB)); constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); id = crm_concat("cli-prefer", rsc_id, '-'); can_run = create_xml_node(NULL, XML_CONS_TAG_RSC_LOCATION); crm_xml_add(can_run, XML_ATTR_ID, id); crm_free(id); id = crm_concat("cli-standby", rsc_id, '-'); dont_run = create_xml_node(NULL, XML_CONS_TAG_RSC_LOCATION); crm_xml_add(dont_run, XML_ATTR_ID, id); crm_free(id); if(migrate_lifetime) { char *life = crm_strdup(migrate_lifetime); char *life_mutable = life; ha_time_t *now = NULL; ha_time_t *later = NULL; ha_time_t *duration = parse_time_duration(&life_mutable); if(duration == NULL) { CMD_ERR("Invalid duration specified: %s\n", migrate_lifetime); CMD_ERR("Please refer to" " http://en.wikipedia.org/wiki/ISO_8601#Duration" " for examples of valid durations\n"); crm_free(life); return cib_invalid_argument; } now = new_ha_date(TRUE); later = add_time(now, duration); log_date(LOG_INFO, "now ", now, ha_log_date|ha_log_time); log_date(LOG_INFO, "later ", later, ha_log_date|ha_log_time); log_date(LOG_INFO, "duration", duration, ha_log_date|ha_log_time|ha_log_local); later_s = date_to_string(later, ha_log_date|ha_log_time); printf("Migration will take effect until: %s\n", later_s); free_ha_date(duration); free_ha_date(later); free_ha_date(now); crm_free(life); } if(existing_node == NULL) { crm_log_xml_notice(can_run, "Deleting"); rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_CONSTRAINTS, dont_run, NULL, cib_options); if(rc == cib_NOTEXISTS) { rc = cib_ok; } else if(rc != cib_ok) { goto bail; } } else { if(BE_QUIET == FALSE) { fprintf(stderr, "WARNING: Creating rsc_location constraint '%s'" " with a score of -INFINITY for resource %s" " on %s.\n", ID(dont_run), rsc_id, existing_node); CMD_ERR("\tThis will prevent %s from running" " on %s until the constraint is removed using" " the 'crm_resource -U' command or manually" " with cibadmin\n", rsc_id, existing_node); CMD_ERR("\tThis will be the case even if %s is" " the last node in the cluster\n", existing_node); CMD_ERR("\tThis messgae can be disabled with -Q\n"); } crm_xml_add(dont_run, "rsc", rsc_id); if(later_s) { lifetime = create_xml_node(dont_run, "lifetime"); rule = create_xml_node(lifetime, XML_TAG_RULE); id = crm_concat("cli-standby-lifetime", rsc_id, '-'); crm_xml_add(rule, XML_ATTR_ID, id); crm_free(id); expr = create_xml_node(rule, "date_expression"); id = crm_concat("cli-standby-lifetime-end",rsc_id,'-'); crm_xml_add(expr, XML_ATTR_ID, id); crm_free(id); crm_xml_add(expr, "operation", "lt"); crm_xml_add(expr, "end", later_s); } rule = create_xml_node(dont_run, XML_TAG_RULE); expr = create_xml_node(rule, XML_TAG_EXPRESSION); id = crm_concat("cli-standby-rule", rsc_id, '-'); crm_xml_add(rule, XML_ATTR_ID, id); crm_free(id); crm_xml_add(rule, XML_RULE_ATTR_SCORE, MINUS_INFINITY_S); id = crm_concat("cli-standby-expr", rsc_id, '-'); crm_xml_add(expr, XML_ATTR_ID, id); crm_free(id); crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, "#uname"); crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq"); crm_xml_add(expr, XML_EXPR_ATTR_VALUE, existing_node); crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string"); add_node_copy(constraints, dont_run); } if(preferred_node == NULL) { crm_log_xml_notice(can_run, "Deleting"); rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_CONSTRAINTS, can_run, NULL, cib_options); if(rc == cib_NOTEXISTS) { rc = cib_ok; } else if(rc != cib_ok) { goto bail; } } else { crm_xml_add(can_run, "rsc", rsc_id); if(later_s) { lifetime = create_xml_node(can_run, "lifetime"); rule = create_xml_node(lifetime, XML_TAG_RULE); id = crm_concat("cli-prefer-lifetime", rsc_id, '-'); crm_xml_add(rule, XML_ATTR_ID, id); crm_free(id); expr = create_xml_node(rule, "date_expression"); id = crm_concat("cli-prefer-lifetime-end", rsc_id, '-'); crm_xml_add(expr, XML_ATTR_ID, id); crm_free(id); crm_xml_add(expr, "operation", "lt"); crm_xml_add(expr, "end", later_s); } rule = create_xml_node(can_run, XML_TAG_RULE); expr = create_xml_node(rule, XML_TAG_EXPRESSION); id = crm_concat("cli-prefer-rule", rsc_id, '-'); crm_xml_add(rule, XML_ATTR_ID, id); crm_free(id); crm_xml_add(rule, XML_RULE_ATTR_SCORE, INFINITY_S); id = crm_concat("cli-prefer-expr", rsc_id, '-'); crm_xml_add(expr, XML_ATTR_ID, id); crm_free(id); crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, "#uname"); crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq"); crm_xml_add(expr, XML_EXPR_ATTR_VALUE, preferred_node); crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string"); add_node_copy(constraints, can_run); } if(preferred_node != NULL || existing_node != NULL) { crm_log_xml_notice(fragment, "CLI Update"); rc = cib_conn->cmds->update(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, NULL, cib_options); } bail: free_xml(fragment); free_xml(dont_run); free_xml(can_run); crm_free(later_s); return rc; } int main(int argc, char **argv) { pe_working_set_t data_set; crm_data_t *cib_xml_copy = NULL; cib_t * cib_conn = NULL; enum cib_errors rc = cib_ok; int argerr = 0; int flag; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"quiet", 0, 0, 'Q'}, {"list", 0, 0, 'L'}, {"list-raw", 0, 0, 'l'}, {"refresh", 0, 0, 'R'}, {"reprobe", 0, 0, 'P'}, {"query-xml", 0, 0, 'x'}, {"delete", 0, 0, 'D'}, {"cleanup", 0, 0, 'C'}, {"locate", 0, 0, 'W'}, {"migrate", 0, 0, 'M'}, {"un-migrate", 0, 0, 'U'}, {"resource", 1, 0, 'r'}, {"host-uname", 1, 0, 'H'}, {"lifetime", 1, 0, 'u'}, {"fail", 0, 0, 'F'}, {"force", 0, 0, 'f'}, {"meta", 0, 0, 'm'}, {"set-parameter", 1, 0, 'p'}, {"get-parameter", 1, 0, 'g'}, {"delete-parameter",1, 0, 'd'}, {"property-value", 1, 0, 'v'}, {"get-property", 1, 0, 'G'}, {"set-property", 1, 0, 'S'}, {"resource-type", 1, 0, 't'}, {"xml-file", 0, 0, 'X'}, {0, 0, 0, 0} }; #endif crm_log_init(basename(argv[0]), LOG_ERR, FALSE, FALSE, argc, argv); if(argc < 2) { usage(crm_system_name, 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 if (flag == -1) break; switch(flag) { case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'X': xml_file = crm_strdup(optarg); break; case 'Q': BE_QUIET = TRUE; break; case 'm': attr_set_type = XML_TAG_META_SETS; break; case 'L': case 'l': case 'R': case 'x': case 'D': case 'F': case 'C': case 'P': case 'W': case 'M': case 'U': rsc_cmd = flag; break; case 'u': migrate_lifetime = crm_strdup(optarg); break; case 'p': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'g': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'd': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'S': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'G': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'f': do_force = TRUE; break; case 'i': crm_debug_2("Option %c => %s", flag, optarg); prop_id = optarg; break; case 's': crm_debug_2("Option %c => %s", flag, optarg); prop_set = optarg; break; case 'r': crm_debug_2("Option %c => %s", flag, optarg); rsc_id = optarg; break; case 'v': crm_debug_2("Option %c => %s", flag, optarg); prop_value = optarg; break; case 't': crm_debug_2("Option %c => %s", flag, optarg); rsc_type = optarg; break; case 'H': crm_debug_2("Option %c => %s", flag, optarg); host_uname = optarg; break; default: CMD_ERR("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc) { CMD_ERR("non-option ARGV-elements: "); while (optind < argc) { CMD_ERR("%s ", argv[optind++]); } CMD_ERR("\n"); } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } crm_malloc0(our_pid, 11); if(our_pid != NULL) { snprintf(our_pid, 10, "%d", getpid()); our_pid[10] = '\0'; } if(do_force) { crm_debug("Forcing..."); cib_options |= cib_scope_local|cib_quorum_override; } if(rsc_cmd == 'L' || rsc_cmd == 'W' || rsc_cmd == 'D' || rsc_cmd == 'x' || rsc_cmd == 'M' || rsc_cmd == 'U' || rsc_cmd == 'C' || rsc_cmd == 'F' || rsc_cmd == 'p' || rsc_cmd == 'd' || rsc_cmd == 'g' || rsc_cmd == 'G' || rsc_cmd == 'S' || rsc_cmd == 'l') { resource_t *rsc = NULL; if(xml_file != NULL) { FILE *xml_strm = fopen(xml_file, "r"); if(strstr(xml_file, ".bz2") != NULL) { cib_xml_copy = file2xml(xml_strm, TRUE); } else { cib_xml_copy = file2xml(xml_strm, FALSE); } if(xml_strm != NULL) { fclose(xml_strm); } } else { cib_conn = cib_new(); rc = cib_conn->cmds->signon( cib_conn, crm_system_name, cib_command_synchronous); if(rc != cib_ok) { CMD_ERR("Error signing on to the CIB service: %s\n", cib_error2string(rc)); return rc; } cib_xml_copy = get_cib_copy(cib_conn); } set_working_set_defaults(&data_set); data_set.input = cib_xml_copy; data_set.now = new_ha_date(TRUE); cluster_status(&data_set); rsc = pe_find_resource(data_set.resources, rsc_id); if(rsc != NULL) { rsc_id = rsc->id; } else { rc = cib_NOTEXISTS; } } if(rsc_cmd == 'R' || rsc_cmd == 'C' || rsc_cmd == 'F' || rsc_cmd == 'P') { GCHSource *src = NULL; src = init_client_ipc_comms(CRM_SYSTEM_CRMD, crmd_msg_callback, NULL, &crmd_channel); if(src == NULL) { CMD_ERR("Error signing on to the CRMd service\n"); return 1; } send_hello_message( crmd_channel, our_pid, crm_system_name, "0", "1"); set_IPC_Channel_dnotify(src, resource_ipc_connection_destroy); } crm_warn("here i am - 3"); if(rsc_cmd == 'L') { rc = cib_ok; do_find_resource_list(&data_set, FALSE); } else if(rsc_cmd == 'l') { rc = cib_ok; do_find_resource_list(&data_set, TRUE); } else if(rsc_cmd == 'C') { rc = delete_lrm_rsc(crmd_channel, host_uname, rsc_id, &data_set); } else if(rsc_cmd == 'F') { rc = fail_lrm_rsc(crmd_channel, host_uname, rsc_id, &data_set); } else if(rc == cib_NOTEXISTS) { CMD_ERR("Resource %s not found: %s\n", crm_str(rsc_id), cib_error2string(rc)); } else if(rsc_cmd == 'W') { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } rc = do_find_resource(rsc_id, &data_set); } else if(rsc_cmd == 'x') { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } rc = dump_resource(rsc_id, &data_set); } else if(rsc_cmd == 'U') { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } rc = migrate_resource(rsc_id, NULL, NULL, cib_conn); } else if(rsc_cmd == 'M') { node_t *dest = NULL; node_t *current = NULL; const char *current_uname = NULL; resource_t *rsc = pe_find_resource(data_set.resources, rsc_id); if(rsc != NULL && rsc->running_on != NULL) { current = rsc->running_on->data; if(current != NULL) { current_uname = current->details->uname; } } if(host_uname != NULL) { dest = pe_find_node(data_set.nodes, host_uname); } if(rsc == NULL) { CMD_ERR("Resource %s not migrated:" " not found\n", rsc_id); } else if(rsc->variant == pe_native && g_list_length(rsc->running_on) > 1) { CMD_ERR("Resource %s not migrated:" " active on multiple nodes\n", rsc_id); } else if(host_uname != NULL && dest == NULL) { CMD_ERR("Error performing operation: " "%s is not a known node\n", host_uname); } else if(host_uname != NULL && safe_str_eq(current_uname, host_uname)) { CMD_ERR("Error performing operation: " "%s is already active on %s\n", rsc_id, host_uname); } else if(current_uname != NULL && (do_force || host_uname == NULL)) { rc = migrate_resource(rsc_id, current_uname, host_uname, cib_conn); } else if(host_uname != NULL) { rc = migrate_resource( rsc_id, NULL, host_uname, cib_conn); } else { CMD_ERR("Resource %s not migrated: " "not-active and no prefered location" " specified.\n", rsc_id); } } else if(rsc_cmd == 'G') { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } rc = dump_resource_prop(rsc_id, prop_name, &data_set); } else if(rsc_cmd == 'S') { crm_data_t *msg_data = NULL; if(prop_value == NULL || strlen(prop_value) == 0) { CMD_ERR("You need to supply a value with the -v option\n"); return CIBRES_MISSING_FIELD; } else if(cib_conn == NULL) { return cib_connection; } if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } CRM_DEV_ASSERT(rsc_type != NULL); CRM_DEV_ASSERT(prop_name != NULL); CRM_DEV_ASSERT(prop_value != NULL); msg_data = create_xml_node(NULL, rsc_type); crm_xml_add(msg_data, XML_ATTR_ID, rsc_id); crm_xml_add(msg_data, prop_name, prop_value); rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_RESOURCES, msg_data, NULL, cib_options); free_xml(msg_data); } else if(rsc_cmd == 'g') { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } rc = dump_resource_attr(rsc_id, prop_name, &data_set); } else if(rsc_cmd == 'p') { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } if(prop_value == NULL || strlen(prop_value) == 0) { CMD_ERR("You need to supply a value with the -v option\n"); return CIBRES_MISSING_FIELD; } rc = set_resource_attr(rsc_id, prop_set, prop_id, prop_name, prop_value, cib_conn, &data_set); } else if(rsc_cmd == 'd') { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } rc = delete_resource_attr(rsc_id, prop_id, prop_set, prop_name, cib_conn, &data_set); } else if(rsc_cmd == 'P') { HA_Message *cmd = NULL; cmd = create_request(CRM_OP_REPROBE, NULL, host_uname, CRM_SYSTEM_CRMD, crm_system_name, our_pid); send_ipc_message(crmd_channel, cmd); crm_msg_del(cmd); } else if(rsc_cmd == 'R') { refresh_lrm(crmd_channel, host_uname); } else if(rsc_cmd == 'D') { crm_data_t *msg_data = NULL; if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } if(rsc_type == NULL) { CMD_ERR("You need to specify a resource type with -t"); return cib_NOTEXISTS; } else if(cib_conn == NULL) { return cib_connection; } msg_data = create_xml_node(NULL, rsc_type); crm_xml_add(msg_data, XML_ATTR_ID, rsc_id); rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_RESOURCES, msg_data, NULL, cib_options); free_xml(msg_data); } else { CMD_ERR("Unknown command: %c\n", rsc_cmd); } if(cib_conn != NULL) { cleanup_calculations(&data_set); cib_conn->cmds->signoff(cib_conn); } if(rc == cib_no_quorum) { CMD_ERR("Error performing operation: %s\n", cib_error2string(rc)); CMD_ERR("Try using -f\n"); } else if(rc != cib_ok) { CMD_ERR("Error performing operation: %s\n", cib_error2string(rc)); } return rc; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-?VS] -(L|Q|W|D|C|P|p) [options]\n", cmd); fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?'); fprintf(stream, "\t--%s (-%c)\t: " "turn on debug info. additional instances increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\t: Print only the value on stdout (for use with -W)\n", "quiet", 'Q'); fprintf(stream, "\nCommands\n"); fprintf(stream, "\t--%s (-%c)\t: List all resources\n", "list", 'L'); fprintf(stream, "\t--%s (-%c)\t: Query a resource\n" "\t\t\t Requires: -r\n", "query-xml", 'x'); fprintf(stream, "\t--%s (-%c)\t: Locate a resource\n" "\t\t\t Requires: -r\n", "locate", 'W'); fprintf(stream, "\t--%s (-%c)\t: Migrate a resource from it current" " location. Use -H to specify a destination\n" "\t\tIf -H is not specified, we will force the resource to move by" " creating a rule for the current location and a score of -INFINITY\n" "\t\tNOTE: This will prevent the resource from running on this" " node until the constraint is removed with -U\n" "\t\t\t Requires: -r, Optional: -H, -f, --lifetime\n", "migrate", 'M'); fprintf(stream, "\t--%s (-%c)\t: Remove all constraints created by -M\n" "\t\t\t Requires: -r\n", "un-migrate", 'U'); fprintf(stream, "\t--%s (-%c)\t: Delete a resource from the CIB\n" "\t\t\t Requires: -r, -t\n", "delete", 'D'); fprintf(stream, "\t--%s (-%c)\t: Delete a resource from the LRM\n" "\t\t\t Requires: -r. Optional: -H\n", "cleanup", 'C'); fprintf(stream, "\t--%s (-%c)\t: Recheck for resources started outside of the CRM\n" "\t\t\t Optional: -H\n", "reprobe", 'P'); fprintf(stream, "\t--%s (-%c)\t: Refresh the CIB from the LRM\n" "\t\t\t Optional: -H\n", "refresh", 'R'); fprintf(stream, "\t--%s (-%c) \t: " "Set the named parameter for a resource\n" "\t\t\t Requires: -r, -v. Optional: -i, -s, --meta\n", "set-parameter", 'p'); fprintf(stream, "\t--%s (-%c) \t: " "Get the named parameter for a resource\n" "\t\t\t Requires: -r. Optional: -i, -s, --meta\n", "get-parameter", 'g'); fprintf(stream, "\t--%s (-%c) : " "Delete the named parameter for a resource\n" "\t\t\t Requires: -r. Optional: -i, --meta\n", "delete-parameter", 'd'); fprintf(stream, "\nOptions\n"); fprintf(stream, "\t--%s (-%c) \t: Resource ID\n", "resource", 'r'); fprintf(stream, "\t--%s (-%c) \t: " "Resource type (primitive, clone, group, ...)\n", "resource-type", 't'); fprintf(stream, "\t--%s (-%c) \t: " "Property value\n", "property-value", 'v'); fprintf(stream, "\t--%s (-%c) \t: " "Host name\n", "host-uname", 'H'); fprintf(stream, "\t--%s\t: Modify a resource's configuration option rather than one which is passed to the resource agent script." "\n\t\tFor use with -p, -g, -d\n", "meta"); fprintf(stream, "\t--%s (-%c) \t: " "Lifespan of migration constraints\n", "lifetime", 'u'); fprintf(stream, "\t--%s (-%c)\t: " "Force the resource to move by creating a rule for the" " current location and a score of -INFINITY\n" "\t\tThis should be used if the resource's stickiness and" " constraint scores total more than INFINITY (Currently 100,000)\n" "\t\tNOTE: This will prevent the resource from running on this" " node until the constraint is removed with -U or the --lifetime duration expires\n", "force", 'f'); fprintf(stream, "\t-%c \t: (Advanced Use Only) ID of the instance_attributes object to change\n", 's'); fprintf(stream, "\t-%c \t: (Advanced Use Only) ID of the nvpair object to change/delete\n", 'i'); fflush(stream); exit(exit_status); } diff --git a/crm/admin/crm_uuid.c b/crm/admin/crm_uuid.c index 2b9e4cd4ca..14a29d35cb 100644 --- a/crm/admin/crm_uuid.c +++ b/crm/admin/crm_uuid.c @@ -1,184 +1,185 @@ /* * 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 #ifdef HAVE_STRING_H #include #endif #include #include #include -#include +#include #include +#include #include #ifdef HAVE_GETOPT_H # include #endif #define UUID_LEN 16 #define UUID_FILE HA_VARLIBDIR"/"PACKAGE"/hb_uuid" #define OPTARGS "rw:" int read_local_hb_uuid(void); int write_local_hb_uuid(const char *buffer); static void usage(void) { fprintf(stderr, "crm_uuid [-r|-w new_ascii_value]\n"); exit(1); } int main(int argc, char **argv) { int flag; int rc = 0; cl_log_enable_stderr(TRUE); if(argc == 1) { /* no arguments specified, default to read */ rc = read_local_hb_uuid(); return rc; } cl_log_args(argc, argv); while (1) { flag = getopt(argc, argv, OPTARGS); if (flag == -1) { break; } switch(flag) { case 'r': rc = read_local_hb_uuid(); break; case 'w': rc = write_local_hb_uuid(optarg); break; default: usage(); break; } } return rc; } int read_local_hb_uuid(void) { int rc = 0; cl_uuid_t uuid; char *buffer = NULL; long start = 0, read_len = 0; FILE *input = fopen(UUID_FILE, "r"); if(input == NULL) { cl_perror("Could not open UUID file %s\n", UUID_FILE); return 1; } /* see how big the file is */ start = ftell(input); fseek(input, 0L, SEEK_END); if(UUID_LEN != ftell(input)) { fprintf(stderr, "%s must contain exactly %d bytes\n", UUID_FILE, UUID_LEN); abort(); } fseek(input, 0L, start); if(start != ftell(input)) { fprintf(stderr, "fseek not behaving: %ld vs. %ld\n", start, ftell(input)); rc = 2; goto bail; } /* fprintf(stderr, "Reading %d bytes from: %s\n", UUID_LEN, UUID_FILE); */ buffer = cl_malloc(50); read_len = fread(uuid.uuid, 1, UUID_LEN, input); if(read_len != UUID_LEN) { fprintf(stderr, "Expected and read bytes differ: %d vs. %ld\n", UUID_LEN, read_len); rc = 3; goto bail; } else if(buffer != NULL) { cl_uuid_unparse(&uuid, buffer); fprintf(stdout, "%s\n", buffer); } else { fprintf(stderr, "No buffer to unparse\n"); rc = 4; } bail: cl_free(buffer); fclose(input); return rc; } int write_local_hb_uuid(const char *new_value) { int fd; int rc = 0; cl_uuid_t uuid; char *buffer = strdup(new_value); rc = cl_uuid_parse(buffer, &uuid); if(rc != 0) { fprintf(stderr, "Invalid ASCII UUID supplied: [%s]\n", new_value); fprintf(stderr, "ASCII UUIDs must be of the form" " XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" " and contain only letters and digits\n"); return 5; } if ((fd = open(UUID_FILE, O_WRONLY|O_SYNC|O_CREAT, 0644)) < 0) { cl_perror("Could not open %s", UUID_FILE); return 6; } if (write(fd, uuid.uuid, UUID_LEN) != UUID_LEN) { cl_perror("Could not write UUID to %s", UUID_FILE); rc=7; } if (close(fd) < 0) { cl_perror("Could not close %s", UUID_FILE); rc=8; } return rc; } diff --git a/crm/admin/crmadmin.c b/crm/admin/crmadmin.c index 6d39fef185..05dee5a362 100644 --- a/crm/admin/crmadmin.c +++ b/crm/admin/crmadmin.c @@ -1,719 +1,717 @@ /* * 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 #include #include #include #ifdef HAVE_GETOPT_H # include #endif int message_timer_id = -1; int message_timeout_ms = 30*1000; GMainLoop *mainloop = NULL; IPC_Channel *crmd_channel = NULL; char *admin_uuid = NULL; void usage(const char *cmd, int exit_status); gboolean do_init(void); int do_work(void); void crmd_ipc_connection_destroy(gpointer user_data); gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data); char *pluralSection(const char *a_section); crm_data_t *handleCibMod(void); int do_find_node_list(crm_data_t *xml_node); gboolean admin_message_timeout(gpointer data); gboolean is_node_online(crm_data_t *node_state); enum debug { debug_none, debug_dec, debug_inc }; gboolean BE_VERBOSE = FALSE; int expected_responses = 1; gboolean BASH_EXPORT = FALSE; gboolean DO_HEALTH = FALSE; gboolean DO_RESET = FALSE; gboolean DO_RESOURCE = FALSE; gboolean DO_ELECT_DC = FALSE; gboolean DO_WHOIS_DC = FALSE; gboolean DO_NODE_LIST = FALSE; gboolean BE_SILENT = FALSE; gboolean DO_RESOURCE_LIST = FALSE; enum debug DO_DEBUG = debug_none; const char *crmd_operation = NULL; crm_data_t *msg_options = NULL; const char *standby_on_off = "on"; const char *admin_verbose = XML_BOOLEAN_FALSE; char *id = NULL; char *this_msg_reference = NULL; char *disconnect = NULL; char *dest_node = NULL; char *rsc_name = NULL; char *crm_option = NULL; int operation_status = 0; const char *sys_to = NULL; #define OPTARGS "V?K:S:HE:Dd:i:RNqt:Bv" int main(int argc, char **argv) { int argerr = 0; int flag; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"quiet", 0, 0, 'q'}, {"reference", 1, 0, 0}, {XML_ATTR_TIMEOUT, 1, 0, 't'}, {"bash-export", 0, 0, 'B'}, /* daemon options */ {"kill", 1, 0, 'K'}, /* stop a node */ {"die", 0, 0, 0}, /* kill a node, no respawn */ {"debug_inc", 1, 0, 'i'}, {"debug_dec", 1, 0, 'd'}, {"status", 1, 0, 'S'}, {"standby", 1, 0, 's'}, {"active", 1, 0, 'a'}, {"health", 0, 0, 'H'}, {"election", 0, 0, 'E'}, {"dc_lookup", 0, 0, 'D'}, {"nodes", 0, 0, 'N'}, {"option", 1, 0, 'o'}, {"version", 0, 0, 'v'}, {0, 0, 0, 0} }; #endif crm_log_init(basename(argv[0]), LOG_ERR, FALSE, TRUE, argc, argv); if(argc < 2) { usage(crm_system_name, 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 if (flag == -1) break; switch(flag) { #ifdef HAVE_GETOPT_H case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); if (strcasecmp("reference", long_options[option_index].name) == 0) { this_msg_reference = crm_strdup(optarg); } else if (strcasecmp("die", long_options[option_index].name) == 0) { DO_RESET = TRUE; crmd_operation = CRM_OP_DIE; } else { printf( "?? Long option (--%s) is not yet properly supported ??\n", long_options[option_index].name); ++argerr; } break; #endif /* a sample test for multiple instance if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); */ case 'v': fprintf(stdout, "HA Version %s, CRM Version %s (CIB feature set %s) %s\n", VERSION, CRM_FEATURE_SET, CIB_FEATURE_SET, HA_HG_VERSION); exit(0); break; case 'V': BE_VERBOSE = TRUE; admin_verbose = XML_BOOLEAN_TRUE; cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 't': message_timeout_ms = atoi(optarg); if(message_timeout_ms < 1) { message_timeout_ms = 30*1000; } break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'D': DO_WHOIS_DC = TRUE; break; case 'B': BASH_EXPORT = TRUE; break; case 'K': DO_RESET = TRUE; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); crmd_operation = CRM_OP_LOCAL_SHUTDOWN; break; case 'q': BE_SILENT = TRUE; break; case 'i': DO_DEBUG = debug_inc; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'd': DO_DEBUG = debug_dec; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'S': DO_HEALTH = TRUE; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'E': DO_ELECT_DC = TRUE; break; case 'N': DO_NODE_LIST = TRUE; break; case 'H': DO_HEALTH = TRUE; 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"); } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } if (do_init()) { int res = 0; res = do_work(); if (res > 0) { /* wait for the reply by creating a mainloop and running it until * the callbacks are invoked... */ mainloop = g_main_new(FALSE); expected_responses++; crm_debug_2("Waiting for %d replies from the local CRM", expected_responses); message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); g_main_run(mainloop); return_to_orig_privs(); } else if(res < 0) { crm_err("No message to send"); operation_status = -1; } } else { crm_warn("Init failed, could not perform requested operations"); operation_status = -2; } crm_debug_2("%s exiting normally", crm_system_name); return operation_status; } int do_work(void) { int ret = 1; /* construct the request */ crm_data_t *msg_data = NULL; gboolean all_is_good = TRUE; msg_options = create_xml_node(NULL, XML_TAG_OPTIONS); crm_xml_add(msg_options, XML_ATTR_VERBOSE, admin_verbose); crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); if (DO_HEALTH == TRUE) { crm_debug_2("Querying the system"); sys_to = CRM_SYSTEM_DC; if (dest_node != NULL) { sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_PING; if (BE_VERBOSE) { expected_responses = 1; } crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); } else { crm_info("Cluster-wide health not available yet"); all_is_good = FALSE; } } else if(DO_ELECT_DC) { /* tell the local node to initiate an election */ sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_VOTE; crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); dest_node = NULL; ret = 0; /* no return message */ } else if(DO_WHOIS_DC) { sys_to = CRM_SYSTEM_DC; crmd_operation = CRM_OP_PING; crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); dest_node = NULL; } else if(DO_NODE_LIST) { cib_t * the_cib = cib_new(); crm_data_t *output = NULL; enum cib_errors rc = the_cib->cmds->signon( the_cib, crm_system_name, cib_command_synchronous); if(rc != cib_ok) { return -1; } output = get_cib_copy(the_cib); do_find_node_list(output); free_xml(output); the_cib->cmds->signoff(the_cib); exit(rc); } else if(DO_RESET) { /* tell dest_node to initiate the shutdown proceedure * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); ret = 0; /* no return message */ } else if(DO_DEBUG == debug_inc) { /* tell dest_node to increase its debug level * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_DEBUG_UP; ret = 0; /* no return message */ } else if(DO_DEBUG == debug_dec) { /* tell dest_node to increase its debug level * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_DEBUG_DOWN; ret = 0; /* no return message */ } else { crm_err("Unknown options"); all_is_good = FALSE; } if(all_is_good == FALSE) { crm_err("Creation of request failed. No message to send"); return -1; } /* send it */ if (crmd_channel == NULL) { crm_err("The IPC connection is not valid, cannot send anything"); return -1; } if(sys_to == NULL) { if (dest_node != NULL) { sys_to = CRM_SYSTEM_CRMD; } else { sys_to = CRM_SYSTEM_DC; } } { HA_Message *cmd = create_request( crmd_operation, msg_data, dest_node, sys_to, crm_system_name, admin_uuid); if(this_msg_reference != NULL) { ha_msg_mod(cmd, XML_ATTR_REFERENCE, this_msg_reference); } send_ipc_message(crmd_channel, cmd); crm_msg_del(cmd); } return ret; } void crmd_ipc_connection_destroy(gpointer user_data) { crm_debug("Connection to CRMd was terminated"); } gboolean do_init(void) { GCHSource *src = NULL; crm_malloc0(admin_uuid, 11); if(admin_uuid != NULL) { snprintf(admin_uuid, 10, "%d", getpid()); admin_uuid[10] = '\0'; } src = init_client_ipc_comms( CRM_SYSTEM_CRMD, admin_msg_callback, NULL, &crmd_channel); if(DO_RESOURCE || DO_RESOURCE_LIST || DO_NODE_LIST) { return TRUE; } else if(crmd_channel != NULL) { send_hello_message( crmd_channel, admin_uuid, crm_system_name,"0", "1"); set_IPC_Channel_dnotify(src, crmd_ipc_connection_destroy); return TRUE; } return FALSE; } gboolean admin_msg_callback(IPC_Channel * server, void *private_data) { int rc = 0; int lpc = 0; IPC_Message *msg = NULL; ha_msg_input_t *new_input = NULL; gboolean hack_return_good = TRUE; static int received_responses = 0; char *filename = NULL; int filename_len = 0; const char *result = NULL; Gmain_timeout_remove(message_timer_id); while (server->ch_status != IPC_DISCONNECT && server->ops->is_message_pending(server) == TRUE) { if(new_input != NULL) { delete_ha_msg_input(new_input); new_input = NULL; } rc = server->ops->recv(server, &msg); if (rc != IPC_OK) { cl_perror("Receive failure (%d)", rc); return !hack_return_good; } if (msg == NULL) { crm_debug_4("No message this time"); continue; } lpc++; received_responses++; new_input = new_ipc_msg_input(msg); crm_log_message(LOG_MSG, new_input->msg); msg->msg_done(msg); if (new_input->xml == NULL) { crm_info("XML in IPC message was not valid... " "discarding."); goto cleanup; } else if (validate_crm_message( new_input->msg, crm_system_name, admin_uuid, XML_ATTR_RESPONSE) == FALSE) { crm_debug_2("Message was not a CRM response. Discarding."); goto cleanup; } result = cl_get_string(new_input->msg, XML_ATTR_RESULT); if(result == NULL || strcasecmp(result, "ok") == 0) { result = "pass"; } else { result = "fail"; } if(DO_HEALTH) { const char *state = crm_element_value( new_input->xml, "crmd_state"); printf("Status of %s@%s: %s (%s)\n", crm_element_value(new_input->xml,XML_PING_ATTR_SYSFROM), cl_get_string(new_input->msg, F_CRM_HOST_FROM), state, crm_element_value(new_input->xml,XML_PING_ATTR_STATUS)); if(BE_SILENT && state != NULL) { fprintf(stderr, "%s\n", state); } } else if(DO_WHOIS_DC) { const char *dc = cl_get_string( new_input->msg, F_CRM_HOST_FROM); printf("Designated Controller is: %s\n", dc); if(BE_SILENT && dc != NULL) { fprintf(stderr, "%s\n", dc); } } if (this_msg_reference != NULL) { /* in testing mode... */ /* 31 = "test-_.xml" + an_int_as_string + '\0' */ filename_len = 31 + strlen(this_msg_reference); crm_malloc0(filename, filename_len); if(filename != NULL) { snprintf(filename, filename_len, "%s-%s_%d.xml", result, this_msg_reference, received_responses); filename[filename_len - 1] = '\0'; if (0 > write_xml_file( new_input->xml, filename, FALSE)) { crm_crit("Could not save response to" " %s", filename); } } } cleanup: delete_ha_msg_input(new_input); new_input = NULL; } if (server->ch_status == IPC_DISCONNECT) { crm_debug_2("admin_msg_callback: received HUP"); return !hack_return_good; } if (received_responses >= expected_responses) { crm_debug_2( "Recieved expected number (%d) of messages from Heartbeat." " Exiting normally.", expected_responses); g_main_quit(mainloop); return !hack_return_good; } message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); return hack_return_good; } gboolean admin_message_timeout(gpointer data) { fprintf(stderr, "No messages received in %d seconds.. aborting\n", (int)message_timeout_ms/1000); crm_err("No messages received in %d seconds", (int)message_timeout_ms/1000); operation_status = -3; g_main_quit(mainloop); return FALSE; } gboolean is_node_online(crm_data_t *node_state) { const char *uname = crm_element_value(node_state,XML_ATTR_UNAME); const char *join_state = crm_element_value(node_state,XML_CIB_ATTR_JOINSTATE); const char *exp_state = crm_element_value(node_state,XML_CIB_ATTR_EXPSTATE); const char *crm_state = crm_element_value(node_state,XML_CIB_ATTR_CRMDSTATE); const char *ha_state = crm_element_value(node_state,XML_CIB_ATTR_HASTATE); const char *ccm_state = crm_element_value(node_state,XML_CIB_ATTR_INCCM); if(safe_str_neq(join_state, CRMD_JOINSTATE_DOWN) - && (ha_state == NULL || safe_str_eq(ha_state, ACTIVESTATUS)) + && (ha_state == NULL || safe_str_eq(ha_state, "active")) && crm_is_true(ccm_state) - && safe_str_eq(crm_state, ONLINESTATUS)) { + && safe_str_eq(crm_state, "online")) { crm_debug_3("Node %s is online", uname); return TRUE; } crm_debug_3("Node %s: ha=%s ccm=%s join=%s exp=%s crm=%s", uname, crm_str(ha_state), crm_str(ccm_state), crm_str(join_state), crm_str(exp_state), crm_str(crm_state)); crm_debug_3("Node %s is offline", uname); return FALSE; } int do_find_node_list(crm_data_t *xml_node) { int found = 0; crm_data_t *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node); xml_child_iter_filter( nodes, node, XML_CIB_TAG_NODE, if(BASH_EXPORT) { printf("export %s=%s\n", crm_element_value(node, XML_ATTR_UNAME), crm_element_value(node, XML_ATTR_ID)); } else { printf("%s node: %s (%s)\n", crm_element_value(node, XML_ATTR_TYPE), crm_element_value(node, XML_ATTR_UNAME), crm_element_value(node, XML_ATTR_ID)); } found++; ); if(found == 0) { printf("NO nodes configured\n"); } return found; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-?Vs] [command] [command args]\n", cmd); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?'); fprintf(stream, "\t--%s (-%c)\t: version details\n", "version", 'v'); fprintf(stream, "\t--%s (-%c)\t: " "turn on debug info. additional instances increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\t: be very *very* quiet\n", "quiet", 'q'); fprintf(stream, "\t--%s (-%c)\t: Only applies to -N.\n" "\t\tCreate Bash export entries of the form \"export uname=uuid\"\n", "bash-export", 'B'); fprintf(stream, "\nCommands\n"); fprintf(stream, "\t--%s (-%c) \t: " "increment the CRMd debug level on \n", CRM_OP_DEBUG_UP,'i'); fprintf(stream, "\t--%s (-%c) \t: " "decrement the CRMd debug level on \n", CRM_OP_DEBUG_DOWN,'d'); fprintf(stream, "\t--%s (-%c) \t: " "shutdown the CRMd on \n", "kill", 'K'); fprintf(stream, "\t--%s (-%c) \t: " "request the status of \n", "status", 'S'); #if 0 fprintf(stream, "\t--%s (-%c)\t\t: " "request the status of all nodes\n", "health", 'H'); #endif fprintf(stream, "\t--%s (-%c) \t: " "initiate an election from \n", "election", 'E'); fprintf(stream, "\t--%s (-%c)\t: " "request the uname of the DC\n", "dc_lookup", 'D'); fprintf(stream, "\t--%s (-%c)\t\t: " "request the uname of all member nodes\n", "nodes", 'N'); /* fprintf(stream, "\t--%s (-%c)\t\n", "disconnect", 'D'); */ fflush(stream); exit(exit_status); } diff --git a/crm/admin/xml_diff.c b/crm/admin/xml_diff.c index 018ec49bb9..1611361c88 100644 --- a/crm/admin/xml_diff.c +++ b/crm/admin/xml_diff.c @@ -1,269 +1,268 @@ /* * 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 #ifdef HAVE_GETOPT_H #include #endif #include /* someone complaining about _ha_msg_mod not being found */ void usage(const char *cmd, int exit_status); #define OPTARGS "V?o:n:p:scfO:N:" int main(int argc, char **argv) { gboolean apply = FALSE; gboolean raw_1 = FALSE; gboolean raw_2 = FALSE; gboolean filter = FALSE; gboolean use_stdin = FALSE; gboolean as_cib = FALSE; int argerr = 0; int flag; crm_data_t *object_1 = NULL; crm_data_t *object_2 = NULL; crm_data_t *output = NULL; const char *xml_file_1 = NULL; const char *xml_file_2 = NULL; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"original", 1, 0, 'o'}, {"new", 1, 0, 'n'}, {"original-string", 1, 0, 'O'}, {"new-string", 1, 0, 'N'}, {"patch", 1, 0, 'p'}, {"stdin", 0, 0, 's'}, {"cib", 0, 0, 'c'}, {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {0, 0, 0, 0} }; #endif crm_log_init("diff", LOG_CRIT-1, FALSE, FALSE, 0, NULL); if(argc < 2) { usage(crm_system_name, 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 if (flag == -1) break; switch(flag) { case 'o': xml_file_1 = optarg; break; case 'O': xml_file_1 = optarg; raw_1 = TRUE; break; case 'n': xml_file_2 = optarg; break; case 'N': xml_file_2 = optarg; raw_2 = TRUE; break; case 'p': xml_file_2 = optarg; apply = TRUE; break; case 'f': filter = TRUE; break; case 's': use_stdin = TRUE; break; case 'c': as_cib = TRUE; break; case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); 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"); } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } if(raw_1) { object_1 = string2xml(xml_file_1); } else if(use_stdin) { fprintf(stderr, "Input first XML fragment:"); object_1 = stdin2xml(); } else if(xml_file_1 != NULL) { FILE *xml_strm = fopen(xml_file_1, "r"); if(xml_strm != NULL) { crm_debug("Reading: %s", xml_file_1); if(strstr(xml_file_1, ".bz2") != NULL) { object_1 = file2xml(xml_strm, TRUE); } else { object_1 = file2xml(xml_strm, FALSE); } fclose(xml_strm); } else { cl_perror("Couldn't open %s for reading", xml_file_1); } } if(raw_2) { object_2 = string2xml(xml_file_2); } else if(use_stdin) { fprintf(stderr, "Input second XML fragment:"); object_2 = stdin2xml(); } else if(xml_file_2 != NULL) { FILE *xml_strm = fopen(xml_file_2, "r"); if(xml_strm != NULL) { crm_debug("Reading: %s", xml_file_2); if(strstr(xml_file_2, ".bz2") != NULL) { object_2 = file2xml(xml_strm, TRUE); } else { object_2 = file2xml(xml_strm, FALSE); } fclose(xml_strm); } else { cl_perror("Couldn't open %s for reading", xml_file_2); } } CRM_ASSERT(object_1 != NULL); CRM_ASSERT(object_2 != NULL); if(apply) { if(as_cib == FALSE) { apply_xml_diff(object_1, object_2, &output); } else { apply_cib_diff(object_1, object_2, &output); } } else { if(as_cib == FALSE) { output = diff_xml_object(object_1, object_2, filter); } else { output = diff_cib_object(object_1, object_2, filter); } } if(output != NULL) { char *buffer = dump_xml_formatted(output); fprintf(stdout, "%s", crm_str(buffer)); crm_free(buffer); } free_xml(object_1); free_xml(object_2); free_xml(output); if(apply == FALSE && output != NULL) { return 1; } return 0; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status != 0 ? stderr : stdout; fprintf(stream, "usage: %s [-?V] [oO] [pnN]\n", cmd); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c)\tthis help message\n", "help", '?'); fprintf(stream, "\t--%s (-%c) \t\n", "original", 'o'); fprintf(stream, "\t--%s (-%c) \t\n", "new", 'n'); fprintf(stream, "\t--%s (-%c) \t\n", "original-string", 'O'); fprintf(stream, "\t--%s (-%c) \t\n", "new-string", 'N'); fprintf(stream, "\t--%s (-%c) \tApply a patch to the original XML\n", "patch", 'p'); fprintf(stream, "\t--%s (-%c)\tCompare/patch the inputs as a CIB\n", "cib", 'c'); fprintf(stream, "\t--%s (-%c)\tRead the inputs from stdin\n", "stdin", 's'); fflush(stream); exit(exit_status); } diff --git a/tools/attrd.c b/tools/attrd.c index 616e5f2a57..2486e595a5 100644 --- a/tools/attrd.c +++ b/tools/attrd.c @@ -1,634 +1,632 @@ /* * 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 /* #include */ #include #include #include #include #include #include #include #include #include #define OPTARGS "hV" GMainLoop* mainloop = NULL; char *attrd_uname = NULL; char *attrd_uuid = NULL; ll_cluster_t *attrd_cluster_conn; gboolean need_shutdown = FALSE; GHashTable *attr_hash = NULL; cib_t *cib_conn = NULL; typedef struct attr_hash_entry_s { char *id; char *set; char *section; char *value; char *last_value; int timeout; char *dampen; guint timer_id; } attr_hash_entry_t; static void free_hash_entry(gpointer data) { attr_hash_entry_t *entry = data; if (entry == NULL) { return; } crm_free(entry->id); crm_free(entry->set); crm_free(entry->dampen); crm_free(entry->section); if(entry->value != entry->last_value) { crm_free(entry->value); crm_free(entry->last_value); } else { crm_free(entry->value); } crm_free(entry); } void attrd_ha_callback(HA_Message * msg, void* private_data); void attrd_local_callback(HA_Message * msg); gboolean attrd_timer_callback(void *user_data); gboolean attrd_trigger_update(attr_hash_entry_t *hash_entry); void attrd_perform_update(attr_hash_entry_t *hash_entry); static gboolean attrd_shutdown(int nsig, gpointer unused) { need_shutdown = TRUE; crm_info("Exiting"); if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); } else { exit(0); } return FALSE; } static void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-srkh] [-c configure file]\n", cmd); /* fprintf(stream, "\t-d\tsets debug level\n"); */ /* fprintf(stream, "\t-s\tgets daemon status\n"); */ /* fprintf(stream, "\t-r\trestarts daemon\n"); */ /* fprintf(stream, "\t-k\tstops daemon\n"); */ /* fprintf(stream, "\t-h\thelp message\n"); */ fflush(stream); exit(exit_status); } typedef struct attrd_client_s { char *id; char *name; IPC_Channel *channel; GCHSource *source; } attrd_client_t; static void stop_attrd_timer(attr_hash_entry_t *hash_entry) { if(hash_entry != NULL && hash_entry->timer_id != 0) { crm_debug_2("Stopping %s timer", hash_entry->id); Gmain_timeout_remove(hash_entry->timer_id); hash_entry->timer_id = 0; } } static gboolean attrd_ipc_callback(IPC_Channel *client, gpointer user_data) { int lpc = 0; HA_Message *msg = NULL; attrd_client_t *curr_client = (attrd_client_t*)user_data; gboolean stay_connected = TRUE; crm_debug_2("Invoked: %s", curr_client->id); while(IPC_ISRCONN(client)) { if(client->ops->is_message_pending(client) == 0) { break; } msg = msgfromIPC_noauth(client); if (msg == NULL) { crm_debug("%s: no message this time", curr_client->id); continue; } lpc++; crm_debug_2("Processing msg from %s", curr_client->id); crm_log_message_adv(LOG_DEBUG_3, __PRETTY_FUNCTION__, msg); attrd_local_callback(msg); crm_msg_del(msg); msg = NULL; if(client->ch_status != IPC_CONNECT) { break; } } crm_debug_2("Processed %d messages", lpc); if (client->ch_status != IPC_CONNECT) { stay_connected = FALSE; } return stay_connected; } static void attrd_connection_destroy(gpointer user_data) { attrd_client_t *client = user_data; /* cib_process_disconnect */ if(client == NULL) { return; } if(client->source != NULL) { crm_debug_4("Deleting %s (%p) from mainloop", client->name, client->source); G_main_del_IPC_Channel(client->source); client->source = NULL; } crm_debug_3("Destroying %s (%p)", client->name, client); crm_free(client->name); crm_free(client->id); crm_free(client); crm_debug_4("Freed the cib client"); return; } static gboolean attrd_connect(IPC_Channel *channel, gpointer user_data) { attrd_client_t *new_client = NULL; crm_debug_3("Connecting channel"); if(channel == NULL) { crm_err("Channel was NULL"); return FALSE; } else if(channel->ch_status != IPC_CONNECT) { crm_err("Channel was disconnected"); return FALSE; } else if(need_shutdown) { crm_info("Ignoring connection request during shutdown"); return FALSE; } crm_malloc0(new_client, sizeof(attrd_client_t)); new_client->channel = channel; crm_debug_3("Created channel %p for channel %s", new_client, new_client->id); /* channel->ops->set_recv_qlen(channel, 100); */ /* channel->ops->set_send_qlen(channel, 400); */ new_client->source = G_main_add_IPC_Channel( G_PRIORITY_DEFAULT, channel, FALSE, attrd_ipc_callback, new_client, attrd_connection_destroy); crm_debug_3("Client %s connected", new_client->id); return TRUE; } static void attrd_ha_connection_destroy(gpointer user_data) { crm_debug_3("Invoked"); if(need_shutdown) { /* we signed out, so this is expected */ crm_info("Heartbeat disconnection complete"); return; } crm_crit("Lost connection to heartbeat service!"); if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); return; } exit(LSB_EXIT_OK); } static gboolean register_with_ha(void) { void *dispatch = attrd_ha_callback; void *destroy = attrd_ha_connection_destroy; if(is_openais_cluster()) { #if SUPPORT_AIS destroy = NULL; dispatch = NULL; #endif } return crm_cluster_connect( &attrd_uname, &attrd_uuid, dispatch, destroy, &attrd_cluster_conn); } static void attrd_cib_connection_destroy(gpointer user_data) { if(need_shutdown) { crm_info("Connection to the CIB terminated..."); } else { /* eventually this will trigger a reconnect, not a shutdown */ crm_err("Connection to the CIB terminated..."); exit(1); } return; } int main(int argc, char ** argv) { int flag; int argerr = 0; gboolean was_err = FALSE; char *channel_name = crm_strdup(attrd_channel); crm_log_init(T_ATTRD, LOG_INFO, TRUE, FALSE, 0, NULL); G_main_add_SignalHandler( G_PRIORITY_HIGH, SIGTERM, attrd_shutdown, NULL, NULL); while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { switch(flag) { case 'V': cl_log_enable_stderr(1); alter_debug(DEBUG_INC); break; case 'h': /* Help message */ usage(T_ATTRD, LSB_EXIT_OK); break; default: ++argerr; break; } } if (optind > argc) { ++argerr; } if (argerr) { usage(T_ATTRD, LSB_EXIT_GENERIC); } crm_info("Starting up...."); if(register_with_ha() == FALSE) { crm_err("HA Signon failed"); was_err = TRUE; } if(was_err == FALSE) { int lpc = 0; int max_retry = 20; enum cib_errors rc = cib_not_connected; cib_conn = cib_new(); for(lpc = 0; lpc < max_retry && rc != cib_ok; lpc++) { crm_debug("CIB signon attempt %d", lpc); rc = cib_conn->cmds->signon( cib_conn, T_ATTRD, cib_command); sleep(5); } if(rc != cib_ok) { crm_err("Signon to CIB failed: %s", cib_error2string(rc)); was_err = TRUE; } } if(was_err == FALSE) { enum cib_errors rc = cib_conn->cmds->set_connection_dnotify( cib_conn, attrd_cib_connection_destroy); if(rc != cib_ok) { crm_err("Could not set dnotify callback"); was_err = TRUE; } } if(was_err == FALSE) { int rc = init_server_ipc_comms( channel_name, attrd_connect, default_ipc_connection_destroy); if(rc != 0) { crm_err("Could not start IPC server"); was_err = TRUE; } } if(was_err) { crm_err("Aborting startup"); return 100; } attr_hash = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, free_hash_entry); crm_info("Starting mainloop..."); mainloop = g_main_new(FALSE); g_main_run(mainloop); crm_info("Exiting..."); attrd_cluster_conn->llc_ops->signoff(attrd_cluster_conn, TRUE); attrd_cluster_conn->llc_ops->delete(attrd_cluster_conn); cib_conn->cmds->signoff(cib_conn); cib_delete(cib_conn); g_hash_table_destroy(attr_hash); crm_free(channel_name); crm_free(attrd_uuid); empty_uuid_cache(); return 0; } static void attrd_cib_callback(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data) { char *attr = user_data; if(rc == cib_NOTEXISTS) { rc = cib_ok; } if(rc < cib_ok) { crm_err("Update %d for %s failed: %s", call_id, attr, cib_error2string(rc)); } else { crm_debug("Update %d for %s passed", call_id, attr); } crm_free(attr); } static void log_hash_entry(int level, attr_hash_entry_t *entry, const char *text) { do_crm_log(level, "%s", text); do_crm_log(level, "Set: %s", entry->section); do_crm_log(level, "Name: %s", entry->id); do_crm_log(level, "Value: %s", entry->value); do_crm_log(level, "Timeout: %s", entry->dampen); } static attr_hash_entry_t * find_hash_entry(HA_Message * msg) { const char *value = NULL; const char *attr = ha_msg_value(msg, F_ATTRD_ATTRIBUTE); attr_hash_entry_t *hash_entry = NULL; if(attr == NULL) { crm_info("Ignoring message with no attribute name"); return NULL; } hash_entry = g_hash_table_lookup(attr_hash, attr); if(hash_entry == NULL) { /* create one and add it */ crm_info("Creating hash entry for %s", attr); crm_malloc0(hash_entry, sizeof(attr_hash_entry_t)); hash_entry->id = crm_strdup(attr); g_hash_table_insert(attr_hash, hash_entry->id, hash_entry); hash_entry = g_hash_table_lookup(attr_hash, attr); CRM_CHECK(hash_entry != NULL, return NULL); } value = ha_msg_value(msg, F_ATTRD_SET); if(value != NULL) { crm_free(hash_entry->set); hash_entry->set = crm_strdup(value); crm_debug("\t%s->set: %s", attr, value); } value = ha_msg_value(msg, F_ATTRD_SECTION); if(value == NULL) { value = XML_CIB_TAG_STATUS; } crm_free(hash_entry->section); hash_entry->section = crm_strdup(value); crm_debug("\t%s->section: %s", attr, value); value = ha_msg_value(msg, F_ATTRD_DAMPEN); if(value != NULL) { crm_free(hash_entry->dampen); hash_entry->dampen = crm_strdup(value); hash_entry->timeout = crm_get_msec(value); crm_debug("\t%s->timeout: %s", attr, value); } log_hash_entry(LOG_DEBUG_2, hash_entry, "Found (and updated) entry:"); return hash_entry; } void attrd_ha_callback(HA_Message * msg, void* private_data) { attr_hash_entry_t *hash_entry = NULL; const char *from = ha_msg_value(msg, F_ORIG); const char *op = ha_msg_value(msg, F_ATTRD_TASK); const char *ignore = ha_msg_value(msg, F_ATTRD_IGNORE_LOCALLY); if(ignore == NULL || safe_str_neq(from, attrd_uname)) { crm_info("%s message from %s", op, from); hash_entry = find_hash_entry(msg); stop_attrd_timer(hash_entry); attrd_perform_update(hash_entry); } } void attrd_perform_update(attr_hash_entry_t *hash_entry) { int rc = cib_ok; if(hash_entry == NULL) { return; } else if(hash_entry->value == NULL) { /* delete the attr */ rc = delete_attr(cib_conn, cib_none, hash_entry->section, attrd_uuid, hash_entry->set, NULL, hash_entry->id, NULL, FALSE); crm_info("Sent delete %d: %s %s %s", rc, hash_entry->id, hash_entry->set, hash_entry->section); } else { /* send update */ rc = update_attr(cib_conn, cib_none, hash_entry->section, attrd_uuid, hash_entry->set, NULL, hash_entry->id, hash_entry->value, FALSE); crm_info("Sent update %d: %s=%s", rc, hash_entry->id, hash_entry->value); } add_cib_op_callback(rc, FALSE, crm_strdup(hash_entry->id), attrd_cib_callback); return; } static void update_for_hash_entry(gpointer key, gpointer value, gpointer user_data) { attrd_timer_callback(value); } void attrd_local_callback(HA_Message * msg) { attr_hash_entry_t *hash_entry = NULL; const char *from = ha_msg_value(msg, F_ORIG); const char *op = ha_msg_value(msg, F_ATTRD_TASK); const char *attr = ha_msg_value(msg, F_ATTRD_ATTRIBUTE); const char *value = ha_msg_value(msg, F_ATTRD_VALUE); if(safe_str_eq(op, "refresh")) { crm_info("Sending full refresh"); g_hash_table_foreach(attr_hash, update_for_hash_entry, NULL); return; } crm_debug("%s message from %s: %s=%s", op, from, attr, crm_str(value)); hash_entry = find_hash_entry(msg); if(hash_entry == NULL) { return; } crm_free(hash_entry->last_value); hash_entry->last_value = hash_entry->value; if(value != NULL) { hash_entry->value = crm_strdup(value); } else { hash_entry->value = NULL; } if(safe_str_eq(hash_entry->value, hash_entry->last_value)) { crm_debug_2("Ignoring non-change"); return; } stop_attrd_timer(hash_entry); if(hash_entry->timeout > 0) { hash_entry->timer_id = Gmain_timeout_add( hash_entry->timeout, attrd_timer_callback, hash_entry); } else { attrd_trigger_update(hash_entry); } return; } gboolean attrd_timer_callback(void *user_data) { stop_attrd_timer(user_data); attrd_trigger_update(user_data); return TRUE; } gboolean attrd_trigger_update(attr_hash_entry_t *hash_entry) { HA_Message *msg = NULL; /* send HA message to everyone */ crm_info("Sending flush op to all hosts for: %s", hash_entry->id); log_hash_entry(LOG_DEBUG_2, hash_entry, "Sending flush op to all hosts for:"); msg = ha_msg_new(8); ha_msg_add(msg, F_TYPE, T_ATTRD); ha_msg_add(msg, F_ORIG, attrd_uname); ha_msg_add(msg, F_ATTRD_TASK, "flush"); ha_msg_add(msg, F_ATTRD_ATTRIBUTE, hash_entry->id); ha_msg_add(msg, F_ATTRD_SET, hash_entry->set); ha_msg_add(msg, F_ATTRD_SECTION, hash_entry->section); ha_msg_add(msg, F_ATTRD_DAMPEN, hash_entry->dampen); ha_msg_add(msg, F_ATTRD_VALUE, hash_entry->value); if(hash_entry->timeout <= 0) { ha_msg_add(msg, F_ATTRD_IGNORE_LOCALLY, hash_entry->value); attrd_perform_update(hash_entry); } send_cluster_message(NULL, crm_proc_attrd, msg, FALSE); crm_msg_del(msg); return TRUE; } diff --git a/transitioner/callbacks.c b/transitioner/callbacks.c index e2d4b6ce28..dc993a9c06 100644 --- a/transitioner/callbacks.c +++ b/transitioner/callbacks.c @@ -1,593 +1,591 @@ /* * 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 void te_update_confirm(const char *event, HA_Message *msg); void te_update_diff(const char *event, HA_Message *msg); crm_data_t *need_abort(crm_data_t *update); void cib_fencing_updated(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data); extern char *te_uuid; gboolean shuttingdown = FALSE; crm_graph_t *transition_graph; GTRIGSource *transition_trigger = NULL; crm_action_timer_t *transition_timer = NULL; static gboolean start_global_timer(crm_action_timer_t *timer, int timeout) { CRM_ASSERT(timer != NULL); CRM_CHECK(timer > 0, return FALSE); CRM_CHECK(timer->source_id == 0, return FALSE); if(timeout <= 0) { crm_err("Tried to start timer with period: %d", timeout); } else if(timer->source_id == 0) { crm_debug_2("Starting abort timer: %dms", timeout); timer->timeout = timeout; timer->source_id = Gmain_timeout_add( timeout, global_timer_callback, (void*)timer); CRM_ASSERT(timer->source_id != 0); return TRUE; } else { crm_err("Timer is already active with period: %d", timer->timeout); } return FALSE; } void te_update_diff(const char *event, HA_Message *msg) { int rc = -1; const char *op = NULL; crm_data_t *diff = NULL; crm_data_t *aborted = NULL; const char *set_name = NULL; int diff_add_updates = 0; int diff_add_epoch = 0; int diff_add_admin_epoch = 0; int diff_del_updates = 0; int diff_del_epoch = 0; int diff_del_admin_epoch = 0; if(msg == NULL) { crm_err("NULL update"); return; } ha_msg_value_int(msg, F_CIB_RC, &rc); op = cl_get_string(msg, F_CIB_OPERATION); if(rc < cib_ok) { crm_debug_2("Ignoring failed %s operation: %s", op, cib_error2string(rc)); return; } diff = get_message_xml(msg, F_CIB_UPDATE_RESULT); cib_diff_version_details( diff, &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates, &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates); crm_debug("Processing diff (%s): %d.%d.%d -> %d.%d.%d", op, diff_del_admin_epoch,diff_del_epoch,diff_del_updates, diff_add_admin_epoch,diff_add_epoch,diff_add_updates); log_cib_diff(LOG_DEBUG_2, diff, op); set_name = "diff-added"; if(diff != NULL) { crm_data_t *section = NULL; crm_data_t *change_set = find_xml_node(diff, set_name, FALSE); change_set = find_xml_node(change_set, XML_TAG_CIB, FALSE); if(change_set != NULL) { crm_debug_2("Checking status changes"); section=get_object_root(XML_CIB_TAG_STATUS,change_set); } if(section != NULL) { extract_event(section); } crm_debug_2("Checking change set: %s", set_name); aborted = need_abort(change_set); } set_name = "diff-removed"; if(diff != NULL && aborted == NULL) { crm_data_t *attrs = NULL; crm_data_t *status = NULL; crm_data_t *change_set = find_xml_node(diff, set_name, FALSE); change_set = find_xml_node(change_set, XML_TAG_CIB, FALSE); crm_debug_2("Checking change set: %s", set_name); aborted = need_abort(change_set); if(aborted == NULL && change_set != NULL) { status = get_object_root(XML_CIB_TAG_STATUS, change_set); xml_child_iter_filter( status, node_state, XML_CIB_TAG_STATE, attrs = find_xml_node( node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE); if(attrs != NULL) { crm_info("Aborting on "XML_TAG_TRANSIENT_NODEATTRS" deletions"); abort_transition(INFINITY, tg_restart, XML_TAG_TRANSIENT_NODEATTRS, attrs); } ); } } if(aborted != NULL) { abort_transition( INFINITY, tg_restart, "Non-status change", NULL); } free_xml(diff); return; } gboolean process_te_message(HA_Message *msg, crm_data_t *xml_data, IPC_Channel *sender) { crm_data_t *xml_obj = NULL; const char *from = cl_get_string(msg, F_ORIG); const char *sys_to = cl_get_string(msg, F_CRM_SYS_TO); const char *sys_from = cl_get_string(msg, F_CRM_SYS_FROM); const char *ref = cl_get_string(msg, XML_ATTR_REFERENCE); const char *op = cl_get_string(msg, F_CRM_TASK); const char *type = cl_get_string(msg, F_CRM_MSG_TYPE); crm_debug_2("Processing %s (%s) message", op, ref); crm_log_message(LOG_DEBUG_3, msg); if(op == NULL){ /* error */ } else if(strcasecmp(op, CRM_OP_HELLO) == 0) { /* ignore */ } else if(sys_to == NULL || strcasecmp(sys_to, CRM_SYSTEM_TENGINE) != 0) { crm_debug_2("Bad sys-to %s", crm_str(sys_to)); return FALSE; } else if(safe_str_eq(op, CRM_OP_INVOKE_LRM) && safe_str_eq(sys_from, CRM_SYSTEM_LRMD) /* && safe_str_eq(type, XML_ATTR_RESPONSE) */ ){ #if CRM_DEPRECATED_SINCE_2_0_4 if(safe_str_eq(crm_element_name(xml_data), XML_TAG_CIB)) { xml_obj = xml_data; } else { xml_obj = find_xml_node(xml_data, XML_TAG_CIB, TRUE); } #else xml_obj = xml_data; CRM_CHECK(xml_obj != NULL, crm_log_message_adv(LOG_ERR, "Invalid (N)ACK", msg); return FALSE); #endif CRM_CHECK(xml_obj != NULL, crm_log_message_adv(LOG_ERR, "Invalid (N)ACK", msg); return FALSE); xml_obj = get_object_root(XML_CIB_TAG_STATUS, xml_obj); CRM_CHECK(xml_obj != NULL, crm_log_message_adv(LOG_ERR, "Invalid (N)ACK", msg); return FALSE); crm_log_message_adv(LOG_DEBUG_2, "Processing (N)ACK", msg); crm_info("Processing (N)ACK %s from %s", cl_get_string(msg, XML_ATTR_REFERENCE), from); extract_event(xml_obj); } else if(safe_str_eq(type, XML_ATTR_RESPONSE)) { crm_err("Message was a response not a request. Discarding"); return TRUE; } else if(strcasecmp(op, CRM_OP_TRANSITION) == 0) { const char *graph_file = cl_get_string(msg, F_CRM_TGRAPH); const char *graph_input = cl_get_string(msg, F_CRM_TGRAPH_INPUT); CRM_CHECK(graph_file != NULL || xml_data != NULL, crm_err("No graph provided"); crm_log_message(LOG_WARNING, msg); return TRUE); if(transition_graph->complete == FALSE) { crm_info("Another transition is already active"); abort_transition( INFINITY, tg_restart, "Transition Active", NULL); } else { crm_data_t *graph_data = xml_data; crm_debug("Processing graph derived from %s", graph_input); if(graph_file != NULL) { FILE *graph_fd = fopen(graph_file, "r"); CRM_CHECK(graph_fd != NULL, cl_perror("Could not open graph file %s", graph_file); return TRUE); graph_data = file2xml(graph_fd, FALSE); unlink(graph_file); fclose(graph_fd); } destroy_graph(transition_graph); transition_graph = unpack_graph(graph_data); start_global_timer(transition_timer, transition_graph->transition_timeout); trigger_graph(); print_graph(LOG_DEBUG_2, transition_graph); if(graph_data != xml_data) { free_xml(graph_data); } } } else if(strcasecmp(op, CRM_OP_TE_HALT) == 0) { abort_transition(INFINITY, tg_stop, "Peer Halt", NULL); } else if(strcasecmp(op, CRM_OP_TEABORT) == 0) { abort_transition(INFINITY, tg_restart, "Peer Cancelled", NULL); } else { crm_err("Unknown command: %s::%s from %s", type, op, sys_from); } crm_debug_3("finished processing message"); return TRUE; } #if SUPPORT_HEARTBEAT void tengine_stonith_callback(stonith_ops_t * op) { const char *allow_fail = NULL; int stonith_id = -1; int transition_id = -1; char *uuid = NULL; crm_action_t *stonith_action = NULL; if(op == NULL) { crm_err("Called with a NULL op!"); return; } crm_info("call=%d, optype=%d, node_name=%s, result=%d, node_list=%s, action=%s", op->call_id, op->optype, op->node_name, op->op_result, (char *)op->node_list, op->private_data); /* this will mark the event complete if a match is found */ CRM_CHECK(op->private_data != NULL, return); /* filter out old STONITH actions */ CRM_CHECK(decode_transition_key( op->private_data, &uuid, &transition_id, &stonith_id), crm_err("Invalid event detected"); goto bail; ); if(transition_graph->complete || stonith_id < 0 || safe_str_neq(uuid, te_uuid) || transition_graph->id != transition_id) { crm_info("Ignoring STONITH action initiated outside" " of the current transition"); } stonith_action = get_action(stonith_id, TRUE); if(stonith_action == NULL) { crm_err("Stonith action not matched"); goto bail; } switch(op->op_result) { case STONITH_SUCCEEDED: send_stonith_update(op); break; case STONITH_CANNOT: case STONITH_TIMEOUT: case STONITH_GENERIC: stonith_action->failed = TRUE; allow_fail = g_hash_table_lookup( stonith_action->params, crm_meta_name(XML_ATTR_TE_ALLOWFAIL)); if(FALSE == crm_is_true(allow_fail)) { crm_err("Stonith of %s failed (%d)..." " aborting transition.", op->node_name, op->op_result); abort_transition(INFINITY, tg_restart, "Stonith failed", NULL); } break; default: crm_err("Unsupported action result: %d", op->op_result); abort_transition(INFINITY, tg_restart, "Unsupport Stonith result", NULL); } update_graph(transition_graph, stonith_action); trigger_graph(); bail: crm_free(uuid); return; } void tengine_stonith_connection_destroy(gpointer user_data) { crm_err("Fencing daemon has left us"); stonith_src = NULL; if(stonith_src == NULL) { G_main_set_trigger(stonith_reconnect); } /* cbchan will be garbage at this point, arrange for it to be reset */ set_stonithd_input_IPC_channel_NULL(); return; } gboolean tengine_stonith_dispatch(IPC_Channel *sender, void *user_data) { int lpc = 0; while(stonithd_op_result_ready()) { if (sender->ch_status == IPC_DISCONNECT) { /* The message which was pending for us is that * the IPC status is now IPC_DISCONNECT */ break; } if(ST_FAIL == stonithd_receive_ops_result(FALSE)) { crm_err("stonithd_receive_ops_result() failed"); } else { lpc++; } } crm_debug_2("Processed %d messages", lpc); if (sender->ch_status == IPC_DISCONNECT) { return FALSE; } return TRUE; } #endif void cib_fencing_updated(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data) { trigger_graph(); if(rc < cib_ok) { crm_err("CIB update failed: %s", cib_error2string(rc)); crm_log_xml_warn(msg, "[Failed Update]"); } } void cib_action_updated(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data) { trigger_graph(); if(rc < cib_ok) { crm_err("Update %d FAILED: %s", call_id, cib_error2string(rc)); } } gboolean action_timer_callback(gpointer data) { crm_action_timer_t *timer = NULL; if(data == NULL) { crm_err("Timer popped with no data"); return FALSE; } timer = (crm_action_timer_t*)data; stop_te_timer(timer); crm_warn("Timer popped (abort_level=%d, complete=%s)", transition_graph->abort_priority, transition_graph->complete?"true":"false"); CRM_CHECK(timer->action != NULL, return FALSE); if(transition_graph->complete) { crm_err("Ignoring timeout while not in transition"); } else if(timer->reason == timeout_action_warn) { print_action( LOG_WARNING,"Action missed its timeout", timer->action); } else { /* fail the action */ cib_action_update(timer->action, LRM_OP_TIMEOUT); } return FALSE; } static int unconfirmed_actions(gboolean send_updates) { int unconfirmed = 0; const char *key = NULL; const char *task = NULL; const char *node = NULL; crm_debug_2("Unconfirmed actions..."); slist_iter( synapse, synapse_t, transition_graph->synapses, lpc, /* lookup event */ slist_iter( action, crm_action_t, synapse->actions, lpc2, if(action->executed == FALSE) { continue; } else if(action->confirmed) { continue; } unconfirmed++; task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); key = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); crm_info("Action %s %d unconfirmed from %s", key, action->id, node); if(action->type != action_type_rsc) { continue; } else if(send_updates == FALSE) { continue; } else if(safe_str_eq(task, "cancel")) { /* we dont need to update the CIB with these */ continue; } else if(safe_str_eq(task, "stop")) { /* *never* update the CIB with these */ continue; } cib_action_update(action, LRM_OP_PENDING); ); ); if(unconfirmed > 0) { crm_warn("Waiting on %d unconfirmed actions", unconfirmed); } return unconfirmed; } gboolean global_timer_callback(gpointer data) { crm_action_timer_t *timer = NULL; if(data == NULL) { crm_err("Timer popped with no data"); return FALSE; } timer = (crm_action_timer_t*)data; stop_te_timer(timer); crm_warn("Timer popped (abort_level=%d, complete=%s)", transition_graph->abort_priority, transition_graph->complete?"true":"false"); CRM_CHECK(timer->action == NULL, return FALSE); if(transition_graph->complete) { crm_err("Ignoring timeout while not in transition"); } else if(timer->reason == timeout_abort) { int unconfirmed = unconfirmed_actions(FALSE); crm_warn("Transition abort timeout reached..." " marking transition complete."); transition_graph->complete = TRUE; abort_transition(INFINITY, tg_restart, "Global Timeout", NULL); if(unconfirmed != 0) { crm_warn("Writing %d unconfirmed actions to the CIB", unconfirmed); unconfirmed_actions(TRUE); } } return FALSE; } gboolean te_graph_trigger(gpointer user_data) { int timeout = 0; enum transition_status graph_rc = -1; if(transition_graph->complete) { notify_crmd(transition_graph); return TRUE; } graph_rc = run_graph(transition_graph); timeout = transition_graph->transition_timeout; print_graph(LOG_DEBUG_3, transition_graph); if(graph_rc == transition_active) { crm_debug_3("Transition not yet complete"); stop_te_timer(transition_timer); start_global_timer(transition_timer, timeout); return TRUE; } else if(graph_rc == transition_pending) { crm_debug_3("Transition not yet complete - no actions fired"); return TRUE; } if(graph_rc != transition_complete) { crm_err("Transition failed: %s", transition_status(graph_rc)); print_graph(LOG_WARNING, transition_graph); } transition_graph->complete = TRUE; notify_crmd(transition_graph); return TRUE; } diff --git a/transitioner/main.c b/transitioner/main.c index 21fdcd15b6..7a902fe9cf 100644 --- a/transitioner/main.c +++ b/transitioner/main.c @@ -1,239 +1,238 @@ /* * 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 #define OPTARGS "hVc" GMainLoop* mainloop = NULL; cib_t *te_cib_conn = NULL; void usage(const char* cmd, int exit_status); int te_init(void); gboolean tengine_shutdown(int nsig, gpointer unused); extern void te_update_confirm(const char *event, HA_Message *msg); extern void te_update_diff(const char *event, HA_Message *msg); extern crm_graph_functions_t te_graph_fns; int main(int argc, char ** argv) { int flag; int rc = 0; int dummy = 0; int argerr = 0; gboolean allow_cores = TRUE; crm_log_init(CRM_SYSTEM_TENGINE, LOG_INFO, TRUE, FALSE, 0, NULL); G_main_add_SignalHandler( G_PRIORITY_HIGH, SIGTERM, tengine_shutdown, NULL, NULL); transition_trigger = G_main_add_TriggerHandler( G_PRIORITY_LOW, te_graph_trigger, NULL, NULL); stonith_reconnect = G_main_add_TriggerHandler( G_PRIORITY_LOW, te_connect_stonith, &dummy, NULL); crm_debug_3("Begining option processing"); while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { switch(flag) { case 'V': alter_debug(DEBUG_INC); break; case 'h': /* Help message */ usage(crm_system_name, LSB_EXIT_OK); break; case 'c': allow_cores = TRUE; break; default: ++argerr; break; } } crm_debug_3("Option processing complete"); if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name,LSB_EXIT_GENERIC); } /* read local config file */ crm_debug_3("Starting..."); rc = te_init(); return rc; } int te_init(void) { int init_ok = TRUE; init_client_ipc_comms( CRM_SYSTEM_CRMD, subsystem_msg_dispatch, (void*)process_te_message, &crm_ch); if(crm_ch != NULL) { send_hello_message(crm_ch, "1234", CRM_SYSTEM_TENGINE, "0", "1"); } else { init_ok = FALSE; crm_err("Could not connect to the CRMd"); } if(init_ok) { crm_debug_4("Creating CIB connection"); te_cib_conn = cib_new(); if(te_cib_conn == NULL) { init_ok = FALSE; } } if(init_ok) { crm_debug_4("Connecting to the CIB"); if(cib_ok != te_cib_conn->cmds->signon( te_cib_conn, crm_system_name, cib_command)) { crm_err("Could not connect to the CIB"); init_ok = FALSE; } } if(init_ok) { crm_debug_4("Setting CIB notification callback"); if(cib_ok != te_cib_conn->cmds->add_notify_callback( te_cib_conn, T_CIB_DIFF_NOTIFY, te_update_diff)) { crm_err("Could not set CIB notification callback"); init_ok = FALSE; } } if(is_heartbeat_cluster() && init_ok) { G_main_set_trigger(stonith_reconnect); } if(init_ok) { cl_uuid_t new_uuid; char uuid_str[UU_UNPARSE_SIZEOF]; cl_uuid_generate(&new_uuid); cl_uuid_unparse(&new_uuid, uuid_str); te_uuid = crm_strdup(uuid_str); crm_info("Registering TE UUID: %s", te_uuid); set_graph_functions(&te_graph_fns); /* create a blank one */ transition_graph = unpack_graph(NULL); transition_graph->complete = TRUE; transition_graph->abort_reason = "DC Takeover"; transition_graph->completion_action = tg_restart; crm_malloc0(transition_timer, sizeof(crm_action_timer_t)); transition_timer->source_id = 0; transition_timer->reason = timeout_abort; transition_timer->action = NULL; } if(init_ok) { /* Create the mainloop and run it... */ crm_info("Starting %s", crm_system_name); mainloop = g_main_new(FALSE); g_main_run(mainloop); return_to_orig_privs(); crm_info("Exiting %s", crm_system_name); } else { crm_warn("Initialization errors, %s not starting.", crm_system_name); } destroy_graph(transition_graph); crm_free(transition_timer); te_cib_conn->cmds->signoff(te_cib_conn); cib_delete(te_cib_conn); te_cib_conn = NULL; #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { stonithd_signoff(); } #endif crm_free(te_uuid); if(init_ok) { return 0; } return 1; } void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-srkh]" "[-c configure file]\n", cmd); /* fprintf(stream, "\t-d\tsets debug level\n"); */ /* fprintf(stream, "\t-s\tgets daemon status\n"); */ /* fprintf(stream, "\t-r\trestarts daemon\n"); */ /* fprintf(stream, "\t-k\tstops daemon\n"); */ /* fprintf(stream, "\t-h\thelp message\n"); */ fflush(stream); exit(exit_status); } gboolean shuttingdown; gboolean tengine_shutdown(int nsig, gpointer unused) { shuttingdown = TRUE; abort_transition(INFINITY, tg_shutdown, "Shutdown", NULL); return TRUE; }