diff --git a/crm/admin/crm_resource.c b/crm/admin/crm_resource.c index 7b486605ac..7f39948b63 100644 --- a/crm/admin/crm_resource.c +++ b/crm/admin/crm_resource.c @@ -1,398 +1,640 @@ -/* $Id: crm_resource.c,v 1.3 2005/09/19 20:37:25 andrew Exp $ */ +/* $Id: crm_resource.c,v 1.4 2005/10/12 19:10:09 andrew Exp $ */ /* * 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 #include void usage(const char *cmd, int exit_status); -int do_find_resource(const char *rsc, crm_data_t *xml_node); -int do_find_resource_list(int level, crm_data_t *cib); gboolean BE_QUIET = FALSE; 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; char rsc_cmd = 0; +char *our_pid = NULL; +IPC_Channel *crmd_channel = NULL; -#define OPTARGS "V?SLRQDCP:WMr:h:v:" +#define OPTARGS "V?SLRQDCPp:WMr:H:v:t:" + +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) { + fprintf(stderr, "\n"); + } + + if(found == 0) { + printf("resource %s is NOT running\n", rsc); + } + + return found; +} + +static int +do_find_resource_list(pe_working_set_t *data_set) +{ + int found = 0; + + slist_iter( + rsc, resource_t, data_set->resources, lpc, + 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 found; +} + +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 1; +} + +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); + } + + 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."); + continue; + } + +/* result = cl_get_string(new_input->msg, XML_ATTR_RESULT); */ +/* if(result == NULL || strcmp(result, "ok") == 0) { */ +/* result = "pass"; */ +/* } else { */ +/* result = "fail"; */ +/* } */ + + } + + if (server->ch_status == IPC_DISCONNECT) { + crm_debug_2("admin_msg_callback: received HUP"); + return !hack_return_good; + } + + return hack_return_good; +} + +static int +delete_lrm_rsc( + IPC_Channel *crmd_channel, const char *host_uname, const char *rsc_id) +{ + HA_Message *cmd = NULL; + crm_data_t *msg_data = NULL; + crm_data_t *rsc = NULL; + char *key = crm_concat(crm_system_name, our_pid, '-'); + + CRM_DEV_ASSERT(rsc_id != NULL); + + msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); + crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key); + + rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE); + crm_xml_add(rsc, XML_ATTR_ID, rsc_id); + + cmd = create_request(CRM_OP_LRM_DELETE, 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)) { + return 0; + } + return -1; +} + +static int +refresh_lrm(IPC_Channel *crmd_channel, const char *host_uname) +{ + HA_Message *cmd = NULL; + + 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)) { + return 0; + } + return -1; +} + +static int +migrate_resource( + const char *rsc_id, + const char *existing_node, const char *preferred_node, + cib_t * cib_conn) +{ + 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 *can_run = NULL; + crm_data_t *dont_run = NULL; + + constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); + + id = crm_concat("cli-prefer", rsc_id, '-'); + can_run = create_xml_node(constraints, XML_CIB_TAG_CONSTRAINT); + crm_xml_add(can_run, XML_ATTR_ID, id); + crm_free(id); + + id = crm_concat("cli-standby", rsc_id, '-'); + dont_run = create_xml_node(constraints, XML_CIB_TAG_CONSTRAINT); + crm_xml_add(dont_run, XML_ATTR_ID, id); + crm_free(id); + + if(existing_node == NULL) { + rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_CONSTRAINTS, + dont_run, NULL, cib_sync_call); + + } else { + 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"); + } + + if(preferred_node == NULL) { + rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_CONSTRAINTS, + can_run, NULL, cib_sync_call); + + } else { + 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"); + } + rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_CONSTRAINTS, + fragment, NULL, cib_sync_call); + return rc; +} int main(int argc, char **argv) { - cib_t * the_cib = NULL; + 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, '?'}, {"silent", 0, 0, 'S'}, {"list", 0, 0, 'L'}, {"refresh", 0, 0, 'R'}, + {"reprobe", 0, 0, 'P'}, {"query", 0, 0, 'Q'}, {"delete", 0, 0, 'D'}, {"cleanup", 0, 0, 'C'}, {"locate", 0, 0, 'W'}, {"migrate", 0, 0, 'M'}, {"resource",1, 0, 'r'}, {"host_uname", 1, 0, 'H'}, {"host_uuid", 1, 0, 'h'}, - {"set-property", 1, 0, 'P'}, + {"set-property", 1, 0, 'p'}, {"property-value", 1, 0, 'v'}, + {"resource-type", 1, 0, 't'}, {0, 0, 0, 0} }; #endif crm_system_name = basename(argv[0]); crm_log_init(crm_system_name); crm_log_level = LOG_ERR; cl_log_enable_stderr(TRUE); 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 'S': BE_QUIET = TRUE; break; case 'L': rsc_cmd = flag; break; case 'R': rsc_cmd = flag; break; case 'Q': rsc_cmd = flag; break; case 'D': rsc_cmd = flag; break; case 'C': rsc_cmd = flag; break; case 'P': + rsc_cmd = flag; + break; + + case 'p': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'W': rsc_cmd = flag; break; case 'M': rsc_cmd = flag; 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; case 'h': crm_debug_2("Option %c => %s", flag, optarg); host_id = crm_strdup(optarg); 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); + crm_malloc0(our_pid, sizeof(char) * 11); + if(our_pid != NULL) { + snprintf(our_pid, 10, "%d", getpid()); + our_pid[10] = '\0'; + } if(rc != cib_ok) { crm_err("Error signing on to the CIB service: %s", cib_error2string(rc)); return rc; } + if(rsc_cmd == 'L' || rsc_cmd == 'W' || rsc_cmd == 'D' + || rsc_cmd == 'Q' || rsc_cmd == 'p') { + cib_conn = cib_new(); + rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command); + if(rsc_cmd == 'D') { + set_working_set_defaults(&data_set); + } else { + cib_xml_copy = get_cib_copy(cib_conn); + set_working_set_defaults(&data_set); + data_set.input = cib_xml_copy; + stage0(&data_set); + } + + } else if(rsc_cmd == 'R' || rsc_cmd == 'D' || rsc_cmd == 'C' || rsc_cmd == 'P') { + GCHSource *src = NULL; + src = init_client_ipc_comms(CRM_SYSTEM_CRMD, crmd_msg_callback, + NULL, &crmd_channel); + + 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') { - crm_data_t *cib_xml_copy = get_cib_copy(the_cib); - crm_data_t *resource_list = get_object_root( - XML_CIB_TAG_RESOURCES, cib_xml_copy); - do_find_resource_list(LOG_INFO, resource_list); - free_xml(cib_xml_copy); + do_find_resource_list(&data_set); } else if(rsc_cmd == 'W') { - crm_data_t *cib_xml_copy = get_cib_copy(the_cib); - rc = do_find_resource(rsc_id, cib_xml_copy); - free_xml(cib_xml_copy); + CRM_DEV_ASSERT(rsc_id != NULL); + rc = do_find_resource(rsc_id, &data_set); - } else if(rsc_cmd == 'R') { } else if(rsc_cmd == 'Q') { - } else if(rsc_cmd == 'D') { - } else if(rsc_cmd == 'C') { + CRM_DEV_ASSERT(rsc_id != NULL); + rc = dump_resource(rsc_id, &data_set); + } else if(rsc_cmd == 'M') { - } else if(rsc_cmd == 'r') { + rc = migrate_resource(rsc_id, NULL, host_uname, cib_conn); + + } else if(rsc_cmd == 'p') { + crm_data_t *msg_data = NULL; + + CRM_DEV_ASSERT(rsc_id != NULL); + 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_sync_call); + free_xml(msg_data); + } 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); + + } else if(rsc_cmd == 'R') { + refresh_lrm(crmd_channel, host_uname); + + } else if(rsc_cmd == 'D') { + crm_data_t *msg_data = NULL; + + CRM_DEV_ASSERT(rsc_type != NULL); + CRM_DEV_ASSERT(rsc_id != NULL); + + 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_sync_call); + free_xml(msg_data); + + } else if(rsc_cmd == 'C') { + delete_lrm_rsc(crmd_channel, host_uname, rsc_id); + refresh_lrm(crmd_channel, host_uname); + + } else { + crm_err("Unknown command: %c", rsc_cmd); } - the_cib->cmds->signoff(the_cib); + if(cib_conn != NULL) { + cleanup_calculations(&data_set); + cib_conn->cmds->signoff(cib_conn); + } if(rc == cib_NOTEXISTS) { crm_warn("Error performing operation: %s", cib_error2string(rc)); } else if(rc < cib_ok) { crm_warn("Error performing operation: %s", cib_error2string(rc)); } + return rc; } -int -do_find_resource(const char *rsc, crm_data_t *xml_node) -{ - int found = 0; - pe_working_set_t data_set; - resource_t *the_rsc = NULL; - - set_working_set_defaults(&data_set); - data_set.input = xml_node; - stage0(&data_set); - 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); - printf("resource %s is running on: %s\n", - rsc, node->details->uname); - if(BE_QUIET) { - fprintf(stderr, "%s ", node->details->uname); - } - found++; - ); - - if(BE_QUIET) { - fprintf(stderr, "\n"); - } - - if(found == 0) { - printf("resource %s is NOT running\n", rsc); - } - - data_set.input = NULL; - cleanup_calculations(&data_set); - - return found; -} - -int -do_find_resource_list(int level, crm_data_t *resource_list) -{ - int lpc = 0; - int found = 0; - const char *name = NULL; - const char *type = NULL; - const char *class = NULL; - - xml_child_iter( - resource_list, rsc, NULL, - name = crm_element_name(rsc); - if(safe_str_eq(name, XML_CIB_TAG_RESOURCE)) { - class = crm_element_value(rsc, "class"); - type = crm_element_value(rsc, XML_ATTR_TYPE); - for(lpc = 0; lpc < level; lpc++) { - printf("\t"); - } - found++; - printf("%s: %s (%s::%s)\n", - name, ID(rsc), crm_str(class), crm_str(type)); - } else if(safe_str_eq(name, XML_CIB_TAG_GROUP) - || safe_str_eq(name, XML_CIB_TAG_INCARNATION)) { - for(lpc = 0; lpc < level; lpc++) { - printf("\t"); - } - printf("%s: %s (complex)\n", name, ID(rsc)); - do_find_resource_list(level+1, rsc); - found++; - } - ); - if(found == 0) { - for(lpc = 0; lpc < level; lpc++) { - printf("\t"); - } - printf("NO resources configured\n"); - } - - return found; -} 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); + fprintf(stream, "usage: %s [-?VS] -(L|Q|W|D|C|P|p) [options]\n", cmd); - } else if(safe_str_eq(cmd, "crm_standby")) { - fprintf(stream, "usage: %s [-?V] -(u|U) -(D|G|v) [-l]\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 attribute\n", "get-value", 'G'); - fprintf(stream, "\t--%s (-%c)\t: " - "Delete rather than set the attribute\n", "delete-attr", 'D'); + fprintf(stream, "\t--%s (-%c)\t: Print only the value on stdout (for use with -W)\n", + "silent", 'S'); + + 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", 'Q'); + fprintf(stream, "\t--%s (-%c)\t: Locate a resource\n" + "\t\t\t Requires: -r\n", "locate", 'W'); + 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, -t. 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: " - "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'); + "Set the named property for a resource\n" + "\t\t\t Requires: -r, -t, -v", "set-property", 'p'); + fprintf(stream, "\nOptions\n"); + fprintf(stream, "\t--%s (-%c) \t: Resource ID\n", "resource", 'r'); fprintf(stream, "\t--%s (-%c) \t: " - "Set of attributes in which to read/write the attribute\n", - "set-name", 's'); + "Resource type (primitive, clone, group, ...)\n", + "resource-type", 't'); + fprintf(stream, "\t--%s (-%c) \t: " - "Attribute to set\n", "attr-name", 'n'); + "Property value\n", "property-value", 'v'); 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); + "Host name\n", "host-uname", 'H'); fflush(stream); exit(exit_status); } diff --git a/crm/admin/crmadmin.c b/crm/admin/crmadmin.c index fef0cc055e..81a3265418 100644 --- a/crm/admin/crmadmin.c +++ b/crm/admin/crmadmin.c @@ -1,839 +1,733 @@ -/* $Id: crmadmin.c,v 1.58 2005/09/15 08:27:40 andrew Exp $ */ +/* $Id: crmadmin.c,v 1.59 2005/10/12 19:10:09 andrew Exp $ */ /* * 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 #include 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_resource(const char *rsc, crm_data_t *xml_node); -int do_find_resource_list(int level, crm_data_t *xml_node); 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 = "crmadmin"; #define OPTARGS "V?K:S:HE:DW:d:i:RNqt:B" 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 */ {"crm_debug_inc", 1, 0, 'i'}, {"crm_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'}, - {"resources", 0, 0, 'R'}, {"nodes", 0, 0, 'N'}, - {"whereis", 1, 0, 'W'}, {"option", 1, 0, 'o'}, {0, 0, 0, 0} }; #endif crm_system_name = basename(argv[0]); crm_log_init(crm_system_name); 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 (strcmp("reference", long_options[option_index].name) == 0) { this_msg_reference = crm_strdup(optarg); } else if (strcmp("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': 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 'W': - DO_RESOURCE = TRUE; - crm_debug_2("Option %c => %s", flag, optarg); - rsc_name = crm_strdup(optarg); - 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 'R': - DO_RESOURCE_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 = 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++; if(res == 0) { crm_debug_2("no reply expected," " wait for the hello message only"); } else { crm_debug_2("Waiting for reply from the local CRM"); } message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); g_main_run(mainloop); return_to_orig_privs(); } else { 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;/* wait until timeout instead */ } 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_RESOURCE || DO_RESOURCE_LIST || DO_NODE_LIST) { + } 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); if(rc != cib_ok) { return -1; - - } else if(DO_RESOURCE) { - output = get_cib_copy(the_cib); - do_find_resource(rsc_name, output); - - } else if(DO_RESOURCE_LIST) { - crm_data_t *rscs = NULL; - output = get_cib_copy(the_cib); - rscs = get_object_root(XML_CIB_TAG_RESOURCES, output); - do_find_resource_list(0, rscs); - - } else if(DO_NODE_LIST) { - output = get_cib_copy(the_cib); - do_find_node_list(output); } - + + 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); } 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, sizeof(char) * 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); } 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."); continue; } else if (validate_crm_message( new_input->msg, crm_system_name, admin_uuid, XML_ATTR_RESPONSE) == FALSE) { crm_info("Message was not a CRM response. Discarding."); continue; } result = cl_get_string(new_input->msg, XML_ATTR_RESULT); if(result == NULL || strcmp(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, sizeof(char) * filename_len); if(filename != NULL) { sprintf(filename, "%s-%s_%d.xml", result, this_msg_reference, received_responses); filename[filename_len - 1] = '\0'; if (0 > write_xml_file(new_input->xml, filename)) { crm_crit("Could not save response to" " %s", filename); } } } } 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; } -int -do_find_resource(const char *rsc, crm_data_t *xml_node) -{ - int found = 0; - pe_working_set_t data_set; - resource_t *the_rsc = NULL; - - set_working_set_defaults(&data_set); - data_set.input = xml_node; - stage0(&data_set); - - the_rsc = pe_find_resource(data_set.resources, rsc); - if(the_rsc == NULL) { - return 0; - } - - slist_iter(node, node_t, the_rsc->running_on, lpc, - crm_debug_3("resource %s is running on: %s", - rsc, node->details->uname); - printf("resource %s is running on: %s\n", - rsc, node->details->uname); - if(BE_SILENT) { - fprintf(stderr, "%s ", node->details->uname); - } - found++; - ); - - if(BE_SILENT) { - fprintf(stderr, "\n"); - } - - if(found == 0) { - printf("resource %s is NOT running\n", rsc); - } - - data_set.input = NULL; - cleanup_calculations(&data_set); - - return found; -} - 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_resource_list(int level, crm_data_t *resource_list) -{ - int lpc = 0; - int found = 0; - const char *name = NULL; - const char *type = NULL; - const char *class = NULL; - - xml_child_iter( - resource_list, rsc, NULL, - name = crm_element_name(rsc); - if(safe_str_eq(name, XML_CIB_TAG_RESOURCE)) { - class = crm_element_value(rsc, "class"); - type = crm_element_value(rsc, XML_ATTR_TYPE); - for(lpc = 0; lpc < level; lpc++) { - printf("\t"); - } - found++; - printf("%s: %s (%s::%s)\n", - name, ID(rsc), crm_str(class), crm_str(type)); - } else if(safe_str_eq(name, XML_CIB_TAG_GROUP) - || safe_str_eq(name, XML_CIB_TAG_INCARNATION)) { - for(lpc = 0; lpc < level; lpc++) { - printf("\t"); - } - printf("%s: %s (complex)\n", name, ID(rsc)); - do_find_resource_list(level+1, rsc); - found++; - } - ); - if(found == 0) { - for(lpc = 0; lpc < level; lpc++) { - printf("\t"); - } - printf("NO resources configured\n"); - } - - return found; -} - 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( 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: " "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'); fprintf(stream, "\t--%s (-%c)\t\t: " "request the status of all nodes\n", "health", 'H'); 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: " "request the names of all resources\n", "resources", 'R'); fprintf(stream, "\t--%s (-%c) \t: " "request the location of \n", "whereis", 'W'); fprintf(stream, "\t--%s (-%c) \t: " "Tell the node to enter \"standby\" mode\n", "standby", 's'); fprintf(stream, "\t--%s (-%c) \t: " "Tell the node to exit \"standby\" mode\n", "active", 'a'); /* fprintf(stream, "\t--%s (-%c)\t\n", "disconnect", 'D'); */ fflush(stream); exit(exit_status); }