diff --git a/crm/admin/ccm_epoche.c b/crm/admin/ccm_epoche.c index 0bac471556..837ff4413b 100644 --- a/crm/admin/ccm_epoche.c +++ b/crm/admin/ccm_epoche.c @@ -1,245 +1,245 @@ /* * 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 const char* crm_system_name = "ccm_tool"; oc_ev_t *ccm_token = NULL; int command = 0; #define OPTARGS "hVqep" void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int ); static void ccm_age_callback( oc_ed_t event, void *cookie, size_t size, const void *data); gboolean ccm_age_connect(int *ccm_fd); void usage(const char* cmd, int exit_status); char *lookup_host = NULL; int main(int argc, char ** argv) { int flag; int argerr = 0; int ccm_fd = 0; fd_set rset; oc_ev_t *ccm_token = NULL; - crm_log_init(crm_system_name, FALSE); + crm_log_init(crm_system_name, LOG_INFO, FALSE, FALSE, 0, NULL); while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { switch(flag) { case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 'h': /* Help message */ usage(crm_system_name, LSB_EXIT_OK); break; case 'p': case 'e': case 'q': command = flag; break; default: ++argerr; break; } } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name,LSB_EXIT_GENERIC); } if(ccm_age_connect(&ccm_fd)) { int rc = 0; int lpc = 0; for (;;lpc++) { FD_ZERO(&rset); FD_SET(ccm_fd, &rset); rc = select(ccm_fd + 1, &rset, NULL,NULL,NULL); if(rc == -1){ perror("select failed"); if(errno == EINTR) { crm_debug("Retry..."); continue; } } else if(oc_ev_handle_event(ccm_token) != 0){ crm_err("oc_ev_handle_event failed"); } return(1); } } return(1); } void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-V] [-p|-e|-q]\n", cmd); fprintf(stream, "\t-p : print the members of this partition\n"); fprintf(stream, "\t-e : print the epoch this node joined the partition\n"); fprintf(stream, "\t-q : print a 1 if our partition has quorum\n"); fflush(stream); exit(exit_status); } gboolean ccm_age_connect(int *ccm_fd) { gboolean did_fail = FALSE; int ret = 0; crm_debug("Registering with CCM"); ret = oc_ev_register(&ccm_token); if (ret != 0) { crm_warn("CCM registration failed"); did_fail = TRUE; } if(did_fail == FALSE) { crm_debug("Setting up CCM callbacks"); ret = oc_ev_set_callback(ccm_token, OC_EV_MEMB_CLASS, ccm_age_callback, NULL); if (ret != 0) { crm_warn("CCM callback not set"); did_fail = TRUE; } } if(did_fail == FALSE) { oc_ev_special(ccm_token, OC_EV_MEMB_CLASS, 0/*don't care*/); crm_debug("Activating CCM token"); ret = oc_ev_activate(ccm_token, ccm_fd); if (ret != 0){ crm_warn("CCM Activation failed"); did_fail = TRUE; } } return !did_fail; } static void ccm_age_callback(oc_ed_t event, void *cookie, size_t size, const void *data) { int lpc; int node_list_size; const oc_ev_membership_t *oc = (const oc_ev_membership_t *)data; crm_debug_3("-----------------------"); crm_debug_3("trans=%d, nodes=%d, new=%d, lost=%d n_idx=%d, " "new_idx=%d, old_idx=%d", oc->m_instance, oc->m_n_member, oc->m_n_in, oc->m_n_out, oc->m_memb_idx, oc->m_in_idx, oc->m_out_idx); node_list_size = oc->m_n_member; if(command == 'q') { crm_debug("Processing \"%s\" event.", event==OC_EV_MS_NEW_MEMBERSHIP?"NEW MEMBERSHIP": event==OC_EV_MS_NOT_PRIMARY?"NOT PRIMARY": event==OC_EV_MS_PRIMARY_RESTORED?"PRIMARY RESTORED": event==OC_EV_MS_EVICTED?"EVICTED": "NO QUORUM MEMBERSHIP"); if(ccm_have_quorum(event)) { fprintf(stdout, "1\n"); } else { fprintf(stdout, "0\n"); } } else if(command == 'e') { crm_debug("Searching %d members for our birth", oc->m_n_member); } for(lpc=0; lpcm_array[oc->m_memb_idx+lpc].node_uname); } else if(command == 'e') { if(oc_ev_is_my_nodeid(ccm_token, &(oc->m_array[lpc]))){ crm_debug("MATCH: nodeid=%d, uname=%s, born=%d", oc->m_array[oc->m_memb_idx+lpc].node_id, oc->m_array[oc->m_memb_idx+lpc].node_uname, oc->m_array[oc->m_memb_idx+lpc].node_born_on); fprintf(stdout, "%d\n", oc->m_array[oc->m_memb_idx+lpc].node_born_on); } } crm_debug_3("\tCURRENT: %s [nodeid=%d, born=%d]", oc->m_array[oc->m_memb_idx+lpc].node_uname, oc->m_array[oc->m_memb_idx+lpc].node_id, oc->m_array[oc->m_memb_idx+lpc].node_born_on); } for(lpc=0; lpc < (int)oc->m_n_in; lpc++) { crm_debug_3("\tNEW: %s [nodeid=%d, born=%d]", oc->m_array[oc->m_in_idx+lpc].node_uname, oc->m_array[oc->m_in_idx+lpc].node_id, oc->m_array[oc->m_in_idx+lpc].node_born_on); } for(lpc=0; lpc < (int)oc->m_n_out; lpc++) { crm_debug_3("\tLOST: %s [nodeid=%d, born=%d]", oc->m_array[oc->m_out_idx+lpc].node_uname, oc->m_array[oc->m_out_idx+lpc].node_id, oc->m_array[oc->m_out_idx+lpc].node_born_on); } crm_debug_3("-----------------------"); oc_ev_callback_done(cookie); if(command == 'p') { fprintf(stdout, "\n"); } fflush(stdout); exit(0); } diff --git a/crm/admin/cibadmin.c b/crm/admin/cibadmin.c index 62856aebd6..0b31006310 100644 --- a/crm/admin/cibadmin.c +++ b/crm/admin/cibadmin.c @@ -1,570 +1,566 @@ /* * 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; const char *crm_system_name = "cibadmin"; 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; #define OPTARGS "V?o:QDUCEX:t:Srwlsh:MmBfbdRx:pP" int main(int argc, char **argv) { int argerr = 0; int flag; char *admin_input_xml = NULL; char *admin_input_file = NULL; 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'}, {"force-quorum",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 - cl_log_set_entity("cibadmin"); - cl_log_set_facility(LOG_USER); - set_crm_log_level(LOG_CRIT); + 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; 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 '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': cib_action = CIB_OP_SLAVE; break; case 'w': 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': command_options |= cib_inhibit_bcast; command_options |= cib_scope_local; break; case 's': command_options |= cib_sync_call; break; case 'f': 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"); } if (optind > argc) { ++argerr; } if(cib_action == NULL) { usage(crm_system_name, cib_operation); } if (argerr) { 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]"); } 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; } - cl_log_args(argc, argv); - 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)\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 3046f5191a..ae60808b38 100644 --- a/crm/admin/crm_attribute.c +++ b/crm/admin/crm_attribute.c @@ -1,489 +1,485 @@ /* * 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; const char *crm_system_name = "crm_master"; #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-name", 1, 0, 'n'}, {"attr-value", 1, 0, 'v'}, {"resource-id", 1, 0, 'r'}, {"lifetime", 1, 0, 'l'}, {"inhibit-policy-engine", 0, 0, '!'}, {"type", 1, 0, 't'}, {0, 0, 0, 0} }; #endif crm_system_name = basename(argv[0]); - crm_log_init(crm_system_name, FALSE); - crm_log_level = LOG_ERR; - cl_log_enable_stderr(TRUE); + crm_log_init(crm_system_name, 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; - } - - cl_log_args(argc, argv); + } 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); } 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); if(rc == cib_NOTEXISTS) { /* Nothing to delete... * which means its not there... * which is what the admin wanted */ rc = cib_ok; } else if(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); 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); } else { char *read_value = NULL; rc = read_attr(the_cib, type, dest_node, set_name, attr_id, attr_name, &read_value); 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(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_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'); 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 c40d5d2e57..d147990e33 100644 --- a/crm/admin/crm_mon.c +++ b/crm/admin/crm_mon.c @@ -1,822 +1,821 @@ /* * 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; */ const char *crm_system_name = "crm_mon"; #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_system_name = basename(argv[0]); - crm_log_init(crm_system_name, FALSE); - crm_log_level = LOG_ERR -1; + crm_log_init(crm_system_name, 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) { 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(rsc->orphan == FALSE) { 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(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); (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 f52f0116db..f59b788bdc 100644 --- a/crm/admin/crm_resource.c +++ b/crm/admin/crm_resource.c @@ -1,1321 +1,1317 @@ /* * 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 *crm_system_name = 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" 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(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) { fprintf(stderr, "%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) { fprintf(stderr, "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) { fprintf(stderr, "\nThe following text can be suppressed with the -Q option:\n"); if(attr_set == NULL) { fprintf(stderr, " * To choose an existing entry to change, please supply one of the set names above using the -s option.\n"); } else { fprintf(stderr, " * To choose an existing entry to change, please supply one of the IDs above using the -i option.\n"); } fprintf(stderr, " * To create a new value with a default ID, please supply a different set name using the -s option.\n"); fprintf(stderr, "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; } xml_match = find_attr_details( rsc->xml, NULL, attr_set, attr_id, attr_name); if(xml_match == NULL) { return cib_missing_data; } 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) { fprintf(stderr, "Resource %s not found\n", rsc_id); return cib_NOTEXISTS; } else if(rsc->variant != pe_native) { fprintf(stderr, "We can only process primitive resources, not %s\n", rsc_id); return cib_invalid_argument; } else if(host_uname == NULL) { fprintf(stderr, "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) { fprintf(stderr, "%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) { fprintf(stderr, "%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); free_xml(msg_data); crm_free(key); if(send_ipc_message(crmd_channel, cmd)) { rc = 0; } 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) { 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) { fprintf(stderr, "Invalid duration specified: %s\n", migrate_lifetime); fprintf(stderr, "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); fprintf(stderr, "\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); fprintf(stderr, "\tThis will be the case even if %s is" " the last node in the cluster\n", existing_node); fprintf(stderr, "\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_system_name = basename(argv[0]); - cl_log_set_entity(crm_system_name); - cl_log_set_facility(LOG_LOCAL7); - set_crm_log_level(LOG_ERR); - cl_log_enable_stderr(TRUE); if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } + crm_log_init(crm_system_name, LOG_ERR, FALSE, FALSE, argc, argv); + 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: fprintf(stderr, "Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc) { fprintf(stderr, "non-option ARGV-elements: "); while (optind < argc) { fprintf(stderr, "%s ", argv[optind++]); } fprintf(stderr, "\n"); } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } - cl_log_args(argc, argv); - 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) { fprintf(stderr, "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) { fprintf(stderr, "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); } 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) { fprintf(stderr, "Resource %s not found: %s\n", crm_str(rsc_id), cib_error2string(rc)); } else if(rsc_cmd == 'W') { if(rsc_id == NULL) { fprintf(stderr, "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) { fprintf(stderr, "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) { fprintf(stderr, "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) { fprintf(stderr, "Resource %s not migrated:" " not found\n", rsc_id); } else if(rsc->variant == pe_native && g_list_length(rsc->running_on) > 1) { fprintf(stderr, "Resource %s not migrated:" " active on multiple nodes\n", rsc_id); } else if(host_uname != NULL && dest == NULL) { fprintf(stderr, "Error performing operation: " "%s is not a known node\n", host_uname); } else if(host_uname != NULL && safe_str_eq(current_uname, host_uname)) { fprintf(stderr, "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 { fprintf(stderr, "Resource %s not migrated: " "not-active and no prefered location" " specified.\n", rsc_id); } } else if(rsc_cmd == 'G') { if(rsc_id == NULL) { fprintf(stderr, "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) { fprintf(stderr, "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) { fprintf(stderr, "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) { fprintf(stderr, "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) { fprintf(stderr, "Must supply a resource id with -r\n"); return cib_NOTEXISTS; } if(prop_value == NULL) { fprintf(stderr, "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) { fprintf(stderr, "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) { fprintf(stderr, "Must supply a resource id with -r\n"); return cib_NOTEXISTS; } if(rsc_type == NULL) { fprintf(stderr, "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 { fprintf(stderr, "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) { fprintf(stderr, "Error performing operation: %s\n", cib_error2string(rc)); fprintf(stderr, "Try using -f\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; 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/crmadmin.c b/crm/admin/crmadmin.c index eb2004437f..e68f123952 100644 --- a/crm/admin/crmadmin.c +++ b/crm/admin/crmadmin.c @@ -1,734 +1,734 @@ /* * 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); ll_cluster_t *do_init(void); int do_work(ll_cluster_t * hb_cluster); 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; const char *crm_system_name = NULL; #define OPTARGS "V?K:S:HE:Dd:i:RNqt:Bv" int main(int argc, char **argv) { int argerr = 0; int flag; ll_cluster_t *hb_cluster = NULL; #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_system_name = basename(argv[0]); - crm_log_init(crm_system_name, FALSE); if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } + + crm_log_init(crm_system_name, LOG_ERR, FALSE, TRUE, argc, argv); 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); } hb_cluster = do_init(); if (hb_cluster != NULL) { int res = 0; - cl_log_args(argc, argv); res = do_work(hb_cluster); 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(ll_cluster_t * hb_cluster) { 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_info("Connection to CRMd was terminated"); exit(1); } ll_cluster_t * do_init(void) { int facility; GCHSource *src = NULL; ll_cluster_t *hb_cluster = NULL; /* change the logging facility to the one used by heartbeat daemon */ hb_cluster = ll_cluster_new("heartbeat"); crm_debug_2("Switching to Heartbeat logger"); if (( facility = hb_cluster->llc_ops->get_logfacility(hb_cluster)) > 0) { cl_log_set_facility(facility); } 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 hb_cluster; } 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 hb_cluster; } return NULL; } gboolean admin_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; 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; } 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++; 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); 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)) && crm_is_true(ccm_state) && safe_str_eq(crm_state, ONLINESTATUS)) { 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/test.iso8601.c b/crm/admin/test.iso8601.c index 5400d3be90..bed3738b88 100644 --- a/crm/admin/test.iso8601.c +++ b/crm/admin/test.iso8601.c @@ -1,139 +1,137 @@ /* * Copyright (C) 2005 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 #define OPTARGS "V?d:p:D:WOLn" char command = 0; static void usage(int rc) { fprintf(stderr, "Usage: iso8601 [-(O|W|L)] -(n|d|p|D) \n"); fprintf(stderr, "Input Options:\n"); fprintf(stderr, "\t-n Display the current date/time\n"); fprintf(stderr, "\t-d Parse an ISO8601 date/time. Eg. '2005-01-20 00:30:00 +01:00' or '2005-040'\n"); fprintf(stderr, "\t-p Parse an ISO8601 date/time interval/period (wth start time). Eg. '2005-040/2005-043'\n"); fprintf(stderr, "\t-D Parse an ISO8601 date/time duration (wth start time). Eg. '2005-040/P1M'\n"); fprintf(stderr, "\nOutput Options:\n"); fprintf(stderr, "\tBy default, shows the result in 'universal' date/time\n"); fprintf(stderr, "\t-L Show result as a 'local' date/time\n"); fprintf(stderr, "\t-O Show result as an 'ordinal' date/time\n"); fprintf(stderr, "\t-W Show result as an 'calendar week' date/time\n"); fprintf(stderr, "\nFor more information on the ISO8601 standard, see: http://en.wikipedia.org/wiki/ISO_8601\n"); exit(rc); } int main(int argc, char **argv) { int argerr = 0; int flag; int print_options = 0; char *input_s = NULL; char *mutable_s = NULL; - crm_log_init("iso8601", FALSE); - cl_log_set_facility(LOG_USER); - cl_log_enable_stderr(TRUE); + crm_log_init("iso8601", LOG_INFO, FALSE, TRUE, 0, NULL); if(argc < 2) { argerr++; } while (1) { flag = getopt(argc, argv, OPTARGS); if (flag == -1) break; switch(flag) { case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case '?': usage(0); break; case 'n': command = flag; break; case 'd': case 'p': case 'D': command = flag; input_s = crm_strdup(optarg); break; case 'W': print_options |= ha_date_weeks; break; case 'O': print_options |= ha_date_ordinal; break; case 'L': print_options |= ha_log_local; break; } } if(input_s == NULL && command != 'n') { usage(1); } mutable_s = input_s; if(command == 'd') { ha_time_t *date_time = parse_date(&mutable_s); if(date_time == NULL) { fprintf(stderr, "Invalid date/time specified: %s\n", input_s); usage(1); } log_date(LOG_INFO, "parsed", date_time, print_options|ha_log_date|ha_log_time); } else if(command == 'p') { ha_time_period_t *interval = parse_time_period(&mutable_s); if(interval == NULL) { fprintf(stderr, "Invalid interval specified: %s\n", input_s); usage(1); } log_time_period(LOG_INFO, interval, print_options|ha_log_date|ha_log_time); } else if(command == 'D') { ha_time_t *duration = parse_time_duration(&mutable_s); if(duration == NULL) { fprintf(stderr, "Invalid duration specified: %s\n", input_s); usage(1); } log_date(LOG_INFO, "Duration", duration, print_options|ha_log_date|ha_log_time|ha_log_local); } else if(command == 'n') { ha_time_t *now = new_ha_date(TRUE); if(now == NULL) { fprintf(stderr, "Internal error: couldnt determin 'now' !\n"); usage(1); } log_date(LOG_INFO, "Current date/time", now, print_options|ha_log_date|ha_log_time); } return 0; } diff --git a/crm/cib/cibmon.c b/crm/cib/cibmon.c index d8e1226de4..3a68745d28 100644 --- a/crm/cib/cibmon.c +++ b/crm/cib/cibmon.c @@ -1,471 +1,468 @@ /* * 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 #ifdef HAVE_GETOPT_H # include #endif #include /* someone complaining about _ha_msg_mod not being found */ #define UPDATE_PREFIX "cib.updates:" int exit_code = cib_ok; int got_signal = 0; GMainLoop *mainloop = NULL; const char *crm_system_name = "cibmon"; void usage(const char *cmd, int exit_status); void cib_connection_destroy(gpointer user_data); void cibmon_pre_notify(const char *event, HA_Message *msg); void cibmon_update_confirm(const char *event, HA_Message *msg); gboolean cibmon_shutdown(int nsig, gpointer unused); void cibmon_diff(const char *event, HA_Message *msg); cib_t *the_cib = NULL; #define OPTARGS "V?pPdam:" gboolean pre_notify = FALSE; gboolean post_notify = FALSE; gboolean log_diffs = FALSE; int max_failures = 30; int main(int argc, char **argv) { int argerr = 0; int flag; int level = 0; int attempts = 0; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"pre", 0, 0, 'p'}, {"post", 0, 0, 'P'}, {"all", 0, 0, 'a'}, {"diffs", 0, 0, 'd'}, {"max-conn-fail",1, 0, 'm'}, {0, 0, 0, 0} }; #endif - crm_log_init(crm_system_name, TRUE); + crm_log_init(crm_system_name, LOG_INFO, FALSE, FALSE, 0, NULL); G_main_add_SignalHandler( G_PRIORITY_HIGH, SIGTERM, cibmon_shutdown, NULL, NULL); - - cl_set_corerootdir(HA_COREDIR); - cl_cdtocoredir(); 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"); printf("Long option (--%s) is not" " (yet?) properly supported\n", long_options[option_index].name); ++argerr; break; #endif case 'V': level = get_crm_log_level(); cl_log_enable_stderr(TRUE); set_crm_log_level(level+1); break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'm': max_failures = crm_parse_int(optarg, "30"); break; case 'a': pre_notify = TRUE; post_notify = TRUE; log_diffs = TRUE; break; case 'd': log_diffs = TRUE; break; case 'p': pre_notify = TRUE; break; case 'P': post_notify = 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); } the_cib = cib_new(); do { if(attempts != 0) { sleep(1); } exit_code = the_cib->cmds->signon( the_cib, crm_system_name, cib_query); } while(exit_code == cib_connection && attempts++ < max_failures); if(exit_code != cib_ok) { crm_err("Signon to CIB failed: %s", cib_error2string(exit_code)); } if(exit_code == cib_ok) { crm_debug("Setting dnotify"); exit_code = the_cib->cmds->set_connection_dnotify( the_cib, cib_connection_destroy); } if(exit_code == cib_ok && pre_notify) { crm_debug("Setting pre-notify callback"); exit_code = the_cib->cmds->add_notify_callback( the_cib, T_CIB_PRE_NOTIFY, cibmon_pre_notify); if(exit_code != cib_ok) { crm_err("Failed to set %s callback: %s", T_CIB_PRE_NOTIFY, cib_error2string(exit_code)); } } if(exit_code == cib_ok && post_notify) { crm_debug("Setting post-notify callback"); exit_code = the_cib->cmds->add_notify_callback( the_cib, T_CIB_UPDATE_CONFIRM, cibmon_update_confirm); if(exit_code != cib_ok) { crm_err("Failed to set %s callback: %s", T_CIB_UPDATE_CONFIRM, cib_error2string(exit_code)); } } if(exit_code == cib_ok && log_diffs) { crm_debug("Setting diff callback"); exit_code = the_cib->cmds->add_notify_callback( the_cib, T_CIB_DIFF_NOTIFY, cibmon_diff); if(exit_code != cib_ok) { crm_err("Failed to set %s callback: %s", T_CIB_DIFF_NOTIFY, cib_error2string(exit_code)); } } if(exit_code != cib_ok) { crm_err("Setup failed, could not monitor CIB actions"); return -exit_code; } mainloop = g_main_new(FALSE); crm_info("Starting mainloop"); g_main_run(mainloop); crm_debug_3("%s exiting normally", crm_system_name); fflush(stderr); return -exit_code; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status != 0 ? stderr : stdout; #if 0 fprintf(stream, "usage: %s [-?Vio] command\n" "\twhere necessary, XML data will be expected using -X" " or on STDIN if -X isnt specified\n", cmd); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c) \tid of the object being operated on\n", XML_ATTR_ID, 'i'); fprintf(stream, "\t--%s (-%c) \tobject type being operated on\n", "obj_type", 'o'); 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)\t\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)\t\n", CIB_OP_REPLACE,'R'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_UPDATE, 'U'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_DELETE, 'D'); 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\n", F_CRM_DATA, 'X'); 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, CRM_OP_CIB_SYNC); fprintf(stream, "\t--%s (-%c)\tcommand only takes effect locally" " on the specified host\n", "local", 'l'); fprintf(stream, "\t--%s (-%c)\twait for call to complete before" " returning\n", "sync-call", 's'); #endif fflush(stream); exit(exit_status); } void cib_connection_destroy(gpointer user_data) { crm_err("Connection to the CIB terminated... exiting"); g_main_quit(mainloop); return; } int update_depth = 0; gboolean last_notify_pre = TRUE; void cibmon_pre_notify(const char *event, HA_Message *msg) { int rc = -1; const char *op = NULL; const char *id = NULL; const char *type = NULL; crm_data_t *update = NULL; crm_data_t *pre_update = NULL; if(msg == NULL) { crm_err("NULL update"); return; } op = cl_get_string(msg, F_CIB_OPERATION); id = cl_get_string(msg, F_CIB_OBJID); type = cl_get_string(msg, F_CIB_OBJTYPE); ha_msg_value_int(msg, F_CIB_RC, &rc); update_depth++; last_notify_pre = TRUE; update = get_message_xml(msg, F_CIB_UPDATE); pre_update = get_message_xml(msg, F_CIB_EXISTING); if(update != NULL) { crm_debug_3(UPDATE_PREFIX"[%s] Performing %s on <%s%s%s>", event, op, type, id?" id=":"", id?id:""); print_xml_formatted(LOG_DEBUG_5, UPDATE_PREFIX, update, "Update"); } else if(update == NULL) { crm_info(UPDATE_PREFIX"[%s] Performing operation %s (on section=%s)", event, op, crm_str(type)); } print_xml_formatted(LOG_DEBUG_3, UPDATE_PREFIX, pre_update, "Existing Object"); free_xml(update); free_xml(pre_update); } void cibmon_update_confirm(const char *event, HA_Message *msg) { int rc = -1; const char *op = NULL; const char *id = NULL; const char *type = NULL; crm_data_t *update = NULL; crm_data_t *output = NULL; crm_data_t *generation = NULL; if(msg == NULL) { crm_err("NULL update"); return; } op = cl_get_string(msg, F_CIB_OPERATION); id = cl_get_string(msg, F_CIB_OBJID); type = cl_get_string(msg, F_CIB_OBJTYPE); update_depth--; last_notify_pre = FALSE; ha_msg_value_int(msg, F_CIB_RC, &rc); update = get_message_xml(msg, F_CIB_UPDATE); output = get_message_xml(msg, F_CIB_UPDATE_RESULT); generation = get_message_xml(msg, "cib_generation"); if(update == NULL) { if(rc == cib_ok) { crm_debug_2(UPDATE_PREFIX"[%s] %s (to %s) confirmed", event, op, crm_str(type)); } else { crm_warn(UPDATE_PREFIX"[%s] %s (to %s) ABORTED: (%d) %s", event, op, crm_str(type), rc, cib_error2string(rc)); } } else { if(rc == cib_ok) { crm_debug_2(UPDATE_PREFIX"[%s] Operation %s to <%s%s%s> confirmed.", event, op, crm_str(type), id?" id=":"", id?id:""); } else { crm_warn(UPDATE_PREFIX"[%s] Operation %s to <%s %s%s> ABORTED: (%d) %s", event, op, crm_str(type), id?" id=":"", id?id:"", rc, cib_error2string(rc)); } } if(update != NULL) { print_xml_formatted( rc==cib_ok?LOG_DEBUG:LOG_WARNING, UPDATE_PREFIX, update, "Update"); } print_xml_formatted( rc==cib_ok?LOG_DEBUG_3:LOG_WARNING, UPDATE_PREFIX, output, "Resulting Object"); if(update_depth == 0) { print_xml_formatted( rc==cib_ok?LOG_DEBUG:LOG_WARNING, UPDATE_PREFIX, generation, "CIB Generation"); } free_xml(update); free_xml(output); free_xml(generation); } void cibmon_diff(const char *event, HA_Message *msg) { int rc = -1; const char *op = NULL; crm_data_t *diff = NULL; crm_data_t *update = get_message_xml(msg, F_CIB_UPDATE); unsigned int log_level = LOG_INFO; 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); diff = get_message_xml(msg, F_CIB_UPDATE_RESULT); if(rc < cib_ok) { log_level = LOG_WARNING; do_crm_log(log_level, "[%s] %s ABORTED: %s", event, op, cib_error2string(rc)); } else { do_crm_log(log_level, "[%s] %s confirmed", event, op); } log_cib_diff(log_level, diff, op); if(update != NULL) { print_xml_formatted( log_level+2, "raw_update", update, NULL); } free_xml(diff); free_xml(update); } gboolean cibmon_shutdown(int nsig, gpointer unused) { got_signal = 1; if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); } else { exit(LSB_EXIT_OK); } return TRUE; } diff --git a/crm/cib/main.c b/crm/cib/main.c index 8ae96c62b9..f46e1fb4d2 100644 --- a/crm/cib/main.c +++ b/crm/cib/main.c @@ -1,607 +1,607 @@ /* * 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 #if HAVE_LIBXML2 # include #endif #ifdef HAVE_GETOPT_H # include #endif extern int init_remote_listener(int port); gboolean cib_shutdown_flag = FALSE; gboolean stand_alone = FALSE; gboolean per_action_cib = FALSE; enum cib_errors cib_status = cib_ok; extern char *ccm_transition_id; extern void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int ); GMainLoop* mainloop = NULL; const char* crm_system_name = CRM_SYSTEM_CIB; const char* cib_root = WORKING_DIR; char *cib_our_uname = NULL; oc_ev_t *cib_ev_token; gboolean preserve_status = FALSE; gboolean cib_writes_enabled = TRUE; void usage(const char* cmd, int exit_status); int cib_init(void); gboolean cib_register_ha(ll_cluster_t *hb_cluster, const char *client_name); gboolean cib_shutdown(int nsig, gpointer unused); void cib_ha_connection_destroy(gpointer user_data); gboolean startCib(const char *filename); extern gboolean cib_msg_timeout(gpointer data); extern int write_cib_contents(gpointer p); GHashTable *client_list = NULL; GHashTable *ccm_membership = NULL; GHashTable *peer_hash = NULL; ll_cluster_t *hb_conn = NULL; GTRIGSource *cib_writer = NULL; char *channel1 = NULL; char *channel2 = NULL; char *channel3 = NULL; char *channel4 = NULL; char *channel5 = NULL; #define OPTARGS "aswr:V?" void cib_cleanup(void); static void cib_diskwrite_complete(gpointer userdata, int status, int signo, int exitcode) { if(exitcode != LSB_EXIT_OK || signo != 0 || status != 0) { crm_err("Disk write failed: status=%d, signo=%d, exitcode=%d", status, signo, exitcode); if(cib_writes_enabled) { crm_err("Disabling disk writes after write failure"); cib_writes_enabled = FALSE; } } else { crm_debug_2("Disk write passed"); } } int main(int argc, char ** argv) { int flag; int rc = 0; int argerr = 0; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { {"per-action-cib", 0, 0, 'a'}, {"stand-alone", 0, 0, 's'}, {"disk-writes", 0, 0, 'w'}, {"cib-root", 1, 0, 'r'}, {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {0, 0, 0, 0} }; #endif - crm_log_init(crm_system_name, TRUE); + crm_log_init(crm_system_name, LOG_INFO, TRUE, FALSE, 0, NULL); G_main_add_SignalHandler( G_PRIORITY_HIGH, SIGTERM, cib_shutdown, NULL, NULL); cib_writer = G_main_add_tempproc_trigger( G_PRIORITY_LOW, write_cib_contents, "write_cib_contents", NULL, NULL, NULL, cib_diskwrite_complete); EnableProcLogging(); set_sigchld_proctrack(G_PRIORITY_HIGH); client_list = g_hash_table_new(g_str_hash, g_str_equal); ccm_membership = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, NULL); peer_hash = g_hash_table_new_full( g_str_hash, g_str_equal,g_hash_destroy_str, g_hash_destroy_str); 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': alter_debug(DEBUG_INC); break; case 's': stand_alone = TRUE; preserve_status = TRUE; cib_writes_enabled = FALSE; cl_log_enable_stderr(1); break; case '?': /* Help message */ usage(crm_system_name, LSB_EXIT_OK); break; case 'f': per_action_cib = TRUE; break; case 'w': cib_writes_enabled = TRUE; break; case 'r': cib_root = optarg; break; default: ++argerr; break; } } crm_info("Retrieval of a per-action CIB: %s", per_action_cib?"enabled":"disabled"); if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name,LSB_EXIT_GENERIC); } /* read local config file */ rc = cib_init(); CRM_CHECK(g_hash_table_size(client_list) == 0, crm_warn("Not all clients gone at exit")); cib_cleanup(); if(hb_conn) { hb_conn->llc_ops->delete(hb_conn); } crm_info("Done"); return rc; } void cib_cleanup(void) { g_hash_table_destroy(ccm_membership); g_hash_table_destroy(client_list); g_hash_table_destroy(peer_hash); crm_free(ccm_transition_id); crm_free(cib_our_uname); #if HAVE_LIBXML2 xmlCleanupParser(); #endif crm_free(channel1); crm_free(channel2); crm_free(channel3); crm_free(channel4); crm_free(channel5); } unsigned long cib_num_ops = 0; const char *cib_stat_interval = "10min"; unsigned long cib_num_local = 0, cib_num_updates = 0, cib_num_fail = 0; unsigned long cib_bad_connects = 0, cib_num_timeouts = 0; longclock_t cib_call_time = 0; gboolean cib_stats(gpointer data); gboolean cib_stats(gpointer data) { int local_log_level = LOG_DEBUG; static unsigned long last_stat = 0; unsigned int cib_calls_ms = 0; static unsigned long cib_stat_interval_ms = 0; if(cib_stat_interval_ms == 0) { cib_stat_interval_ms = crm_get_msec(cib_stat_interval); } cib_calls_ms = longclockto_ms(cib_call_time); if((cib_num_ops - last_stat) > 0) { unsigned long calls_diff = cib_num_ops - last_stat; double stat_1 = (1000*cib_calls_ms)/calls_diff; local_log_level = LOG_INFO; do_crm_log(local_log_level, "Processed %lu operations" " (%.2fus average, %lu%% utilization) in the last %s", calls_diff, stat_1, (100*cib_calls_ms)/cib_stat_interval_ms, cib_stat_interval); } do_crm_log(local_log_level+1, "\tDetail: %lu operations (%ums total)" " (%lu local, %lu updates, %lu failures," " %lu timeouts, %lu bad connects)", cib_num_ops, cib_calls_ms, cib_num_local, cib_num_updates, cib_num_fail, cib_bad_connects, cib_num_timeouts); last_stat = cib_num_ops; cib_call_time = 0; return TRUE; } int cib_init(void) { gboolean was_error = FALSE; if(startCib("cib.xml") == FALSE){ crm_crit("Cannot start CIB... terminating"); exit(1); } if(stand_alone == FALSE) { hb_conn = ll_cluster_new("heartbeat"); if(cib_register_ha(hb_conn, CRM_SYSTEM_CIB) == FALSE) { crm_crit("Cannot sign in to heartbeat... terminating"); exit(1); } } else { cib_our_uname = crm_strdup("localhost"); } channel1 = crm_strdup(cib_channel_callback); was_error = init_server_ipc_comms( channel1, cib_client_connect_null, default_ipc_connection_destroy); channel2 = crm_strdup(cib_channel_ro); was_error = was_error || init_server_ipc_comms( channel2, cib_client_connect_rw_ro, default_ipc_connection_destroy); channel3 = crm_strdup(cib_channel_rw); was_error = was_error || init_server_ipc_comms( channel3, cib_client_connect_rw_ro, default_ipc_connection_destroy); channel4 = crm_strdup(cib_channel_rw_synchronous); was_error = was_error || init_server_ipc_comms( channel4, cib_client_connect_rw_synch, default_ipc_connection_destroy); channel5 = crm_strdup(cib_channel_ro_synchronous); was_error = was_error || init_server_ipc_comms( channel5, cib_client_connect_ro_synch, default_ipc_connection_destroy); if(stand_alone) { if(was_error) { crm_err("Couldnt start"); return 1; } cib_is_master = TRUE; /* Create the mainloop and run it... */ mainloop = g_main_new(FALSE); crm_info("Starting %s mainloop", crm_system_name); /* Gmain_timeout_add(crm_get_msec("10s"), cib_msg_timeout, NULL); */ /* Gmain_timeout_add( */ /* crm_get_msec(cib_stat_interval), cib_stats, NULL); */ g_main_run(mainloop); return_to_orig_privs(); return 0; } if(was_error == FALSE) { crm_debug_3("Be informed of CRM Client Status changes"); if (HA_OK != hb_conn->llc_ops->set_cstatus_callback( hb_conn, cib_client_status_callback, hb_conn)) { crm_err("Cannot set cstatus callback: %s", hb_conn->llc_ops->errmsg(hb_conn)); was_error = TRUE; } else { crm_debug_3("Client Status callback set"); } } if(was_error == FALSE) { gboolean did_fail = TRUE; int num_ccm_fails = 0; int max_ccm_fails = 30; int ret; int cib_ev_fd; while(did_fail && was_error == FALSE) { did_fail = FALSE; crm_debug_3("Registering with CCM"); ret = oc_ev_register(&cib_ev_token); if (ret != 0) { did_fail = TRUE; } if(did_fail == FALSE) { crm_debug_3("Setting up CCM callbacks"); ret = oc_ev_set_callback( cib_ev_token, OC_EV_MEMB_CLASS, cib_ccm_msg_callback, NULL); if (ret != 0) { crm_warn("CCM callback not set"); did_fail = TRUE; } } if(did_fail == FALSE) { oc_ev_special(cib_ev_token, OC_EV_MEMB_CLASS, 0); crm_debug_3("Activating CCM token"); ret = oc_ev_activate(cib_ev_token, &cib_ev_fd); if (ret != 0){ crm_warn("CCM Activation failed"); did_fail = TRUE; } } if(did_fail) { num_ccm_fails++; oc_ev_unregister(cib_ev_token); if(num_ccm_fails < max_ccm_fails){ crm_warn("CCM Connection failed" " %d times (%d max)", num_ccm_fails, max_ccm_fails); sleep(1); } else { crm_err("CCM Activation failed" " %d (max) times", num_ccm_fails); was_error = TRUE; } } } if(was_error == FALSE) { crm_debug_3("CCM Activation passed... all set to go!"); G_main_add_fd(G_PRIORITY_HIGH, cib_ev_fd, FALSE, cib_ccm_dispatch, cib_ev_token, default_ipc_connection_destroy); } } if(was_error == FALSE) { /* Async get client status information in the cluster */ crm_debug_3("Requesting an initial dump of CIB client_status"); hb_conn->llc_ops->client_status( hb_conn, NULL, CRM_SYSTEM_CIB, -1); /* Create the mainloop and run it... */ mainloop = g_main_new(FALSE); crm_info("Starting %s mainloop", crm_system_name); Gmain_timeout_add(crm_get_msec("10s"), cib_msg_timeout, NULL); Gmain_timeout_add( crm_get_msec(cib_stat_interval), cib_stats, NULL); g_main_run(mainloop); return_to_orig_privs(); } else { crm_err("Couldnt start all communication channels, exiting."); } return 0; } 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\tTurn on debug info." " Additional instances increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\t\tThis help message\n", "help", '?'); fprintf(stream, "\t--%s (-%c)\tAdvanced use only\n", "per-action-cib", 'a'); fprintf(stream, "\t--%s (-%c)\tAdvanced use only\n", "stand-alone", 's'); fprintf(stream, "\t--%s (-%c)\tAdvanced use only\n", "disk-writes", 'w'); fprintf(stream, "\t--%s (-%c)\t\tAdvanced use only\n", "cib-root", 'r'); fflush(stream); exit(exit_status); } gboolean cib_register_ha(ll_cluster_t *hb_cluster, const char *client_name) { const char *uname = NULL; crm_info("Signing in with Heartbeat"); if (hb_cluster->llc_ops->signon(hb_cluster, client_name)!= HA_OK) { crm_err("Cannot sign on with heartbeat: %s", hb_cluster->llc_ops->errmsg(hb_cluster)); return FALSE; } crm_debug_3("Be informed of CIB messages"); if (HA_OK != hb_cluster->llc_ops->set_msg_callback( hb_cluster, T_CIB, cib_peer_callback, hb_cluster)){ crm_err("Cannot set msg callback: %s", hb_cluster->llc_ops->errmsg(hb_cluster)); return FALSE; } crm_debug_3("Finding our node name"); if ((uname = hb_cluster->llc_ops->get_mynodeid(hb_cluster)) == NULL) { crm_err("get_mynodeid() failed"); return FALSE; } cib_our_uname = crm_strdup(uname); crm_info("FSA Hostname: %s", cib_our_uname); crm_debug_3("Adding channel to mainloop"); G_main_add_IPC_Channel( G_PRIORITY_DEFAULT, hb_cluster->llc_ops->ipcchan(hb_cluster), FALSE, cib_ha_dispatch, hb_cluster /* userdata */, cib_ha_connection_destroy); return TRUE; } void cib_ha_connection_destroy(gpointer user_data) { if(cib_shutdown_flag) { crm_info("Heartbeat disconnection complete... exiting"); } else { crm_err("Heartbeat connection lost! Exiting."); } uninitializeCib(); if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); } else { exit(LSB_EXIT_OK); } } static void disconnect_cib_client(gpointer key, gpointer value, gpointer user_data) { cib_client_t *a_client = value; crm_debug_2("Processing client %s/%s... send=%d, recv=%d", crm_str(a_client->name), crm_str(a_client->channel_name), (int)a_client->channel->send_queue->current_qlen, (int)a_client->channel->recv_queue->current_qlen); if(a_client->channel->ch_status == IPC_CONNECT) { a_client->channel->ops->resume_io(a_client->channel); if(a_client->channel->send_queue->current_qlen != 0 || a_client->channel->recv_queue->current_qlen != 0) { crm_info("Flushed messages to/from %s/%s... send=%d, recv=%d", crm_str(a_client->name), crm_str(a_client->channel_name), (int)a_client->channel->send_queue->current_qlen, (int)a_client->channel->recv_queue->current_qlen); } } if(a_client->channel->ch_status == IPC_CONNECT) { crm_warn("Disconnecting %s/%s...", crm_str(a_client->name), crm_str(a_client->channel_name)); a_client->channel->ops->disconnect(a_client->channel); } } extern gboolean cib_process_disconnect( IPC_Channel *channel, cib_client_t *cib_client); gboolean cib_shutdown(int nsig, gpointer unused) { if(cib_shutdown_flag == FALSE) { cib_shutdown_flag = TRUE; crm_debug("Disconnecting %d clients", g_hash_table_size(client_list)); g_hash_table_foreach(client_list, disconnect_cib_client, NULL); crm_info("Disconnected %d clients", g_hash_table_size(client_list)); cib_process_disconnect(NULL, NULL); } else { crm_info("Waiting for %d clients to disconnect...", g_hash_table_size(client_list)); } return TRUE; } gboolean startCib(const char *filename) { gboolean active = FALSE; crm_data_t *cib = readCibXmlFile(cib_root, filename, !preserve_status); CRM_ASSERT(cib != NULL); if(activateCibXml(cib, TRUE) == 0) { int port = 0; active = TRUE; ha_msg_value_int(cib, "remote_access_port", &port); init_remote_listener(port); crm_info("CIB Initialization completed successfully"); if(per_action_cib) { uninitializeCib(); } } return active; } diff --git a/crm/crmd/main.c b/crm/crmd/main.c index 905e22f538..3ab82bfbb5 100644 --- a/crm/crmd/main.c +++ b/crm/crmd/main.c @@ -1,206 +1,206 @@ /* * 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 #include const char* crm_system_name = SYS_NAME; #define OPTARGS "hV" void usage(const char* cmd, int exit_status); int crmd_init(void); void crmd_hamsg_callback(const HA_Message * msg, void* private_data); gboolean crmd_tickle_apphb(gpointer data); extern void init_dotfile(void); GMainLoop* crmd_mainloop = NULL; int main(int argc, char ** argv) { int flag; int argerr = 0; - crm_log_init(crm_system_name, TRUE); + crm_log_init(crm_system_name, LOG_INFO, TRUE, FALSE, 0, NULL); crm_info("CRM Hg Version: %s\n", HA_HG_VERSION); 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(crm_system_name, LSB_EXIT_OK); break; default: ++argerr; break; } } if(argc - optind == 1 && safe_str_eq("metadata", argv[optind])) { crmd_metadata(); return 0; } else if(argc - optind == 1 && safe_str_eq("version", argv[optind])) { fprintf(stderr, "CRM Version: "); fprintf(stdout, "%s (%s)\n", VERSION, HA_HG_VERSION); return 0; } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name,LSB_EXIT_GENERIC); } /* read local config file */ crm_debug_3("Enabling coredumps"); if(cl_enable_coredumps(1) != 0) { crm_warn("Cannot enable coredumps"); } if(crm_is_writable(HA_VARLIBDIR"/heartbeat/pengine", NULL, HA_CCMUSER, HA_APIGROUP, FALSE) == FALSE) { fprintf(stderr,"ERROR: Bad permissions on " HA_VARLIBDIR"/heartbeat/pengine... See logs for details\n"); fflush(stderr); return 100; } return crmd_init(); } int crmd_init(void) { int exit_code = 0; enum crmd_fsa_state state; fsa_state = S_STARTING; fsa_input_register = 0; /* zero out the regester */ init_dotfile(); crm_info("Starting %s", crm_system_name); register_fsa_input(C_STARTUP, I_STARTUP, NULL); state = s_crmd_fsa(C_STARTUP); if (state == S_PENDING || state == S_STARTING) { /* Create the mainloop and run it... */ crmd_mainloop = g_main_new(FALSE); crm_info("Starting %s's mainloop", crm_system_name); #ifdef REALTIME_SUPPORT static int crm_realtime = 1; if (crm_realtime == 1){ cl_enable_realtime(); }else if (crm_realtime == 0){ cl_disable_realtime(); } cl_make_realtime(SCHED_RR, 5, 64, 64); #endif g_main_run(crmd_mainloop); return_to_orig_privs(); if(is_set(fsa_input_register, R_STAYDOWN)) { crm_info("Inhibiting respawn by Heartbeat"); exit_code = 100; } } else { crm_err("Startup of %s failed. Current state: %s", crm_system_name, fsa_state2string(state)); exit_code = 1; } crm_info("[%s] stopped (%d)", crm_system_name, exit_code); return exit_code; } void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-V] [-h|version|metadata]\n", cmd); fprintf(stream, "\t-h\t: this help message\n"); fprintf(stream, "\t-V\t: increase verbosity\n"); fprintf(stream, "\tmetadata\t: show configurable crmd options\n"); fprintf(stream, "\tversion\t\t: show version information and quit\n"); fflush(stream); exit(exit_status); } gboolean crmd_tickle_apphb(gpointer data) { char app_instance[APPNAME_LEN]; int rc = 0; snprintf(app_instance, sizeof(app_instance), "%s_%ld", crm_system_name , (long)getpid()); rc = apphb_hb(); if (rc < 0) { cl_perror("%s apphb_hb failure", app_instance); exit(3); } return TRUE; } diff --git a/crm/pengine/main.c b/crm/pengine/main.c index e7340efabe..5a700370b3 100644 --- a/crm/pengine/main.c +++ b/crm/pengine/main.c @@ -1,179 +1,179 @@ /* * 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 #if HAVE_LIBXML2 # include #endif #define SYS_NAME CRM_SYSTEM_PENGINE #define OPTARGS "hVc" GMainLoop* mainloop = NULL; const char* crm_system_name = SYS_NAME; void usage(const char* cmd, int exit_status); int pe_init(void); gboolean pengine_shutdown(int nsig, gpointer unused); extern gboolean process_pe_message(crm_data_t * msg, IPC_Channel *sender); extern unsigned int pengine_input_loglevel; int main(int argc, char ** argv) { int flag; int argerr = 0; char *param_val = NULL; gboolean allow_cores = TRUE; const char *param_name = NULL; - crm_log_init(crm_system_name, TRUE); + crm_log_init(crm_system_name, LOG_INFO, TRUE, FALSE, 0, NULL); G_main_add_SignalHandler( G_PRIORITY_HIGH, SIGTERM, pengine_shutdown, NULL, NULL); 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; } } if(argc - optind == 1 && safe_str_eq("metadata", argv[optind])) { pe_metadata(); return 0; } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name,LSB_EXIT_GENERIC); } param_name = ENV_PREFIX "" KEY_LOG_PENGINE_INPUTS; param_val = getenv(param_name); crm_debug("%s = %s", param_name, param_val); pengine_input_loglevel = crm_log_level; if(param_val != NULL) { int do_log = 0; cl_str_to_boolean(param_val, &do_log); if(do_log == FALSE) { pengine_input_loglevel = crm_log_level + 1; } param_val = NULL; } /* read local config file */ crm_debug_4("do start"); return pe_init(); } int pe_init(void) { IPC_Channel *crm_ch = NULL; crm_debug_4("initialize comms"); init_client_ipc_comms( CRM_SYSTEM_CRMD, subsystem_msg_dispatch, (void*)process_pe_message, &crm_ch); if(crm_ch != NULL) { crm_debug_4("sending hello message"); send_hello_message( crm_ch, "1234", CRM_SYSTEM_PENGINE, "0", "1"); /* 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(); #if HAVE_LIBXML2 xmlCleanupParser(); #endif crm_info("Exiting %s", crm_system_name); return 0; } crm_err("Could not connect to the CRMd"); 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 pengine_shutdown(int nsig, gpointer unused) { crm_info("Exiting PEngine (SIGTERM)"); exit(LSB_EXIT_OK); } diff --git a/crm/tengine/main.c b/crm/tengine/main.c index 3dff05e718..f9ad278c7e 100644 --- a/crm/tengine/main.c +++ b/crm/tengine/main.c @@ -1,259 +1,259 @@ /* * 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 SYS_NAME CRM_SYSTEM_TENGINE #define OPTARGS "hVc" GMainLoop* mainloop = NULL; const char* crm_system_name = SYS_NAME; cib_t *te_cib_conn = NULL; extern GTRIGSource *transition_trigger; extern crm_action_timer_t *transition_timer; 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 argerr = 0; gboolean allow_cores = TRUE; - crm_log_init(crm_system_name, TRUE); + crm_log_init(crm_system_name, 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); 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(init_ok && ST_OK != stonithd_signon(crm_system_name)) { crm_err("Could not sign up to stonithd"); /* init_ok = FALSE; */ } if(init_ok && ST_OK != stonithd_set_stonith_ops_callback( tengine_stonith_callback)) { crm_err("Could not set stonith callback"); stonithd_signoff(); /* init_ok = FALSE; */ } if(init_ok) { IPC_Channel *fence_ch = stonithd_input_IPC_channel(); if(fence_ch == NULL) { } else if(NULL == G_main_add_IPC_Channel( G_PRIORITY_LOW, fence_ch, FALSE, tengine_stonith_dispatch, NULL, tengine_stonith_connection_destroy)) { crm_err("Failed to add Fencing channel to our mainloop"); init_ok = FALSE; } } 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; stonithd_signoff(); 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; } diff --git a/include/crm/common/util.h b/include/crm/common/util.h index 63cadbaac2..f13ce18e5c 100644 --- a/include/crm/common/util.h +++ b/include/crm/common/util.h @@ -1,176 +1,178 @@ /* * 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 */ #ifndef CRM_COMMON_UTIL__H #define CRM_COMMON_UTIL__H #include #include #include #include #include #define DEBUG_INC SIGUSR1 #define DEBUG_DEC SIGUSR2 extern unsigned int crm_log_level; extern gboolean crm_config_error; extern gboolean crm_config_warning; #define crm_config_err(fmt...) { crm_config_error = TRUE; crm_err(fmt); } #define crm_config_warn(fmt...) { crm_config_warning = TRUE; crm_warn(fmt); } -extern gboolean crm_log_init(const char *entity, gboolean coredir); +extern gboolean crm_log_init( + const char *entity, int level, gboolean coredir, gboolean to_stderr, + int argc, char **argv); /* returns the old value */ extern unsigned int set_crm_log_level(unsigned int level); extern unsigned int get_crm_log_level(void); extern char *crm_itoa(int an_int); extern char *crm_strdup_fn(const char *a, const char *file, const char *fn, int line); extern char *generate_hash_key(const char *crm_msg_reference, const char *sys); extern char *generate_hash_value(const char *src_node, const char *src_subsys); extern gboolean decodeNVpair(const char *srcstring, char separator, char **name, char **value); extern int compare_version(const char *version1, const char *version2); extern char *generateReference(const char *custom1, const char *custom2); extern void alter_debug(int nsig); extern void g_hash_destroy_str(gpointer data); extern void empty_uuid_cache(void); extern const char *get_uuid(ll_cluster_t *hb, const char *uname); extern const char *get_uname(ll_cluster_t *hb, const char *uuid); extern void unget_uuid(const char *uname); extern void set_uuid( ll_cluster_t* hb, crm_data_t *node, const char *attr, const char *uname); extern gboolean crm_is_true(const char * s); extern int crm_str_to_boolean(const char * s, int * ret); extern long crm_get_msec(const char * input); extern gboolean ccm_have_quorum(oc_ed_t event); extern const char *ccm_event_name(oc_ed_t event); extern const char *op_status2text(op_status_t status); extern char *generate_op_key( const char *rsc_id, const char *op_type, int interval); extern gboolean parse_op_key( const char *key, char **rsc_id, char **op_type, int *interval); extern char *generate_notify_key( const char *rsc_id, const char *notify_type, const char *op_type); extern char *generate_transition_magic_v202( const char *transition_key, int op_status); extern char *generate_transition_magic( const char *transition_key, int op_status, int op_rc); extern gboolean decode_transition_magic( const char *magic, char **uuid, int *transition_id, int *action_id, int *op_status, int *op_rc); extern char *generate_transition_key(int action, int transition_id, const char *node); extern gboolean decode_transition_key( const char *key, char **uuid, int *action, int *transition_id); extern char *crm_concat(const char *prefix, const char *suffix, char join); extern gboolean decode_op_key( const char *key, char **rsc_id, char **op_type, int *interval); extern void filter_action_parameters(crm_data_t *param_set, const char *version); extern void filter_reload_parameters(crm_data_t *param_set, const char *restart_string); #define safe_str_eq(a, b) crm_str_eq(a, b, FALSE) extern gboolean crm_str_eq(const char *a, const char *b, gboolean use_case); extern gboolean safe_str_neq(const char *a, const char *b); extern int crm_parse_int(const char *text, const char *default_text); extern int crm_int_helper(const char *text, char **end_text); #define crm_atoi(text, default_text) crm_parse_int(text, default_text) extern void crm_abort(const char *file, const char *function, int line, const char *condition, gboolean do_fork); extern char *generate_series_filename( const char *directory, const char *series, int sequence, gboolean bzip); extern int get_last_sequence(const char *directory, const char *series); extern void write_last_sequence( const char *directory, const char *series, int sequence, int max); extern void crm_make_daemon( const char *name, gboolean daemonize, const char *pidfile); typedef struct pe_cluster_option_s { const char *name; const char *alt_name; const char *type; const char *values; const char *default_value; gboolean (*is_valid)(const char *); const char *description_short; const char *description_long; } pe_cluster_option; extern const char *cluster_option( GHashTable* options, gboolean(*validate)(const char*), const char *name, const char *old_name, const char *def_value); extern const char *get_cluster_pref( GHashTable *options, pe_cluster_option *option_list, int len, const char *name); extern void config_metadata( const char *name, const char *version, const char *desc_short, const char *desc_long, pe_cluster_option *option_list, int len); extern void verify_all_options(GHashTable *options, pe_cluster_option *option_list, int len); extern gboolean check_time(const char *value); extern gboolean check_timer(const char *value); extern gboolean check_boolean(const char *value); extern gboolean check_number(const char *value); extern int char2score(const char *score); extern char *score2char(int score); extern gboolean crm_is_writable( const char *dir, const char *file, const char *user, const char *group, gboolean need_both); #endif diff --git a/lib/crm/common/utils.c b/lib/crm/common/utils.c index 3837512dbf..d54a6f2c36 100644 --- a/lib/crm/common/utils.c +++ b/lib/crm/common/utils.c @@ -1,1728 +1,1734 @@ /* * 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 #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif #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 #ifndef MAXLINE # define MAXLINE 512 #endif static uint ref_counter = 0; gboolean crm_assert_failed = FALSE; unsigned int crm_log_level = LOG_INFO; gboolean crm_config_error = FALSE; gboolean crm_config_warning = FALSE; void crm_set_env_options(void); gboolean check_time(const char *value) { if(crm_get_msec(value) < 5000) { return FALSE; } return TRUE; } gboolean check_timer(const char *value) { if(crm_get_msec(value) < 0) { return FALSE; } return TRUE; } gboolean check_boolean(const char *value) { int tmp = FALSE; if(crm_str_to_boolean(value, &tmp) != 1) { return FALSE; } return TRUE; } gboolean check_number(const char *value) { errno = 0; if(value == NULL) { return FALSE; } else if(safe_str_eq(value, MINUS_INFINITY_S)) { } else if(safe_str_eq(value, INFINITY_S)) { } else { crm_int_helper(value, NULL); } if(errno != 0) { return FALSE; } return TRUE; } int char2score(const char *score) { int score_f = 0; if(score == NULL) { } else if(safe_str_eq(score, MINUS_INFINITY_S)) { score_f = -INFINITY; } else if(safe_str_eq(score, INFINITY_S)) { score_f = INFINITY; } else if(safe_str_eq(score, "+"INFINITY_S)) { score_f = INFINITY; } else { score_f = crm_parse_int(score, NULL); if(score_f > 0 && score_f > INFINITY) { score_f = INFINITY; } else if(score_f < 0 && score_f < -INFINITY) { score_f = -INFINITY; } } return score_f; } char * score2char(int score) { if(score >= INFINITY) { return crm_strdup("+"INFINITY_S); } else if(score <= -INFINITY) { return crm_strdup("-"INFINITY_S); } return crm_itoa(score); } const char * cluster_option(GHashTable* options, gboolean(*validate)(const char*), const char *name, const char *old_name, const char *def_value) { const char *value = NULL; CRM_ASSERT(name != NULL); if(options != NULL) { value = g_hash_table_lookup(options, name); } if(value == NULL && old_name && options != NULL) { value = g_hash_table_lookup(options, old_name); if(value != NULL) { crm_config_warn("Using deprecated name '%s' for" " cluster option '%s'", old_name, name); g_hash_table_insert( options, crm_strdup(name), crm_strdup(value)); value = g_hash_table_lookup(options, old_name); } } if(value == NULL) { crm_notice("Using default value '%s' for cluster option '%s'", def_value, name); if(options == NULL) { return def_value; } g_hash_table_insert( options, crm_strdup(name), crm_strdup(def_value)); value = g_hash_table_lookup(options, name); } if(validate && validate(value) == FALSE) { crm_config_err("Value '%s' for cluster option '%s' is invalid." " Defaulting to %s", value, name, def_value); g_hash_table_replace(options, crm_strdup(name), crm_strdup(def_value)); value = g_hash_table_lookup(options, name); } return value; } const char * get_cluster_pref(GHashTable *options, pe_cluster_option *option_list, int len, const char *name) { int lpc = 0; const char *value = NULL; gboolean found = FALSE; for(lpc = 0; lpc < len; lpc++) { if(safe_str_eq(name, option_list[lpc].name)) { found = TRUE; value = cluster_option(options, option_list[lpc].is_valid, option_list[lpc].name, option_list[lpc].alt_name, option_list[lpc].default_value); } } CRM_CHECK(found, crm_err("No option named: %s", name)); CRM_ASSERT(value != NULL); return value; } void config_metadata(const char *name, const char *version, const char *desc_short, const char *desc_long, pe_cluster_option *option_list, int len) { int lpc = 0; fprintf(stdout, "" "\n" "\n" " %s\n" " %s\n" " %s\n" " \n", name, version, desc_long, desc_short); for(lpc = 0; lpc < len; lpc++) { if(option_list[lpc].description_long == NULL && option_list[lpc].description_short == NULL) { continue; } fprintf(stdout, " \n" " %s\n" " \n" " %s%s%s\n" " \n", option_list[lpc].name, option_list[lpc].description_short, option_list[lpc].type, option_list[lpc].default_value, option_list[lpc].description_long?option_list[lpc].description_long:option_list[lpc].description_short, option_list[lpc].values?" Allowed values: ":"", option_list[lpc].values?option_list[lpc].values:""); } fprintf(stdout, " \n\n"); } void verify_all_options(GHashTable *options, pe_cluster_option *option_list, int len) { int lpc = 0; for(lpc = 0; lpc < len; lpc++) { cluster_option(options, option_list[lpc].is_valid, option_list[lpc].name, option_list[lpc].alt_name, option_list[lpc].default_value); } } char * generateReference(const char *custom1, const char *custom2) { const char *local_cust1 = custom1; const char *local_cust2 = custom2; int reference_len = 4; char *since_epoch = NULL; reference_len += 20; /* too big */ reference_len += 40; /* too big */ if(local_cust1 == NULL) { local_cust1 = "_empty_"; } reference_len += strlen(local_cust1); if(local_cust2 == NULL) { local_cust2 = "_empty_"; } reference_len += strlen(local_cust2); crm_malloc0(since_epoch, reference_len); if(since_epoch != NULL) { sprintf(since_epoch, "%s-%s-%ld-%u", local_cust1, local_cust2, (unsigned long)time(NULL), ref_counter++); } return since_epoch; } gboolean decodeNVpair(const char *srcstring, char separator, char **name, char **value) { int lpc = 0; int len = 0; const char *temp = NULL; CRM_ASSERT(name != NULL && value != NULL); *name = NULL; *value = NULL; crm_debug_4("Attempting to decode: [%s]", srcstring); if (srcstring != NULL) { len = strlen(srcstring); while(lpc <= len) { if (srcstring[lpc] == separator) { crm_malloc0(*name, lpc+1); if(*name == NULL) { break; /* and return FALSE */ } strncpy(*name, srcstring, lpc); (*name)[lpc] = '\0'; /* this sucks but as the strtok manpage says.. * it *is* a bug */ len = len-lpc; len--; if(len <= 0) { *value = NULL; } else { crm_malloc0(*value, len+1); if(*value == NULL) { crm_free(*name); break; /* and return FALSE */ } temp = srcstring+lpc+1; strncpy(*value, temp, len); (*value)[len] = '\0'; } return TRUE; } lpc++; } } if(*name != NULL) { crm_free(*name); } *name = NULL; *value = NULL; return FALSE; } char * crm_concat(const char *prefix, const char *suffix, char join) { int len = 0; char *new_str = NULL; CRM_ASSERT(prefix != NULL); CRM_ASSERT(suffix != NULL); len = strlen(prefix) + strlen(suffix) + 2; crm_malloc0(new_str, (len)); sprintf(new_str, "%s%c%s", prefix, join, suffix); new_str[len-1] = 0; return new_str; } char * generate_hash_key(const char *crm_msg_reference, const char *sys) { char *hash_key = crm_concat(sys?sys:"none", crm_msg_reference, '_'); crm_debug_3("created hash key: (%s)", hash_key); return hash_key; } char * generate_hash_value(const char *src_node, const char *src_subsys) { char *hash_value = NULL; if (src_node == NULL || src_subsys == NULL) { return NULL; } if (strcasecmp(CRM_SYSTEM_DC, src_subsys) == 0) { hash_value = crm_strdup(src_subsys); if (!hash_value) { crm_err("memory allocation failed in " "generate_hash_value()"); } return hash_value; } hash_value = crm_concat(src_node, src_subsys, '_'); crm_info("created hash value: (%s)", hash_value); return hash_value; } char * crm_itoa(int an_int) { int len = 32; char *buffer = NULL; crm_malloc0(buffer, (len+1)); if(buffer != NULL) { snprintf(buffer, len, "%d", an_int); } return buffer; } extern int LogToLoggingDaemon(int priority, const char * buf, int bstrlen, gboolean use_pri_str); gboolean -crm_log_init(const char *entity, gboolean coredir) +crm_log_init( + const char *entity, int level, gboolean coredir, gboolean to_stderr, + int argc, char **argv) { /* const char *test = "Testing log daemon connection"; */ /* Redirect messages from glib functions to our handler */ /* cl_malloc_forced_for_glib(); */ g_log_set_handler(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG | G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL, cl_glib_msg_handler, NULL); /* and for good measure... - this enum is a bit field (!) */ g_log_set_always_fatal((GLogLevelFlags)0); /*value out of range*/ cl_log_set_entity(entity); cl_log_set_facility(LOG_LOCAL7); if(coredir) { cl_set_corerootdir(HA_COREDIR); cl_cdtocoredir(); } + set_crm_log_level(level); crm_set_env_options(); + cl_log_args(argc, argv); + cl_log_enable_stderr(to_stderr); + CL_SIGNAL(DEBUG_INC, alter_debug); CL_SIGNAL(DEBUG_DEC, alter_debug); return TRUE; } /* returns the old value */ unsigned int set_crm_log_level(unsigned int level) { unsigned int old = crm_log_level; while(crm_log_level < 100 && crm_log_level < level) { alter_debug(DEBUG_INC); } while(crm_log_level > 0 && crm_log_level > level) { alter_debug(DEBUG_DEC); } return old; } unsigned int get_crm_log_level(void) { return crm_log_level; } void crm_log_message_adv(int level, const char *prefix, const HA_Message *msg) { if((int)crm_log_level >= level) { do_crm_log(level, "#========= %s message start ==========#", prefix?prefix:""); if(level > LOG_DEBUG) { cl_log_message(LOG_DEBUG, msg); } else { cl_log_message(level, msg); } } } int compare_version(const char *version1, const char *version2) { int rc = 0; int lpc = 0; char *step1 = NULL, *step2 = NULL; char *rest1 = NULL, *rest2 = NULL; if(version1 == NULL && version2 == NULL) { return 0; } else if(version1 == NULL) { return -1; } else if(version2 == NULL) { return 1; } rest1 = crm_strdup(version1); rest2 = crm_strdup(version2); while(1) { int cmp = 0; int step1_i = 0; int step2_i = 0; char *tmp1 = NULL, *tmp2 = NULL; decodeNVpair(rest1, '.', &step1, &tmp1); decodeNVpair(rest2, '.', &step2, &tmp2); if(step1 == NULL && step2 == NULL) { CRM_CHECK(tmp1 == tmp2 && tmp1 == NULL, crm_err("Leftover data: %s, %s", crm_str(tmp1), crm_str(tmp2))); crm_free(tmp1); crm_free(tmp2); break; } if(step1 != NULL) { step1_i = crm_parse_int(step1, NULL); } if(step2 != NULL) { step2_i = crm_parse_int(step2, NULL); } if(step1_i < step2_i){ cmp = -1; } else if (step1_i > step2_i){ cmp = 1; } crm_debug_4("compare[%d (%d)]: %d(%s) %d(%s)", lpc++, cmp, step1_i, crm_str(step1), step2_i, crm_str(step2)); crm_free(rest1); crm_free(rest2); crm_free(step1); crm_free(step2); rest1 = tmp1; rest2 = tmp2; if(cmp < 0) { rc = -1; break; } else if(cmp > 0) { rc = 1; break; } } crm_free(rest1); crm_free(rest2); if(rc == 0) { crm_debug_3("%s == %s", version1, version2); } else if(rc < 0) { crm_debug_3("%s < %s", version1, version2); } else if(rc > 0) { crm_debug_3("%s > %s", version1, version2); } return rc; } gboolean do_stderr = FALSE; void alter_debug(int nsig) { CL_SIGNAL(DEBUG_INC, alter_debug); CL_SIGNAL(DEBUG_DEC, alter_debug); switch(nsig) { case DEBUG_INC: if (crm_log_level < 100) { crm_log_level++; } break; case DEBUG_DEC: if (crm_log_level > 0) { crm_log_level--; } break; default: fprintf(stderr, "Unknown signal %d\n", nsig); cl_log(LOG_ERR, "Unknown signal %d", nsig); break; } } void g_hash_destroy_str(gpointer data) { crm_free(data); } int crm_int_helper(const char *text, char **end_text) { int atoi_result = -1; char *local_end_text = NULL; errno = 0; if(text != NULL) { if(end_text != NULL) { atoi_result = (int)strtol(text, end_text, 10); } else { atoi_result = (int)strtol(text, &local_end_text, 10); } /* CRM_CHECK(errno != EINVAL); */ if(errno == EINVAL) { crm_err("Conversion of %s failed", text); atoi_result = -1; } else { if(errno == ERANGE) { crm_err("Conversion of %s was clipped", text); } if(end_text == NULL && local_end_text[0] != '\0') { crm_err("Characters left over after parsing " "\"%s\": \"%s\"", text, local_end_text); } } } return atoi_result; } int crm_parse_int(const char *text, const char *default_text) { int atoi_result = -1; if(text != NULL) { atoi_result = crm_int_helper(text, NULL); if(errno == 0) { return atoi_result; } } if(default_text != NULL) { atoi_result = crm_int_helper(default_text, NULL); if(errno == 0) { return atoi_result; } } else { crm_err("No default conversion value supplied"); } return -1; } gboolean crm_str_eq(const char *a, const char *b, gboolean use_case) { if(a == NULL || b == NULL) { /* shouldn't be comparing NULLs */ CRM_CHECK(a != b, return TRUE); return FALSE; } else if(use_case && a[0] != b[0]) { return FALSE; } else if(a == b) { return TRUE; } else if(strcasecmp(a, b) == 0) { return TRUE; } return FALSE; } gboolean safe_str_neq(const char *a, const char *b) { if(a == b) { return FALSE; } else if(a==NULL || b==NULL) { return TRUE; } else if(strcasecmp(a, b) == 0) { return FALSE; } return TRUE; } char * crm_strdup_fn(const char *src, const char *file, const char *fn, int line) { char *dup = NULL; CRM_CHECK(src != NULL, return NULL); crm_malloc0(dup, strlen(src) + 1); return strcpy(dup, src); } static GHashTable *crm_uuid_cache = NULL; static GHashTable *crm_uname_cache = NULL; void empty_uuid_cache(void) { if(crm_uuid_cache != NULL) { g_hash_table_destroy(crm_uuid_cache); crm_uuid_cache = NULL; } } void unget_uuid(const char *uname) { if(crm_uuid_cache == NULL) { return; } g_hash_table_remove(crm_uuid_cache, uname); } const char * get_uuid(ll_cluster_t *hb, const char *uname) { cl_uuid_t uuid_raw; char *uuid_calc = NULL; const char *unknown = "00000000-0000-0000-0000-000000000000"; if(crm_uuid_cache == NULL) { crm_uuid_cache = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); } CRM_CHECK(uname != NULL, return NULL); /* avoid blocking calls where possible */ uuid_calc = g_hash_table_lookup(crm_uuid_cache, uname); if(uuid_calc != NULL) { return uuid_calc; } if(hb->llc_ops->get_uuid_by_name(hb, uname, &uuid_raw) == HA_FAIL) { crm_err("get_uuid_by_name() call failed for host %s", uname); crm_free(uuid_calc); return NULL; } crm_malloc0(uuid_calc, 50); if(uuid_calc == NULL) { return NULL; } cl_uuid_unparse(&uuid_raw, uuid_calc); if(safe_str_eq(uuid_calc, unknown)) { crm_warn("Could not calculate UUID for %s", uname); crm_free(uuid_calc); return NULL; } g_hash_table_insert(crm_uuid_cache, crm_strdup(uname), uuid_calc); uuid_calc = g_hash_table_lookup(crm_uuid_cache, uname); return uuid_calc; } const char * get_uname(ll_cluster_t *hb, const char *uuid) { char *uname = NULL; if(crm_uuid_cache == NULL) { crm_uname_cache = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); } CRM_CHECK(uuid != NULL, return NULL); /* avoid blocking calls where possible */ uname = g_hash_table_lookup(crm_uname_cache, uuid); if(uname != NULL) { return uname; } if(uuid != NULL) { cl_uuid_t uuid_raw; char *uuid_copy = crm_strdup(uuid); cl_uuid_parse(uuid_copy, &uuid_raw); if(hb->llc_ops->get_name_by_uuid( hb, &uuid_raw, uname, 256) == HA_FAIL) { crm_err("Could not calculate UUID for %s", uname); uname = NULL; crm_free(uuid_copy); } else { g_hash_table_insert( crm_uuid_cache, uuid_copy, crm_strdup(uname)); uname = g_hash_table_lookup(crm_uname_cache, uuid); } return uname; } return NULL; } void set_uuid(ll_cluster_t *hb,crm_data_t *node,const char *attr,const char *uname) { const char *uuid_calc = get_uuid(hb, uname); crm_xml_add(node, attr, uuid_calc); return; } #define ENV_PREFIX "HA_" void crm_set_env_options(void) { char *param_val = NULL; const char *param_name = NULL; /* apparently we're not allowed to free the result of getenv */ param_name = ENV_PREFIX "" KEY_DEBUGLEVEL; param_val = getenv(param_name); if(param_val != NULL) { int debug_level = crm_parse_int(param_val, NULL); if(debug_level > 0 && (debug_level+LOG_INFO) > (int)crm_log_level) { set_crm_log_level(LOG_INFO + debug_level); } crm_debug("%s = %s", param_name, param_val); param_val = NULL; } param_name = ENV_PREFIX "" KEY_FACILITY; param_val = getenv(param_name); crm_debug("%s = %s", param_name, param_val); if(param_val != NULL) { int facility = cl_syslogfac_str2int(param_val); if(facility >= 0) { cl_log_set_facility(facility); } param_val = NULL; } param_name = ENV_PREFIX "" KEY_LOGFILE; param_val = getenv(param_name); crm_debug("%s = %s", param_name, param_val); if(param_val != NULL) { if(safe_str_eq("/dev/null", param_val)) { param_val = NULL; } cl_log_set_logfile(param_val); param_val = NULL; } param_name = ENV_PREFIX "" KEY_DBGFILE; param_val = getenv(param_name); crm_debug("%s = %s", param_name, param_val); if(param_val != NULL) { if(safe_str_eq("/dev/null", param_val)) { param_val = NULL; } cl_log_set_debugfile(param_val); param_val = NULL; } param_name = ENV_PREFIX "" KEY_LOGDAEMON; param_val = getenv(param_name); crm_debug("%s = %s", param_name, param_val); if(param_val != NULL) { int uselogd; cl_str_to_boolean(param_val, &uselogd); cl_log_set_uselogd(uselogd); if(uselogd) { cl_set_logging_wqueue_maxlen(500); cl_log_set_logd_channel_source(NULL, NULL); } param_val = NULL; } param_name = ENV_PREFIX "" KEY_CONNINTVAL; param_val = getenv(param_name); crm_debug("%s = %s", param_name, param_val); if(param_val != NULL) { int logdtime; logdtime = crm_get_msec(param_val); cl_log_set_logdtime(logdtime); param_val = NULL; } inherit_compress(); } gboolean crm_is_true(const char * s) { gboolean ret = FALSE; if(s != NULL) { cl_str_to_boolean(s, &ret); } return ret; } int crm_str_to_boolean(const char * s, int * ret) { if(s == NULL) { return -1; } else if (strcasecmp(s, "true") == 0 || strcasecmp(s, "on") == 0 || strcasecmp(s, "yes") == 0 || strcasecmp(s, "y") == 0 || strcasecmp(s, "1") == 0){ *ret = TRUE; return 1; } else if (strcasecmp(s, "false") == 0 || strcasecmp(s, "off") == 0 || strcasecmp(s, "no") == 0 || strcasecmp(s, "n") == 0 || strcasecmp(s, "0") == 0){ *ret = FALSE; return 1; } return -1; } #ifndef NUMCHARS # define NUMCHARS "0123456789." #endif #ifndef WHITESPACE # define WHITESPACE " \t\n\r\f" #endif long crm_get_msec(const char * input) { const char * cp = input; const char * units; long multiplier = 1000; long divisor = 1; long ret = -1; double dret; if(input == NULL) { return 0; } cp += strspn(cp, WHITESPACE); units = cp + strspn(cp, NUMCHARS); units += strspn(units, WHITESPACE); if (strchr(NUMCHARS, *cp) == NULL) { return ret; } if (strncasecmp(units, "ms", 2) == 0 || strncasecmp(units, "msec", 4) == 0) { multiplier = 1; divisor = 1; }else if (strncasecmp(units, "us", 2) == 0 || strncasecmp(units, "usec", 4) == 0) { multiplier = 1; divisor = 1000; }else if (strncasecmp(units, "s", 1) == 0 || strncasecmp(units, "sec", 3) == 0) { multiplier = 1000; divisor = 1; }else if (strncasecmp(units, "m", 1) == 0 || strncasecmp(units, "min", 3) == 0) { multiplier = 60*1000; divisor = 1; }else if (strncasecmp(units, "h", 1) == 0 || strncasecmp(units, "hr", 2) == 0) { multiplier = 60*60*1000; divisor = 1; }else if (*units != EOS && *units != '\n' && *units != '\r') { return ret; } dret = atof(cp); dret *= (double)multiplier; dret /= (double)divisor; dret += 0.5; ret = (long)dret; return(ret); } gboolean ccm_have_quorum(oc_ed_t event) { if(event==OC_EV_MS_NEW_MEMBERSHIP) { return TRUE; } return FALSE; } const char * ccm_event_name(oc_ed_t event) { if(event==OC_EV_MS_NEW_MEMBERSHIP) { return "NEW MEMBERSHIP"; } else if(event==OC_EV_MS_NOT_PRIMARY) { return "NOT PRIMARY"; } else if(event==OC_EV_MS_PRIMARY_RESTORED) { return "PRIMARY RESTORED"; } else if(event==OC_EV_MS_EVICTED) { return "EVICTED"; } else if(event==OC_EV_MS_INVALID) { return "INVALID"; } return "NO QUORUM MEMBERSHIP"; } const char * op_status2text(op_status_t status) { switch(status) { case LRM_OP_PENDING: return "pending"; break; case LRM_OP_DONE: return "complete"; break; case LRM_OP_ERROR: return "Error"; break; case LRM_OP_TIMEOUT: return "Timed Out"; break; case LRM_OP_NOTSUPPORTED: return "NOT SUPPORTED"; break; case LRM_OP_CANCELLED: return "Cancelled"; break; } CRM_CHECK(status >= LRM_OP_PENDING && status <= LRM_OP_CANCELLED, crm_err("Unknown status: %d", status)); return "UNKNOWN!"; } char * generate_op_key(const char *rsc_id, const char *op_type, int interval) { int len = 35; char *op_id = NULL; CRM_CHECK(rsc_id != NULL, return NULL); CRM_CHECK(op_type != NULL, return NULL); len += strlen(op_type); len += strlen(rsc_id); crm_malloc0(op_id, len); CRM_CHECK(op_id != NULL, return NULL); sprintf(op_id, "%s_%s_%d", rsc_id, op_type, interval); return op_id; } gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, int *interval) { char *mutable_key = NULL; char *mutable_key_ptr = NULL; int len = 0, offset = 0, ch = 0; CRM_CHECK(key != NULL, return FALSE); *interval = 0; len = strlen(key); offset = len-1; crm_debug_3("Source: %s", key); while(offset > 0 && isdigit(key[offset])) { int digits = len-offset; ch = key[offset] - '0'; CRM_CHECK(ch < 10, return FALSE); CRM_CHECK(ch >= 0, return FALSE); while(digits > 1) { digits--; ch = ch * 10; } *interval += ch; offset--; } crm_debug_3(" Interval: %d", *interval); CRM_CHECK(key[offset] == '_', return FALSE); mutable_key = crm_strdup(key); mutable_key_ptr = mutable_key_ptr; mutable_key[offset] = 0; offset--; while(offset > 0 && key[offset] != '_') { offset--; } CRM_CHECK(key[offset] == '_', crm_free(mutable_key); return FALSE); mutable_key_ptr = mutable_key+offset+1; crm_debug_3(" Action: %s", mutable_key_ptr); *op_type = crm_strdup(mutable_key_ptr); mutable_key[offset] = 0; offset--; CRM_CHECK(mutable_key != mutable_key_ptr, crm_free(mutable_key); return FALSE); crm_debug_3(" Resource: %s", mutable_key); *rsc_id = crm_strdup(mutable_key); crm_free(mutable_key); return TRUE; } char * generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type) { int len = 12; char *op_id = NULL; CRM_CHECK(rsc_id != NULL, return NULL); CRM_CHECK(op_type != NULL, return NULL); CRM_CHECK(notify_type != NULL, return NULL); len += strlen(op_type); len += strlen(rsc_id); len += strlen(notify_type); crm_malloc0(op_id, len); if(op_id != NULL) { sprintf(op_id, "%s_%s_notify_%s_0", rsc_id, notify_type, op_type); } return op_id; } char * generate_transition_magic_v202(const char *transition_key, int op_status) { int len = 80; char *fail_state = NULL; CRM_CHECK(transition_key != NULL, return NULL); len += strlen(transition_key); crm_malloc0(fail_state, len); if(fail_state != NULL) { snprintf(fail_state, len, "%d:%s", op_status,transition_key); } return fail_state; } char * generate_transition_magic(const char *transition_key, int op_status, int op_rc) { int len = 80; char *fail_state = NULL; CRM_CHECK(transition_key != NULL, return NULL); len += strlen(transition_key); crm_malloc0(fail_state, len); if(fail_state != NULL) { snprintf(fail_state, len, "%d:%d;%s", op_status, op_rc, transition_key); } return fail_state; } gboolean decode_transition_magic( const char *magic, char **uuid, int *transition_id, int *action_id, int *op_status, int *op_rc) { char *rc = NULL; char *key = NULL; char *magic2 = NULL; char *status = NULL; gboolean result = TRUE; if(decodeNVpair(magic, ':', &status, &magic2) == FALSE) { crm_err("Couldn't find ':' in: %s", magic); result = FALSE; goto bail; } if(decodeNVpair(magic2, ';', &rc, &key) == FALSE) { crm_err("Couldn't find ';' in: %s", magic2); result = FALSE; goto bail; } CRM_CHECK(decode_transition_key(key, uuid, transition_id, action_id), result = FALSE; goto bail; ); *op_rc = crm_parse_int(rc, NULL); *op_status = crm_parse_int(status, NULL); bail: crm_free(rc); crm_free(key); crm_free(magic2); crm_free(status); return result; } char * generate_transition_key(int transition_id, int action_id, const char *node) { int len = 40; char *fail_state = NULL; CRM_CHECK(node != NULL, return NULL); len += strlen(node); crm_malloc0(fail_state, len); if(fail_state != NULL) { snprintf(fail_state, len, "%d:%d:%s", action_id, transition_id, node); } return fail_state; } gboolean decode_transition_key( const char *key, char **uuid, int *transition_id, int *action_id) { char *tmp = NULL; char *action = NULL; char *transition = NULL; *uuid = NULL; *action_id = -1; *transition_id = -1; if(decodeNVpair(key, ':', &action, &tmp) == FALSE) { crm_err("Couldn't find ':' in: %s", key); return FALSE; } *action_id = crm_parse_int(action, NULL); crm_free(action); if(decodeNVpair(tmp, ':', &transition, uuid) == FALSE) { /* this would be an error but some versions dont * have the action */ *transition_id = *action_id; *action_id = -1; *uuid = tmp; } else { *transition_id = crm_parse_int(transition, NULL); crm_free(transition); crm_free(tmp); } return TRUE; } void filter_action_parameters(crm_data_t *param_set, const char *version) { const char *timeout = NULL; const char *interval = NULL; #if CRM_DEPRECATED_SINCE_2_0_5 const char *filter_205[] = { XML_ATTR_TE_TARGET_RC, XML_ATTR_LRM_PROBE, XML_RSC_ATTR_START, XML_RSC_ATTR_NOTIFY, XML_RSC_ATTR_UNIQUE, XML_RSC_ATTR_MANAGED, XML_RSC_ATTR_PRIORITY, XML_RSC_ATTR_MULTIPLE, XML_RSC_ATTR_STICKINESS, XML_RSC_ATTR_FAIL_STICKINESS, XML_RSC_ATTR_TARGET_ROLE, /* ignore clone fields */ XML_RSC_ATTR_INCARNATION, XML_RSC_ATTR_INCARNATION_MAX, XML_RSC_ATTR_INCARNATION_NODEMAX, XML_RSC_ATTR_MASTER_MAX, XML_RSC_ATTR_MASTER_NODEMAX, /* old field names */ "role", "crm_role", "te-target-rc", /* ignore notify fields */ "notify_stop_resource", "notify_stop_uname", "notify_start_resource", "notify_start_uname", "notify_active_resource", "notify_active_uname", "notify_inactive_resource", "notify_inactive_uname", "notify_promote_resource", "notify_promote_uname", "notify_demote_resource", "notify_demote_uname", "notify_master_resource", "notify_master_uname", "notify_slave_resource", "notify_slave_uname" }; #endif const char *attr_filter[] = { XML_ATTR_ID, XML_ATTR_CRM_VERSION, XML_LRM_ATTR_OP_DIGEST, }; gboolean do_delete = FALSE; int lpc = 0; static int meta_len = 0; if(meta_len == 0) { meta_len = strlen(CRM_META); } if(param_set == NULL) { return; } #if CRM_DEPRECATED_SINCE_2_0_5 if(version == NULL || compare_version("1.0.5", version)) { for(lpc = 0; lpc < DIMOF(filter_205); lpc++) { xml_remove_prop(param_set, filter_205[lpc]); } } #endif for(lpc = 0; lpc < DIMOF(attr_filter); lpc++) { xml_remove_prop(param_set, attr_filter[lpc]); } timeout = crm_element_value(param_set, CRM_META"_timeout"); interval = crm_element_value(param_set, CRM_META"_interval"); xml_prop_iter(param_set, prop_name, prop_value, do_delete = FALSE; if(strncasecmp(prop_name, CRM_META, meta_len) == 0) { do_delete = TRUE; } if(do_delete) { /* remove it */ xml_remove_prop(param_set, prop_name); /* unwind the counetr */ __counter--; } ); if(crm_get_msec(interval) && compare_version(version, "1.0.8")) { /* Re-instate the operation's timeout value */ if(timeout != NULL) { crm_xml_add(param_set, CRM_META"_timeout", timeout); } } } void filter_reload_parameters(crm_data_t *param_set, const char *restart_string) { int len = 0; char *name = NULL; char *match = NULL; if(param_set == NULL) { return; } xml_prop_iter(param_set, prop_name, prop_value, name = NULL; len = strlen(prop_name) + 3; crm_malloc0(name, len); sprintf(name, " %s ", prop_name); name[len-1] = 0; match = strstr(restart_string, name); if(match == NULL) { /* remove it */ crm_debug_3("%s not found in %s", prop_name, restart_string); xml_remove_prop(param_set, prop_name); /* unwind the counetr */ __counter--; } crm_free(name); ); } void crm_abort(const char *file, const char *function, int line, const char *assert_condition, gboolean do_fork) { int rc = 0; int pid = 0; int status = 0; if(do_fork == FALSE) { do_crm_log(LOG_ERR, "%s: Triggered fatal assert at %s:%d : %s", function, file, line, assert_condition); } else if(crm_log_level < LOG_DEBUG) { do_crm_log(LOG_ERR, "%s: Triggered non-fatal assert at %s:%d : %s", function, file, line, assert_condition); return; } else { pid=fork(); } switch(pid) { case -1: crm_err("Cannot fork!"); return; default: /* Parent */ do_crm_log(LOG_ERR, "%s: Forked child %d to record non-fatal assert at %s:%d : %s", function, pid, file, line, assert_condition); do { rc = waitpid(pid, &status, 0); if(rc < 0 && errno != EINTR) { cl_perror("%s: Cannot wait on forked child %d", function, pid); } } while(rc < 0 && errno == EINTR); return; case 0: /* Child */ abort(); break; } } char * generate_series_filename( const char *directory, const char *series, int sequence, gboolean bzip) { int len = 40; char *filename = NULL; const char *ext = "raw"; CRM_CHECK(directory != NULL, return NULL); CRM_CHECK(series != NULL, return NULL); len += strlen(directory); len += strlen(series); crm_malloc0(filename, len); CRM_CHECK(filename != NULL, return NULL); if(bzip) { ext = "bz2"; } sprintf(filename, "%s/%s-%d.%s", directory, series, sequence, ext); return filename; } int get_last_sequence(const char *directory, const char *series) { FILE *file_strm = NULL; int start = 0, length = 0, read_len = 0; char *series_file = NULL; char *buffer = NULL; int seq = 0; int len = 36; CRM_CHECK(directory != NULL, return 0); CRM_CHECK(series != NULL, return 0); len += strlen(directory); len += strlen(series); crm_malloc0(series_file, len); CRM_CHECK(series_file != NULL, return 0); sprintf(series_file, "%s/%s.last", directory, series); file_strm = fopen(series_file, "r"); if(file_strm == NULL) { crm_debug("Series file %s does not exist", series_file); crm_free(series_file); return 0; } /* see how big the file is */ start = ftell(file_strm); fseek(file_strm, 0L, SEEK_END); length = ftell(file_strm); fseek(file_strm, 0L, start); CRM_ASSERT(start == ftell(file_strm)); crm_debug_3("Reading %d bytes from file", length); crm_malloc0(buffer, (length+1)); read_len = fread(buffer, 1, length, file_strm); if(read_len != length) { crm_err("Calculated and read bytes differ: %d vs. %d", length, read_len); crm_free(buffer); buffer = NULL; } else if(length <= 0) { crm_info("%s was not valid", series_file); crm_free(buffer); buffer = NULL; } crm_free(series_file); seq = crm_parse_int(buffer, "0"); crm_free(buffer); fclose(file_strm); return seq; } void write_last_sequence( const char *directory, const char *series, int sequence, int max) { int rc = 0; int len = 36; char *buffer = NULL; FILE *file_strm = NULL; char *series_file = NULL; CRM_CHECK(directory != NULL, return); CRM_CHECK(series != NULL, return); if(max == 0) { return; } while(max > 0 && sequence > max) { sequence -= max; } buffer = crm_itoa(sequence); len += strlen(directory); len += strlen(series); crm_malloc0(series_file, len); sprintf(series_file, "%s/%s.last", directory, series); file_strm = fopen(series_file, "w"); if(file_strm == NULL) { crm_err("Cannout open series file %s for writing", series_file); goto bail; } rc = fprintf(file_strm, "%s", buffer); if(rc < 0) { cl_perror("Cannot write to series file %s", series_file); } bail: if(file_strm != NULL) { fflush(file_strm); fclose(file_strm); } crm_free(series_file); crm_free(buffer); } void crm_make_daemon(const char *name, 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", name); cl_perror("fork"); exit(LSB_EXIT_GENERIC); } else if (pid > 0) { exit(LSB_EXIT_OK); } if (cl_lock_pidfile(pidfile) < 0 ) { pid = cl_read_pidfile_no_checking(pidfile); crm_warn("%s: already running [pid %ld] (%s).\n", name, pid, pidfile); exit(LSB_EXIT_OK); } umask(022); close(FD_STDIN); (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 */ } gboolean crm_is_writable(const char *dir, const char *file, const char *user, const char *group, gboolean need_both) { int s_res = -1; struct stat buf; char *full_file = NULL; const char *target = NULL; gboolean pass = TRUE; gboolean readwritable = FALSE; CRM_ASSERT(dir != NULL); if(file != NULL) { full_file = crm_concat(dir, file, '/'); target = full_file; s_res = stat(full_file, &buf); if( s_res == 0 && S_ISREG(buf.st_mode) == FALSE ) { crm_err("%s must be a regular file", target); pass = FALSE; goto out; } } if (s_res != 0) { target = dir; s_res = stat(dir, &buf); if(s_res != 0) { crm_err("%s must exist and be a directory", dir); pass = FALSE; goto out; } else if( S_ISDIR(buf.st_mode) == FALSE ) { crm_err("%s must be a directory", dir); pass = FALSE; } } if(user) { struct passwd *sys_user = NULL; sys_user = getpwnam(user); readwritable = (sys_user != NULL && buf.st_uid == sys_user->pw_uid && (buf.st_mode & (S_IRUSR|S_IWUSR))); if(readwritable == FALSE) { crm_err("%s must be owned and r/w by user %s", target, user); if(need_both) { pass = FALSE; } } } if(group) { struct group *sys_grp = getgrnam(group); readwritable = ( sys_grp != NULL && buf.st_gid == sys_grp->gr_gid && (buf.st_mode & (S_IRGRP|S_IWGRP))); if(readwritable == FALSE) { if(need_both || user == NULL) { pass = FALSE; crm_err("%s must be owned and r/w by group %s", target, group); } else { crm_warn("%s should be owned and r/w by group %s", target, group); } } } out: crm_free(full_file); return pass; } diff --git a/tools/attrd.c b/tools/attrd.c index adb7d259ac..99c478e71b 100644 --- a/tools/attrd.c +++ b/tools/attrd.c @@ -1,676 +1,676 @@ /* * 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 #define OPTARGS "hV" GMainLoop* mainloop = NULL; const 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 gboolean attrd_ha_dispatch(IPC_Channel *channel, gpointer user_data) { gboolean stay_connected = TRUE; crm_debug_2("Invoked"); while(attrd_cluster_conn != NULL && IPC_ISRCONN(channel)) { if(attrd_cluster_conn->llc_ops->msgready(attrd_cluster_conn) == 0) { crm_debug_2("no message ready yet"); break; } /* invoke the callbacks but dont block */ attrd_cluster_conn->llc_ops->rcvmsg(attrd_cluster_conn, 0); } if (attrd_cluster_conn == NULL || channel->ch_status != IPC_CONNECT) { if(need_shutdown == FALSE) { crm_crit("Lost connection to heartbeat service."); } else { crm_info("Lost connection to heartbeat service."); } stay_connected = FALSE; } return stay_connected; } 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) { const char *const_attrd_uuid = NULL; if(attrd_cluster_conn == NULL) { attrd_cluster_conn = ll_cluster_new("heartbeat"); } if(attrd_cluster_conn == NULL) { crm_err("Cannot create heartbeat object"); return FALSE; } crm_debug("Signing in with Heartbeat"); if (attrd_cluster_conn->llc_ops->signon(attrd_cluster_conn, T_ATTRD)!= HA_OK) { crm_err("Cannot sign on with heartbeat: %s", attrd_cluster_conn->llc_ops->errmsg(attrd_cluster_conn)); return FALSE; } crm_debug_3("Be informed of CRM messages"); if (HA_OK != attrd_cluster_conn->llc_ops->set_msg_callback( attrd_cluster_conn, T_ATTRD, attrd_ha_callback, attrd_cluster_conn)) { crm_err("Cannot set msg callback: %s", attrd_cluster_conn->llc_ops->errmsg(attrd_cluster_conn)); return FALSE; } crm_debug_3("Adding channel to mainloop"); G_main_add_IPC_Channel( G_PRIORITY_HIGH, attrd_cluster_conn->llc_ops->ipcchan( attrd_cluster_conn), FALSE, attrd_ha_dispatch, attrd_cluster_conn /* userdata */, attrd_ha_connection_destroy); crm_debug_3("Finding our node name"); attrd_uname = attrd_cluster_conn->llc_ops->get_mynodeid( attrd_cluster_conn); if (attrd_uname == NULL) { crm_err("get_mynodeid() failed"); return FALSE; } crm_info("Hostname: %s", attrd_uname); crm_debug_3("Finding our node uuid"); const_attrd_uuid = get_uuid(attrd_cluster_conn, attrd_uname); if(const_attrd_uuid == NULL) { crm_err("get_uuid_by_name() failed"); return FALSE; } /* copy it so that unget_uuid() doesn't trash the value on us */ attrd_uuid = crm_strdup(const_attrd_uuid); crm_info("UUID: %s", attrd_uuid); return TRUE; } 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, TRUE); + 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); } 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) { 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); 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); 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, value); hash_entry = find_hash_entry(msg); crm_free(hash_entry->last_value); hash_entry->last_value = hash_entry->value; value = ha_msg_value(msg, F_ATTRD_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_ha_message(attrd_cluster_conn, msg, NULL, FALSE); crm_msg_del(msg); return TRUE; } diff --git a/tools/attrd_updater.c b/tools/attrd_updater.c index 00f417d7f8..13e2f72776 100644 --- a/tools/attrd_updater.c +++ b/tools/attrd_updater.c @@ -1,163 +1,161 @@ /* * 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 #define OPTARGS "hVn:v:d:s:S:" const char* crm_system_name = "attrd_updater"; const char *attr_name = NULL; const char *attr_value = NULL; const char *attr_set = NULL; const char *attr_section = NULL; const char *attr_dampen = NULL; void usage(const char* cmd, int exit_status); static gboolean process_attrd_message( HA_Message *msg, crm_data_t *xml_data, IPC_Channel *sender) { crm_err("Why did we get a message?"); crm_log_message_adv(LOG_WARNING, "attrd:msg", msg); return TRUE; } int main(int argc, char ** argv) { HA_Message *update = NULL; IPC_Channel *attrd = NULL; int argerr = 0; int flag; - crm_log_init(crm_system_name, FALSE); + crm_log_init(crm_system_name, LOG_ERR, FALSE, FALSE, argc, argv); 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 'n': attr_name = crm_strdup(optarg); break; case 'v': attr_value = crm_strdup(optarg); break; case 's': attr_set = crm_strdup(optarg); break; case 'd': attr_dampen = crm_strdup(optarg); break; case 'S': attr_section = crm_strdup(optarg); 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 */ init_client_ipc_comms(T_ATTRD, subsystem_msg_dispatch, (void*)process_attrd_message, &attrd); if(attrd == NULL) { fprintf(stderr, "Could not connect to "T_ATTRD"\n"); return 1; } - cl_log_args(argc, argv); - update = ha_msg_new(4); ha_msg_add(update, F_TYPE, T_ATTRD); ha_msg_add(update, F_ORIG, crm_system_name); ha_msg_add(update, F_ATTRD_TASK, "update"); ha_msg_add(update, F_ATTRD_ATTRIBUTE, attr_name); if(attr_value != NULL) { ha_msg_add(update, F_ATTRD_VALUE, attr_value); } if(attr_set != NULL) { ha_msg_add(update, F_ATTRD_SET, attr_set); } if(attr_section != NULL) { ha_msg_add(update, F_ATTRD_SECTION, attr_section); } if(attr_dampen != NULL) { ha_msg_add(update, F_ATTRD_DAMPEN, attr_dampen); } if(send_ipc_message(attrd, update) == FALSE) { fprintf(stderr, "Could not send update\n"); crm_msg_del(update); return 1; } crm_msg_del(update); return 0; } void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s -n [-vdsS]\n", cmd); fprintf(stream, "\t-n \tthe attribute that changed\n"); fprintf(stream, "\t-v \tthe attribute's value\n"); fprintf(stream, "\t\tIf no value is supplied, the attribute value for this node will be deleted\n"); fprintf(stream, "\t-d \tthe time to wait (dampening) further changes occur\n"); fprintf(stream, "\t-s \tthe attribute set in which to place the value\n"); fprintf(stream, "\t\tMost people have no need to specify this\n"); fprintf(stream, "\t-S \tthe section in which to place the value\n"); fprintf(stream, "\t\tMost people have no need to specify this\n"); fflush(stream); exit(exit_status); } diff --git a/tools/pingd.c b/tools/pingd.c index 7c3c24881a..c66fb5bbdd 100644 --- a/tools/pingd.c +++ b/tools/pingd.c @@ -1,465 +1,465 @@ /* * 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 /* GMainLoop *mainloop = NULL; */ const char *crm_system_name = "pingd"; #define OPTARGS "V?p:a:d:s:S:h:Dm:" IPC_Channel *attrd = NULL; GMainLoop* mainloop = NULL; GHashTable *ping_nodes = NULL; const char *pingd_attr = "pingd"; gboolean do_filter = FALSE; ll_cluster_t *pingd_cluster = NULL; gboolean need_shutdown = FALSE; const char *attr_set = NULL; const char *attr_section = NULL; const char *attr_dampen = NULL; int attr_multiplier = 1; void pingd_nstatus_callback( const char *node, const char *status, void *private_data); void pingd_lstatus_callback( const char *node, const char *link, const char *status, void *private_data); void do_node_walk(ll_cluster_t *hb_cluster); void send_update(void); static gboolean pingd_shutdown(int nsig, gpointer unused) { need_shutdown = TRUE; send_update(); 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 [-%s]\n", cmd, OPTARGS); fprintf(stream, "\t--%s (-%c) \t\t\tThis text\n", "help", '?'); fprintf(stream, "\t--%s (-%c) \t\tRun in daemon mode\n", "daemonize", 'D'); fprintf(stream, "\t--%s (-%c) \tFile in which to store the process' PID\n" "\t\t\t\t\t* Default=/tmp/pingd.pid\n", "pid-file", 'p'); fprintf(stream, "\t--%s (-%c) \tName of the node attribute to set\n" "\t\t\t\t\t* Default=pingd\n", "attr-name", 'a'); fprintf(stream, "\t--%s (-%c) \tName of the set in which to set the attribute\n" "\t\t\t\t\t* Default=cib-bootstrap-options\n", "attr-set", 's'); fprintf(stream, "\t--%s (-%c) \tWhich part of the CIB to put the attribute in\n" "\t\t\t\t\t* Default=status\n", "attr-section", 'S'); fprintf(stream, "\t--%s (-%c) \tMonitor a subset of the ping nodes listed in ha.cf (can be specified multiple times)\n", "ping-host", 'h'); fprintf(stream, "\t--%s (-%c) \t\tHow long to wait for no further changes to occur before updating the CIB with a changed attribute\n", "attr-dampen", 'd'); fprintf(stream, "\t--%s (-%c) \tFor every connected node, add to the value set in the CIB\n" "\t\t\t\t\t\t* Default=1\n", "value-multiplier", 'm'); fflush(stream); exit(exit_status); } static gboolean pingd_ha_dispatch(IPC_Channel *channel, gpointer user_data) { gboolean stay_connected = TRUE; crm_debug_2("Invoked"); while(pingd_cluster != NULL && IPC_ISRCONN(channel)) { if(pingd_cluster->llc_ops->msgready(pingd_cluster) == 0) { crm_debug_2("no message ready yet"); break; } /* invoke the callbacks but dont block */ pingd_cluster->llc_ops->rcvmsg(pingd_cluster, 0); } if (pingd_cluster == NULL || channel->ch_status != IPC_CONNECT) { if(need_shutdown == FALSE) { crm_crit("Lost connection to heartbeat service."); } else { crm_info("Lost connection to heartbeat service."); } stay_connected = FALSE; } return stay_connected; } static void pingd_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!"); } static gboolean register_with_ha(void) { if(pingd_cluster == NULL) { pingd_cluster = ll_cluster_new("heartbeat"); } if(pingd_cluster == NULL) { crm_err("Cannot create heartbeat object"); return FALSE; } crm_debug("Signing in with Heartbeat"); if (pingd_cluster->llc_ops->signon( pingd_cluster, crm_system_name) != HA_OK) { crm_err("Cannot sign on with heartbeat: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster)); crm_err("REASON: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster)); return FALSE; } do_node_walk(pingd_cluster); crm_debug_3("Be informed of Node Status changes"); if (HA_OK != pingd_cluster->llc_ops->set_nstatus_callback( pingd_cluster, pingd_nstatus_callback, NULL)) { crm_err("Cannot set nstatus callback: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster)); crm_err("REASON: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster)); return FALSE; } if (pingd_cluster->llc_ops->set_ifstatus_callback( pingd_cluster, pingd_lstatus_callback, NULL) != HA_OK) { cl_log(LOG_ERR, "Cannot set if status callback"); crm_err("REASON: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster)); return FALSE; } crm_debug_3("Adding channel to mainloop"); G_main_add_IPC_Channel( G_PRIORITY_HIGH, pingd_cluster->llc_ops->ipcchan( pingd_cluster), FALSE, pingd_ha_dispatch, pingd_cluster, pingd_ha_connection_destroy); return TRUE; } int main(int argc, char **argv) { int lpc; int argerr = 0; int flag; char *pid_file = NULL; gboolean daemonize = FALSE; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"pid-file", 1, 0, 'p'}, {"ping-host", 1, 0, 'h'}, {"attr-name", 1, 0, 'a'}, {"attr-set", 1, 0, 's'}, {"daemonize", 0, 0, 'D'}, {"attr-section", 1, 0, 'S'}, {"attr-dampen", 1, 0, 'd'}, {"value-multiplier", 1, 0, 'm'}, {0, 0, 0, 0} }; #endif pid_file = crm_strdup("/tmp/pingd.pid"); crm_system_name = "pingd"; G_main_add_SignalHandler( G_PRIORITY_HIGH, SIGTERM, pingd_shutdown, NULL, NULL); ping_nodes = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); - crm_log_init(crm_system_name, TRUE); + crm_log_init(crm_system_name, LOG_INFO, TRUE, FALSE, argc, argv); 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 'p': pid_file = crm_strdup(optarg); break; case 'a': pingd_attr = crm_strdup(optarg); break; case 'h': do_filter = TRUE; fprintf(stdout, "Adding ping host %s", optarg); g_hash_table_insert(ping_nodes, crm_strdup(optarg), crm_strdup(optarg)); break; case 's': attr_set = crm_strdup(optarg); break; case 'm': attr_multiplier = crm_parse_int(optarg, "1"); break; case 'S': attr_section = crm_strdup(optarg); break; case 'd': attr_dampen = crm_strdup(optarg); break; case 'D': daemonize = TRUE; break; case '?': usage(crm_system_name, LSB_EXIT_GENERIC); break; default: printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); crm_err("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc) { crm_err("non-option ARGV-elements: "); printf("non-option ARGV-elements: "); while (optind < argc) { crm_err("%s ", argv[optind++]); printf("%s ", argv[optind++]); } printf("\n"); } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } crm_make_daemon(crm_system_name, daemonize, pid_file); for(lpc = 0; attrd == NULL && lpc < 30; lpc++) { crm_debug("attrd registration attempt: %d", lpc); sleep(5); attrd = init_client_ipc_comms_nodispatch(T_ATTRD); } if(attrd == NULL) { crm_err("attrd registration failed"); cl_flush_logs(); exit(LSB_EXIT_GENERIC); } if(register_with_ha() == FALSE) { crm_err("HA registration failed"); cl_flush_logs(); exit(LSB_EXIT_GENERIC); } crm_info("Starting %s", crm_system_name); mainloop = g_main_new(FALSE); g_main_run(mainloop); crm_info("Exiting %s", crm_system_name); return 0; } static void count_ping_nodes(gpointer key, gpointer value, gpointer user_data) { int *num_active = user_data; CRM_CHECK(num_active != NULL, return); if(need_shutdown) { return; } if(safe_str_eq(value, PINGSTATUS)) { (*num_active)++; } else if(safe_str_eq(value, LINKUP)) { (*num_active)++; } } void send_update(void) { int num_active = 0; HA_Message *update = ha_msg_new(4); ha_msg_add(update, F_TYPE, T_ATTRD); ha_msg_add(update, F_ORIG, crm_system_name); ha_msg_add(update, F_ATTRD_TASK, "update"); ha_msg_add(update, F_ATTRD_ATTRIBUTE, pingd_attr); g_hash_table_foreach(ping_nodes, count_ping_nodes, &num_active); crm_info("%d active ping nodes", num_active); ha_msg_add_int(update, F_ATTRD_VALUE, attr_multiplier*num_active); if(attr_set != NULL) { ha_msg_add(update, F_ATTRD_SET, attr_set); } if(attr_section != NULL) { ha_msg_add(update, F_ATTRD_SECTION, attr_section); } if(attr_dampen != NULL) { ha_msg_add(update, F_ATTRD_DAMPEN, attr_dampen); } if(send_ipc_message(attrd, update) == FALSE) { crm_err("Could not send update"); exit(1); } crm_msg_del(update); } void pingd_nstatus_callback( const char *node, const char * status, void* private_data) { crm_notice("Status update: Ping node %s now has status [%s]", node, status); if(g_hash_table_lookup(ping_nodes, node) != NULL) { g_hash_table_replace( ping_nodes, crm_strdup(node), crm_strdup(status)); send_update(); } } void pingd_lstatus_callback(const char *node, const char *lnk, const char *status, void *private) { crm_notice("Status update: Ping node %s now has status [%s]", node, status); pingd_nstatus_callback(node, status, private); } void do_node_walk(ll_cluster_t *hb_cluster) { const char *ha_node = NULL; /* Async get client status information in the cluster */ crm_debug_2("Invoked"); crm_debug_3("Requesting an initial dump of CRMD client_status"); hb_cluster->llc_ops->client_status( hb_cluster, NULL, CRM_SYSTEM_CRMD, -1); crm_info("Requesting the list of configured nodes"); hb_cluster->llc_ops->init_nodewalk(hb_cluster); do { const char *ha_node_type = NULL; const char *ha_node_status = NULL; ha_node = hb_cluster->llc_ops->nextnode(hb_cluster); if(ha_node == NULL) { continue; } ha_node_type = hb_cluster->llc_ops->node_type( hb_cluster, ha_node); if(safe_str_neq(PINGNODE, ha_node_type)) { crm_debug("Node %s: skipping '%s'", ha_node, ha_node_type); continue; } if(do_filter && g_hash_table_lookup(ping_nodes, ha_node) == NULL) { crm_debug("Filtering: %s", ha_node); continue; } ha_node_status = hb_cluster->llc_ops->node_status( hb_cluster, ha_node); crm_debug("Adding: %s=%s", ha_node, ha_node_status); g_hash_table_replace(ping_nodes, crm_strdup(ha_node), crm_strdup(ha_node_status)); } while(ha_node != NULL); hb_cluster->llc_ops->end_nodewalk(hb_cluster); crm_debug_2("Complete"); send_update(); }