Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4511794
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
109 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/crm/admin/cibadmin.c b/crm/admin/cibadmin.c
index fab5619dd6..22ef65b1df 100644
--- a/crm/admin/cibadmin.c
+++ b/crm/admin/cibadmin.c
@@ -1,567 +1,568 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <crm_internal.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <clplumbing/uids.h>
#include <clplumbing/Gmain_timeout.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/ctrl.h>
#include <crm/common/ipc.h>
#include <crm/cib.h>
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
#include <ha_msg.h> /* someone complaining about _ha_msg_mod not being found */
int exit_code = cib_ok;
int message_timer_id = -1;
int message_timeout_ms = 30;
GMainLoop *mainloop = NULL;
IPC_Channel *crmd_channel = NULL;
const char *host = NULL;
void usage(const char *cmd, int exit_status);
enum cib_errors do_init(void);
int do_work(xmlNode *input, int command_options, xmlNode **output);
gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data);
gboolean admin_message_timeout(gpointer data);
void cib_connection_destroy(gpointer user_data);
void cibadmin_op_callback(xmlNode *msg, int call_id, int rc,
xmlNode *output, void *user_data);
int command_options = 0;
const char *cib_action = NULL;
typedef struct str_list_s
{
int num_items;
char *value;
struct str_list_s *next;
} str_list_t;
char *this_msg_reference = NULL;
char *obj_type = NULL;
char *status = NULL;
char *migrate_from = NULL;
char *migrate_res = NULL;
char *subtype = NULL;
char *reset = NULL;
int request_id = 0;
int operation_status = 0;
cib_t *the_cib = NULL;
gboolean force_flag = FALSE;
#define OPTARGS "V?o:QDUCEX:t:Srwlsh:MmBfbRx:pP5N:"
int
main(int argc, char **argv)
{
int argerr = 0;
int flag;
char *admin_input_xml = NULL;
char *admin_input_file = NULL;
gboolean dangerous_cmd = FALSE;
gboolean admin_input_stdin = FALSE;
xmlNode *output = NULL;
xmlNode *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_BUMP, 0, 0, 'B'},
{CIB_OP_SYNC, 0, 0, 'S'},
{CIB_OP_SLAVE, 0, 0, 'r'},
{CIB_OP_MASTER, 0, 0, 'w'},
{CIB_OP_ISMASTER,0, 0, 'm'},
{"md5-sum", 0, 0, '5'},
{"file-mode", 1, 0, 0},
{"force-quorum",0, 0, 'f'},
{"force", 0, 0, 'f'},
{"local", 0, 0, 'l'},
{"sync-call", 0, 0, 's'},
{"no-bcast", 0, 0, 'b'},
{"host", 0, 0, 'h'}, /* legacy */
{"node", 0, 0, 'N'},
- {F_CRM_DATA, 1, 0, 'X'},
+ {F_CRM_DATA, 1, 0, 'X'}, /* legacy */
+ {"xml-text", 1, 0, 'X'},
{"xml-file", 1, 0, 'x'},
{"xml-pipe", 0, 0, 'p'},
{"verbose", 0, 0, 'V'},
{"help", 0, 0, '?'},
{"reference", 1, 0, 0},
{"timeout", 1, 0, 't'},
/* common options */
{"obj_type", 1, 0, 'o'},
{0, 0, 0, 0}
};
#endif
crm_log_init("cibadmin", LOG_CRIT, FALSE, FALSE, argc, argv);
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:
if (safe_str_eq("reference", long_options[option_index].name)) {
this_msg_reference = crm_strdup(optarg);
} else if (safe_str_eq("file-mode", long_options[option_index].name)) {
setenv("CIB_file", optarg, 1);
} else {
printf("Long option (--%s) is not (yet?) properly supported\n",
long_options[option_index].name);
++argerr;
}
break;
#endif
case 't':
message_timeout_ms = atoi(optarg);
if(message_timeout_ms < 1) {
message_timeout_ms = 30;
}
break;
case 'E':
cib_action = CIB_OP_ERASE;
dangerous_cmd = TRUE;
break;
case 'Q':
cib_action = CIB_OP_QUERY;
break;
case 'P':
cib_action = CIB_OP_APPLY_DIFF;
break;
case 'S':
cib_action = CIB_OP_SYNC;
break;
case 'U':
case 'M':
cib_action = CIB_OP_MODIFY;
break;
case 'R':
cib_action = CIB_OP_REPLACE;
break;
case 'C':
cib_action = CIB_OP_CREATE;
break;
case 'D':
cib_action = CIB_OP_DELETE;
break;
case '5':
cib_action = "md5-sum";
break;
case 'm':
cib_action = CIB_OP_ISMASTER;
command_options |= cib_scope_local;
break;
case 'B':
cib_action = CIB_OP_BUMP;
break;
case 'r':
dangerous_cmd = TRUE;
cib_action = CIB_OP_SLAVE;
break;
case 'w':
dangerous_cmd = TRUE;
cib_action = CIB_OP_MASTER;
command_options |= cib_scope_local;
break;
case 'V':
command_options = command_options | cib_verbose;
cl_log_enable_stderr(TRUE);
alter_debug(DEBUG_INC);
break;
case '?':
usage(crm_system_name, LSB_EXIT_OK);
break;
case 'o':
crm_debug_2("Option %c => %s", flag, optarg);
obj_type = crm_strdup(optarg);
break;
case 'X':
crm_debug_2("Option %c => %s", flag, optarg);
admin_input_xml = crm_strdup(optarg);
break;
case 'x':
crm_debug_2("Option %c => %s", flag, optarg);
admin_input_file = crm_strdup(optarg);
break;
case 'p':
admin_input_stdin = TRUE;
break;
case 'h':
host = crm_strdup(optarg);
break;
case 'l':
command_options |= cib_scope_local;
break;
case 'b':
dangerous_cmd = TRUE;
command_options |= cib_inhibit_bcast;
command_options |= cib_scope_local;
break;
case 's':
command_options |= cib_sync_call;
break;
case 'f':
force_flag = TRUE;
command_options |= cib_quorum_override;
break;
default:
printf("Argument code 0%o (%c)"
" is not (?yet?) supported\n",
flag, flag);
++argerr;
break;
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
usage(crm_system_name, LSB_EXIT_EINVAL);
}
if (optind > argc || cib_action == NULL) {
++argerr;
}
if (argerr) {
usage(crm_system_name, LSB_EXIT_GENERIC);
}
if(dangerous_cmd && force_flag == FALSE) {
fprintf(stderr, "The supplied command is considered dangerous."
" To prevent accidental destruction of the cluster,"
" the --force flag is required in order to proceed.\n");
fflush(stderr);
usage(crm_system_name, LSB_EXIT_GENERIC);
}
if(admin_input_file != NULL) {
FILE *xml_strm = fopen(admin_input_file, "r");
input = file2xml(xml_strm, FALSE);
if(input == NULL) {
fprintf(stderr, "Couldn't parse input file: %s\n", admin_input_file);
return 1;
}
fclose(xml_strm);
} else if(admin_input_xml != NULL) {
input = string2xml(admin_input_xml);
if(input == NULL) {
fprintf(stderr, "Couldn't parse input string: %s\n", admin_input_xml);
return 1;
}
} else if(admin_input_stdin) {
input = stdin2xml();
if(input == NULL) {
fprintf(stderr, "Couldn't parse input from STDIN.\n");
return 1;
}
}
if(input != NULL) {
crm_log_xml_debug(input, "[admin input]");
}
if(safe_str_eq(cib_action, "md5-sum")) {
char *digest = NULL;
if(input == NULL) {
fprintf(stderr,
"Please supply XML to process with -X, -x or -p\n");
exit(1);
}
digest = calculate_xml_digest(input, FALSE, FALSE);
fprintf(stderr, "Digest: ");
fprintf(stdout, "%s\n", crm_str(digest));
crm_free(digest);
exit(0);
}
exit_code = do_init();
if(exit_code != cib_ok) {
crm_err("Init failed, could not perform requested operations");
fprintf(stderr, "Init failed, could not perform requested operations\n");
return -exit_code;
}
exit_code = do_work(input, command_options, &output);
if (exit_code > 0) {
/* wait for the reply by creating a mainloop and running it until
* the callbacks are invoked...
*/
request_id = exit_code;
add_cib_op_callback_timeout(
request_id, message_timeout_ms, FALSE, NULL, cibadmin_op_callback);
mainloop = g_main_new(FALSE);
crm_debug_3("%s waiting for reply from the local CIB",
crm_system_name);
crm_info("Starting mainloop");
g_main_run(mainloop);
} else if(exit_code < 0) {
crm_err("Call failed: %s", cib_error2string(exit_code));
fprintf(stderr, "Call failed: %s\n",
cib_error2string(exit_code));
operation_status = exit_code;
}
if(output != NULL) {
char *buffer = dump_xml_formatted(output);
fprintf(stdout, "%s", crm_str(buffer));
crm_free(buffer);
}
the_cib->cmds->signoff(the_cib);
crm_debug_3("%s exiting normally", crm_system_name);
return -exit_code;
}
int
do_work(xmlNode *input, int call_options, xmlNode **output)
{
/* construct the request */
the_cib->call_timeout = message_timeout_ms;
if (strcasecmp(CIB_OP_SYNC, cib_action) == 0) {
crm_debug_4("Performing %s op...", cib_action);
return the_cib->cmds->sync_from(
the_cib, host, obj_type, call_options);
} else if (strcasecmp(CIB_OP_SLAVE, cib_action) == 0
&& (call_options ^ cib_scope_local) ) {
crm_debug_4("Performing %s op on all nodes...", cib_action);
return the_cib->cmds->set_slave_all(the_cib, call_options);
} else if (strcasecmp(CIB_OP_MASTER, cib_action) == 0) {
crm_debug_4("Performing %s op on all nodes...", cib_action);
return the_cib->cmds->set_master(the_cib, call_options);
} else if(cib_action != NULL) {
crm_debug_4("Passing \"%s\" to variant_op...", cib_action);
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) <type>\tobject type being operated on\n",
"obj_type", 'o');
fprintf(stream, "\t\tValid values are: nodes, resources, constraints, crm_config, status\n");
fprintf(stream, "\t--%s (-%c)\tturn on debug info."
" additional instance increase verbosity\n", "verbose", 'V');
fprintf(stream, "\t--%s (-%c)\tthis help message\n", "help", '?');
fprintf(stream, "\nCommands\n");
fprintf(stream, "\t--%s (-%c)\tErase the contents of the whole CIB\n", CIB_OP_ERASE, 'E');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_QUERY, 'Q');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_CREATE, 'C');
fprintf(stream, "\t--%s (-%c)\tCalculate an XML file's digest."
" Requires either -X, -x or -p\n", "md5-sum", '5');
fprintf(stream, "\t--%s (-%c)\tRecursivly replace an object in the CIB\n", CIB_OP_REPLACE,'R');
fprintf(stream, "\t--%s (-%c)\tRecursivly update an object in the CIB\n", CIB_OP_UPDATE, 'U');
fprintf(stream, "\t--%s (-%c)\tFind the object somewhere in the CIB's XML tree and update is as --"CIB_OP_UPDATE" would\n", CIB_OP_MODIFY, 'M');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_DELETE, 'D');
fprintf(stream, "\t\t\tDelete the first object matching the supplied criteria\n");
fprintf(stream, "\t\t\tEg. <op id=\"rsc1_op1\" name=\"monitor\"/>\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_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) <string>\t\tRetrieve XML from the supplied string\n", F_CRM_DATA, 'X');
fprintf(stream, "\t--%s (-%c) <filename>\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);
}
void
cib_connection_destroy(gpointer user_data)
{
crm_err("Connection to the CIB terminated... exiting");
g_main_quit(mainloop);
return;
}
void
cibadmin_op_callback(xmlNode *msg, int call_id, int rc,
xmlNode *output, void *user_data)
{
char *admin_input_xml = NULL;
exit_code = rc;
if(output != NULL) {
admin_input_xml = dump_xml_formatted(output);
}
if(safe_str_eq(cib_action, CIB_OP_ISMASTER) && rc != cib_ok) {
crm_info("CIB on %s is _not_ the master instance",
host?host:"localhost");
fprintf(stderr, "CIB on %s is _not_ the master instance\n",
host?host:"localhost");
} else if(safe_str_eq(cib_action, CIB_OP_ISMASTER)) {
crm_info("CIB on %s _is_ the master instance",
host?host:"localhost");
fprintf(stderr, "CIB on %s _is_ the master instance\n",
host?host:"localhost");
} else if(rc != 0) {
crm_warn("Call %s failed (%d): %s",
cib_action, rc, cib_error2string(rc));
fprintf(stderr, "Call %s failed (%d): %s\n",
cib_action, rc, cib_error2string(rc));
fprintf(stdout, "%s\n", crm_str(admin_input_xml));
} else if(safe_str_eq(cib_action, CIB_OP_QUERY) && output==NULL) {
crm_err("Output expected in query response");
crm_log_xml(LOG_ERR, "no output", msg);
} else if(output == NULL) {
crm_info("Call passed");
} else {
crm_info("Call passed");
fprintf(stdout, "%s\n", crm_str(admin_input_xml));
}
crm_free(admin_input_xml);
if(call_id == request_id) {
g_main_quit(mainloop);
} else {
crm_info("Message was not the response we were looking for (%d vs. %d", call_id, request_id);
}
}
diff --git a/crm/admin/crm_mon.c b/crm/admin/crm_mon.c
index 8f97879df3..f5a3c2570b 100644
--- a/crm/admin/crm_mon.c
+++ b/crm/admin/crm_mon.c
@@ -1,1015 +1,1015 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <crm_internal.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <clplumbing/uids.h>
#include <clplumbing/cl_pidfile.h>
#include <clplumbing/Gmain_timeout.h>
#include <crm/msg_xml.h>
#include <crm/common/util.h>
#include <crm/common/xml.h>
#include <crm/common/ctrl.h>
#include <crm/common/ipc.h>
#include <crm/cib.h>
#include <crm/pengine/status.h>
#include <lib/crm/pengine/unpack.h>
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
/* GMainLoop *mainloop = NULL; */
#define OPTARGS "V?i:nrh:cdp:s1wX:oft"
void usage(const char *cmd, int exit_status);
void blank_screen(void);
int print_status(xmlNode *cib);
void print_warn(const char *descr);
int print_simple_status(xmlNode *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(xmlNode *cib, const char *filename, gboolean web_cgi);
void make_daemon(gboolean daemonize, const char *pidfile);
gboolean mon_timer_popped(gpointer data);
void mon_update(xmlNode*, int, int, xmlNode*,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;
gboolean print_failcount = FALSE;
gboolean print_operations = FALSE;
gboolean print_timing = FALSE;
#if CURSES_ENABLED
# define print_as(fmt...) if(as_console) { \
printw(fmt); \
clrtoeol(); \
refresh(); \
} 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'},
- {"failcounts", 0, 0, 'f'},
- {"operations", 0, 0, 'o'},
+ {"verbose", 0, 0, 'V'},
+ {"help", 0, 0, '?'},
+ {"interval", 1, 0, 'i'},
+ {"group-by-node", 0, 0, 'n'},
+ {"inactive", 0, 0, 'r'},
+ {"failcounts", 0, 0, 'f'},
+ {"operations", 0, 0, 'o'},
{"timing-details", 0, 0, 't'},
- {"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'},
+ {"as-html", 1, 0, 'h'},
+ {"web-cgi", 0, 0, 'w'},
+ {"simple-status", 0, 0, 's'},
+ {"as-console", 0, 0, 'c'},
+ {"one-shot", 0, 0, '1'},
+ {"daemonize", 0, 0, 'd'},
+ {"pid-file", 0, 0, 'p'},
+ {"xml-file", 1, 0, 'x'},
{0, 0, 0, 0}
};
#endif
pid_file = crm_strdup("/tmp/ClusterMon.pid");
crm_log_init(basename(argv[0]), LOG_ERR-1, FALSE, FALSE, 0, NULL);
if (strcmp(crm_system_name, "crm_mon.cgi")==0) {
web_cgi = TRUE;
one_shot = TRUE;
}
while (1) {
#ifdef HAVE_GETOPT_H
flag = getopt_long(argc, argv, OPTARGS,
long_options, &option_index);
#else
flag = getopt(argc, argv, OPTARGS);
#endif
if (flag == -1)
break;
switch(flag) {
case 'V':
cl_log_enable_stderr(TRUE);
alter_debug(DEBUG_INC);
break;
case 'i':
interval = crm_get_msec(optarg);
break;
case 'n':
group_by_node = TRUE;
break;
case 'r':
inactive_resources = TRUE;
break;
case 'd':
daemonize = TRUE;
break;
case 't':
print_timing = TRUE;
print_operations = TRUE;
break;
case 'o':
print_operations = TRUE;
break;
case 'f':
print_failcount = 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;
case '?':
usage(crm_system_name, LSB_EXIT_OK);
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");
xmlNode *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|cib_sync_call;
static gboolean need_pass = TRUE;
xmlNode *output = NULL;
if(timer_id > 0) {
Gmain_timeout_remove(timer_id);
}
if(cib_conn == NULL) {
crm_debug_4("Creating CIB connection");
cib_conn = cib_new();
CRM_CHECK(cib_conn != NULL, return FALSE);
}
if(as_console) {
print_as("Updating...\n");
} else {
crm_notice("Updating...");
}
if(cib_conn->state != cib_connected_query
&& cib_conn->state != cib_connected_command) {
crm_debug_4("Connecting to the CIB");
if(as_console) {
print_as("Signing on...\n");
}
if(need_pass && cib_conn->variant == cib_remote) {
need_pass = FALSE;
print_as("Password:");
}
if(cib_ok == cib_conn->cmds->signon(
cib_conn, crm_system_name, cib_query)) {
failed_connections = 0;
} else if (simple_status || one_shot) {
fprintf(stdout, "Critical: Unable to connect to the CIB\n");
exit(2);
} else {
failed_connections++;
CRM_DEV_ASSERT(cib_conn->cmds->signoff(cib_conn) == cib_ok);
wait_for_refresh(0, "Not connected: ", 2*interval);
return FALSE;
}
}
if(as_console) {
blank_screen();
print_as("Querying...\n");
}
rc = cib_conn->cmds->query(cib_conn, NULL, &output, options);
mon_update(NULL, 0, rc, output, NULL);
free_xml(output);
/* add_cib_op_callback(rc, FALSE, NULL, mon_update); */
return FALSE;
}
void
mon_update(xmlNode *msg, int call_id, int rc,
xmlNode *output, void*user_data)
{
const char *prefix = NULL;
if(rc == cib_ok) {
xmlNode *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(LSB_EXIT_GENERIC);
} else if(one_shot) {
fprintf(stderr, "Query failed: %s", cib_error2string(rc));
exit(LSB_EXIT_GENERIC);
} else {
CRM_DEV_ASSERT(cib_conn->cmds->signoff(cib_conn) == cib_ok);
print_as("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(xmlNode *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;
}
extern int get_failcount(node_t *node, resource_t *rsc, int *last_failure, pe_working_set_t *data_set);
static void print_date(time_t time)
{
int lpc = 0;
char date_str[26];
asctime_r(localtime(&time), date_str);
for(; lpc < 26; lpc++) {
if(date_str[lpc] == '\n') {
date_str[lpc] = 0;
}
}
print_as("'%s'", date_str);
}
static void print_rsc_summary(pe_working_set_t *data_set, node_t *node, resource_t *rsc, gboolean all)
{
gboolean printed = FALSE;
time_t last_failure = 0;
int failcount = get_failcount(node, rsc, (int*)&last_failure, data_set);
if(all || failcount || last_failure > 0) {
printed = TRUE;
print_as(" %s: migration-threshold=%d",
rsc->id, rsc->migration_threshold);
}
if(failcount > 0) {
printed = TRUE;
print_as(" fail-count=%d", failcount);
}
if(last_failure > 0) {
printed = TRUE;
print_as(" last-failure=");
print_date(last_failure);
}
if(printed) {
print_as("\n");
}
}
static void print_rsc_history(pe_working_set_t *data_set, node_t *node, xmlNode *rsc_entry)
{
GListPtr op_list = NULL;
gboolean print_name = TRUE;
GListPtr sorted_op_list = NULL;
const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID);
resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
xml_child_iter_filter(
rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP,
op_list = g_list_append(op_list, rsc_op);
);
sorted_op_list = g_list_sort(op_list, sort_op_by_callid);
slist_iter(xml_op, xmlNode, sorted_op_list, lpc,
const char *value = NULL;
const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
const char *op_rc = crm_element_value(xml_op, XML_LRM_ATTR_RC);
const char *interval = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL);
int rc = crm_parse_int(op_rc, "0");
if(safe_str_eq(task, CRMD_ACTION_STATUS)
&& safe_str_eq(interval, "0")) {
task = "probe";
}
if(rc == 7 && safe_str_eq(task, "probe")) {
continue;
} else if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) {
continue;
}
if(print_name) {
print_name = FALSE;
print_rsc_summary(data_set, node, rsc, TRUE);
}
print_as(" + %s:", task);
if(safe_str_neq(interval, "0")) {
print_as(" interval=%sms", interval);
}
if(print_timing) {
int int_value;
value = crm_element_value(xml_op, "last_rc_change");
if(value) {
int_value = crm_parse_int(value, NULL);
print_as(" last-rc-change=");
print_date(int_value);
}
value = crm_element_value(xml_op, "last_run");
if(value) {
int_value = crm_parse_int(value, NULL);
print_as(" last-run=");
print_date(int_value);
}
value = crm_element_value(xml_op, "exec_time");
if(value) {
int_value = crm_parse_int(value, NULL);
print_as(" exec-time=");
print_date(int_value);
}
value = crm_element_value(xml_op, "queue_time");
if(value) {
int_value = crm_parse_int(value, NULL);
print_as(" queue-time=");
print_date(int_value);
}
}
print_as(" rc=%s (%s)\n", op_rc, execra_code2string(rc));
);
/* no need to free the contents */
g_list_free(sorted_op_list);
}
static void print_node_summary(pe_working_set_t *data_set, gboolean operations)
{
xmlNode *lrm_rsc = NULL;
xmlNode *cib_status = get_object_root(XML_CIB_TAG_STATUS, data_set->input);
if(operations) {
print_as("\nOperations:\n");
} else {
print_as("\nMigration summary::\n");
}
xml_child_iter_filter(
cib_status, node_state, XML_CIB_TAG_STATE,
node_t *node = pe_find_node_id(data_set->nodes, ID(node_state));
print_as("* Node %s:\n", crm_element_value(node_state, XML_ATTR_UNAME));
lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE);
lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE);
xml_child_iter_filter(
lrm_rsc, rsc_entry, XML_LRM_TAG_RESOURCE,
if(operations) {
print_rsc_history(data_set, node, rsc_entry);
} else {
const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID);
resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
print_rsc_summary(data_set, node, rsc, FALSE);
}
);
);
}
int
print_status(xmlNode *cib)
{
node_t *dc = NULL;
static int updates = 0;
pe_working_set_t data_set;
char *since_epoch = NULL;
time_t a_time = time(NULL);
int configured_resources = 0;
int print_opts = pe_print_ncurses;
if(as_console) {
blank_screen();
} else {
print_opts = pe_print_printf;
}
updates++;
set_working_set_defaults(&data_set);
data_set.input = cib;
cluster_status(&data_set);
dc = data_set.dc_node;
print_as("\n\n============\n");
if(a_time == (time_t)-1) {
cl_perror("set_node_tstamp(): Invalid time returned");
return 1;
}
since_epoch = ctime(&a_time);
if(since_epoch != NULL) {
print_as("Last updated: %s", since_epoch);
}
if(dc == NULL) {
print_as("Current DC: NONE\n");
} else {
print_as("Current DC: %s (%s)\n",
dc->details->uname, dc->details->id);
}
slist_iter(rsc, resource_t, data_set.resources, lpc,
if(is_not_set(rsc->flags, pe_rsc_orphan)) {
configured_resources++;
}
);
print_as("%d Nodes configured.\n", g_list_length(data_set.nodes));
print_as("%d Resources configured.\n", configured_resources);
print_as("============\n\n");
slist_iter(node, node_t, data_set.nodes, lpc2,
const char *node_mode = "OFFLINE";
if(node->details->standby && node->details->online) {
node_mode = "standby";
} else if(node->details->standby) {
node_mode = "OFFLINE (standby)";
} else if(node->details->online) {
node_mode = "online";
}
print_as("Node: %s (%s): %s\n",
node->details->uname, node->details->id,
node_mode);
if(group_by_node) {
slist_iter(rsc, resource_t,
node->details->running_rsc, lpc2,
rsc->fns->print(
rsc, "\t", print_opts|pe_print_rsconly, stdout);
);
}
);
if(group_by_node == FALSE && inactive_resources) {
print_as("\nFull list of resources:\n");
} else if(inactive_resources) {
print_as("\nInactive resources:\n");
}
if(group_by_node == FALSE || inactive_resources) {
print_as("\n");
slist_iter(rsc, resource_t, data_set.resources, lpc2,
gboolean is_active = rsc->fns->active(rsc, TRUE);
gboolean partially_active = rsc->fns->active(rsc, FALSE);
if(is_set(rsc->flags, pe_rsc_orphan) && is_active == FALSE) {
continue;
} else if(group_by_node == FALSE) {
if(partially_active || inactive_resources) {
rsc->fns->print(rsc, NULL, print_opts, stdout);
}
} else if(is_active == FALSE && inactive_resources) {
rsc->fns->print(rsc, NULL, print_opts, stdout);
}
);
}
if(print_operations || print_failcount) {
print_node_summary(&data_set, print_operations);
}
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 *last = crm_element_value(xml_op, "last_run");
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",
id, node, call, rc);
if(last) {
time_t run_at = crm_parse_int(last, "0");
print_as(", last-run=%s, queued=%sms, exec=%sms\n",
ctime(&run_at),
crm_element_value(xml_op, "exec_time"),
crm_element_value(xml_op, "queue_time"));
}
print_as("): %s\n", 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(xmlNode *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");
if(stream == NULL) {
cl_perror("Cannot open %s for writing", filename_tmp);
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, "<html>");
fprintf(stream, "<head>");
fprintf(stream, "<title>Cluster status</title>");
/* content="%d;url=http://webdesign.about.com" */
fprintf(stream,
"<meta http-equiv=\"refresh\" content=\"%d\">", interval);
fprintf(stream, "</head>");
/*** SUMMARY ***/
fprintf(stream, "<h2>Cluster summary</h2>");
{
char *now_str = NULL;
time_t now = time(NULL);
now_str = ctime(&now);
now_str[24] = EOS; /* replace the newline */
fprintf(stream, "Last updated: <b>%s</b><br/>\n", now_str);
}
if(dc == NULL) {
fprintf(stream, "Current DC: <font color=\"red\"><b>NONE</b></font><br/>");
} else {
fprintf(stream, "Current DC: %s (%s)<br/>",
dc->details->uname, dc->details->id);
}
fprintf(stream, "%d Nodes configured.<br/>",
g_list_length(data_set.nodes));
fprintf(stream, "%d Resources configured.<br/>",
g_list_length(data_set.resources));
/*** CONFIG ***/
fprintf(stream, "<h3>Config Options</h3>\n");
fprintf(stream, "<table>\n");
fprintf(stream, "<tr><td>Default resource stickiness</td><td>:</td><td>%d</td></tr>\n",
data_set.default_resource_stickiness);
fprintf(stream, "<tr><td>STONITH of failed nodes</td><td>:</td><td>%s</td></tr>\n",
data_set.stonith_enabled?"enabled":"disabled");
fprintf(stream, "<tr><td>Cluster is</td><td>:</td><td>%ssymmetric</td></tr>\n",
data_set.symmetric_cluster?"":"a-");
fprintf(stream, "<tr><td>No Quorum Policy</td><td>:</td><td>");
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</td></tr>\n</table>\n");
/*** NODE LIST ***/
fprintf(stream, "<h2>Node List</h2>\n");
fprintf(stream, "<ul>\n");
slist_iter(node, node_t, data_set.nodes, lpc2,
fprintf(stream, "<li>");
fprintf(stream, "Node: %s (%s): %s",
node->details->uname, node->details->id,
node->details->online?"<font color=\"green\">online</font>\n":"<font color=\"orange\"><b>OFFLINE</b></font>\n");
if(group_by_node) {
fprintf(stream, "<ul>\n");
slist_iter(rsc, resource_t,
node->details->running_rsc, lpc2,
fprintf(stream, "<li>");
rsc->fns->print(rsc, NULL,
pe_print_html, stream);
fprintf(stream, "</li>\n");
);
fprintf(stream, "</ul>\n");
}
fprintf(stream, "</li>\n");
);
fprintf(stream, "</ul>\n");
if(group_by_node && inactive_resources) {
fprintf(stream, "<h2>(Partially) Inactive Resources</h2>\n");
} else if(group_by_node == FALSE) {
fprintf(stream, "<h2>Resource List</h2>\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, "</html>");
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);
refresh();
#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) <seconds>\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 resource fail counts\n", "failcount", 'f');
fprintf(stream, "\t--%s (-%c) \t: Display resource operation history\n", "operations", 'o');
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) <filename>\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) <filename>\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(0);
close(1);
close(2);
(void)open(devnull, O_RDONLY); /* Stdin: fd 0 */
(void)open(devnull, O_WRONLY); /* Stdout: fd 1 */
(void)open(devnull, O_WRONLY); /* Stderr: fd 2 */
}
diff --git a/crm/admin/crm_resource.c b/crm/admin/crm_resource.c
index cea59530f3..85564a973c 100644
--- a/crm/admin/crm_resource.c
+++ b/crm/admin/crm_resource.c
@@ -1,1464 +1,1464 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <crm_internal.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <clplumbing/uids.h>
#include <clplumbing/Gmain_timeout.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/ctrl.h>
#include <crm/common/ipc.h>
#include <crm/cib.h>
#include <crm/pengine/rules.h>
#include <crm/pengine/status.h>
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
void usage(const char *cmd, int exit_status);
gboolean do_force = FALSE;
gboolean BE_QUIET = FALSE;
const char *attr_set_type = XML_TAG_ATTR_SETS;
char *host_id = NULL;
const char *rsc_id = NULL;
const char *host_uname = NULL;
const char *prop_name = NULL;
const char *prop_value = NULL;
const char *rsc_type = NULL;
const char *prop_id = NULL;
const char *prop_set = NULL;
char *migrate_lifetime = NULL;
char rsc_cmd = 'L';
char *our_pid = NULL;
IPC_Channel *crmd_channel = NULL;
char *xml_file = NULL;
int cib_options = cib_sync_call;
-#define OPTARGS "V?LRQxDCPp:WMUr:H:h:v:t:p:g:d:i:s:G:S:fX:lmu:FOoc"
+#define OPTARGS "V?LRQxDCPp:WMUr:H:h:v:t:p:g:d:i:s:G:S:fX:lmu:FOocq"
#define CMD_ERR(fmt, args...) do { \
crm_warn(fmt, ##args); \
fprintf(stderr, fmt, ##args); \
} while(0)
static int
do_find_resource(const char *rsc, pe_working_set_t *data_set)
{
int found = 0;
resource_t *the_rsc = pe_find_resource(data_set->resources, rsc);
if(the_rsc == NULL) {
return cib_NOTEXISTS;
}
slist_iter(node, node_t, the_rsc->running_on, lpc,
crm_debug_3("resource %s is running on: %s",
rsc, node->details->uname);
if(BE_QUIET) {
fprintf(stdout, "%s\n", node->details->uname);
} else {
fprintf(stdout, "resource %s is running on: %s\n",
rsc, node->details->uname);
}
found++;
);
if(BE_QUIET == FALSE && found == 0) {
fprintf(stderr, "resource %s is NOT running\n", rsc);
}
return 0;
}
#define cons_string(x) x?x:"NA"
static void
print_cts_constraints(pe_working_set_t *data_set)
{
xmlNode *lifetime = NULL;
xmlNode * cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, data_set->input);
xml_child_iter(cib_constraints, xml_obj,
const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
if(id == NULL) {
continue;
}
lifetime = first_named_child(xml_obj, "lifetime");
if(test_ruleset(lifetime, NULL, data_set->now) == FALSE) {
continue;
}
if(safe_str_eq(XML_CONS_TAG_RSC_DEPEND, crm_element_name(xml_obj))) {
printf("Constraint %s %s %s %s %s %s %s\n",
crm_element_name(xml_obj),
cons_string(crm_element_value(xml_obj, XML_ATTR_ID)),
cons_string(crm_element_value(xml_obj, XML_CONS_ATTR_FROM)),
cons_string(crm_element_value(xml_obj, XML_CONS_ATTR_TO)),
cons_string(crm_element_value(xml_obj, XML_RULE_ATTR_SCORE)),
cons_string(crm_element_value(xml_obj, XML_RULE_ATTR_FROMSTATE)),
cons_string(crm_element_value(xml_obj, XML_RULE_ATTR_TOSTATE)));
} else if(safe_str_eq(XML_CONS_TAG_RSC_LOCATION, crm_element_name(xml_obj))) {
/* unpack_rsc_location(xml_obj, data_set); */
}
);
}
static void
print_cts_rsc(resource_t *rsc)
{
gboolean needs_quorum = TRUE;
const char *p_id = "NA";
if(rsc->parent) {
p_id = rsc->parent->id;
}
xml_child_iter_filter(rsc->ops_xml, op, "op",
const char *name = crm_element_value(op, "name");
if(safe_str_neq(name, CRMD_ACTION_START)) {
const char *value = crm_element_value(op, "prereq");
if(safe_str_eq(value, "nothing")) {
needs_quorum = FALSE;
}
break;
}
);
printf("Resource: %s %s %s %d %d\n", crm_element_name(rsc->xml), rsc->id, p_id,
is_set(rsc->flags, pe_rsc_managed), needs_quorum);
slist_iter(child, resource_t, rsc->children, lpc,
print_cts_rsc(child);
);
}
static void
print_raw_rsc(resource_t *rsc)
{
GListPtr children = rsc->fns->children(rsc);
if(children == NULL) {
printf("%s\n", rsc->id);
}
slist_iter(child, resource_t, children, lpc,
print_raw_rsc(child);
);
}
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(is_set(rsc->flags, pe_rsc_orphan)
&& rsc->fns->active(rsc, TRUE) == FALSE) {
continue;
}
rsc->fns->print(
rsc, NULL, pe_print_printf|pe_print_rsconly, stdout);
found++;
);
if(found == 0) {
printf("NO resources configured\n");
return cib_NOTEXISTS;
}
return 0;
}
static int
dump_resource(const char *rsc, pe_working_set_t *data_set)
{
char *rsc_xml = NULL;
resource_t *the_rsc = pe_find_resource(data_set->resources, rsc);
if(the_rsc == NULL) {
return cib_NOTEXISTS;
}
the_rsc->fns->print(the_rsc, NULL, pe_print_printf, stdout);
rsc_xml = dump_xml_formatted(the_rsc->xml);
fprintf(stdout, "raw xml:\n%s", rsc_xml);
crm_free(rsc_xml);
return 0;
}
static int
dump_resource_attr(
const char *rsc, const char *attr, pe_working_set_t *data_set)
{
node_t *current = NULL;
resource_t *the_rsc = pe_find_resource(data_set->resources, rsc);
const char *value = NULL;
if(the_rsc == NULL) {
return cib_NOTEXISTS;
}
if(g_list_length(the_rsc->running_on) == 1) {
current = the_rsc->running_on->data;
} else if(g_list_length(the_rsc->running_on) > 1) {
CMD_ERR("%s is active on more than one node,"
" returning the default value for %s\n",
the_rsc->id, crm_str(value));
}
unpack_instance_attributes(
the_rsc->xml, attr_set_type, current?current->details->attrs:NULL,
the_rsc->parameters, NULL, FALSE, 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;
xmlNode *xml_top = NULL;
xmlNode *xml_obj = NULL;
xmlNode *nv_children = NULL;
xmlNode *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:"<any>");
if(matches == 0) {
/* nothing more to search */
crm_debug("No objects matching tag=%s id=%s",
attr_set_type, attr_set?attr_set:"<any>");
} else if(attr_id == NULL) {
matches = find_xml_children(
&nv_children, set_children,
XML_CIB_TAG_NVPAIR, XML_NVPAIR_ATTR_NAME, attr_name, FALSE);
crm_log_xml_debug(nv_children, "search by name:");
} else {
matches = find_xml_children(
&nv_children, set_children,
XML_CIB_TAG_NVPAIR, XML_ATTR_ID, attr_id, FALSE);
crm_log_xml_debug(nv_children, "search by id:");
}
if(matches > 1) {
CMD_ERR("Multiple attributes match name=%s for the resource %s:\n",
attr_name, rsc->id);
if(set_children == NULL) {
free_xml(set_children);
set_children = NULL;
find_xml_children(
&set_children, rsc->xml,
attr_set_type, NULL, NULL, FALSE);
xml_child_iter(
set_children, set,
free_xml(nv_children);
nv_children = NULL;
find_xml_children(
&nv_children, set,
XML_CIB_TAG_NVPAIR, XML_NVPAIR_ATTR_NAME, attr_name, FALSE);
xml_child_iter(
nv_children, child,
fprintf(stderr," Set: %s,\tValue: %s,\tID: %s\n",
ID(set),
crm_element_value(child, XML_NVPAIR_ATTR_VALUE),
ID(child));
);
);
} else {
xml_child_iter(
nv_children, child,
fprintf(stderr," ID: %s, Value: %s\n", ID(child),
crm_element_value(child, XML_NVPAIR_ATTR_VALUE));
);
}
if(BE_QUIET == FALSE) {
CMD_ERR("\nThe following text can be suppressed with the -Q option:\n");
if(attr_set == NULL) {
CMD_ERR(" * To choose an existing entry to change, please supply one of the set names above using the -s option.\n");
} else {
CMD_ERR(" * To choose an existing entry to change, please supply one of the IDs above using the -i option.\n");
}
CMD_ERR(" * To create a new value with a default ID, please supply a different set name using the -s option.\n");
CMD_ERR("You can also use --query-xml to display the complete resource definition.\n");
}
return cib_unknown;
} else if(matches == 0) {
if(attr_set == NULL) {
if(safe_str_eq(attr_set_type, XML_TAG_META_SETS)) {
local_attr_set = crm_concat(rsc->id, "meta-options", '-');
} else {
local_attr_set = crm_strdup(rsc->id);
}
attr_set = local_attr_set;
}
if(attr_id == NULL) {
local_attr_id = crm_concat(attr_set, attr_name, '-');
attr_id = local_attr_id;
}
xml_top = create_xml_node(NULL, crm_element_name(rsc->xml));
crm_xml_add(xml_top, XML_ATTR_ID, rsc->id);
xml_obj = create_xml_node(xml_top, attr_set_type);
crm_xml_add(xml_obj, XML_ATTR_ID, attr_set);
xml_obj = create_xml_node(xml_obj, XML_TAG_ATTRS);
xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR);
} else {
if(attr_id == NULL) {
/* extract it */
xml_child_iter(nv_children, child, attr_id = ID(child));
}
xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR);
xml_top = xml_obj;
}
crm_xml_add(xml_obj, XML_ATTR_ID, attr_id);
crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name);
crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value);
crm_log_xml_debug(xml_top, "Update");
rc = cib->cmds->modify(cib, XML_CIB_TAG_RESOURCES, xml_top, NULL,
cib_options);
free_xml(xml_top);
crm_free(local_attr_id);
crm_free(local_attr_set);
return rc;
}
static int
delete_resource_attr(
const char *rsc_id, const char *attr_set, const char *attr_id,
const char *attr_name, cib_t *cib, pe_working_set_t *data_set)
{
xmlNode *xml_obj = NULL;
xmlNode *xml_match = NULL;
int rc = cib_ok;
char *local_attr_id = NULL;
resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
if(rsc == NULL) {
return cib_NOTEXISTS;
}
rc = find_attr_details(
rsc->xml, NULL, attr_set, attr_id, attr_name, &xml_match, TRUE);
if(rc == cib_NOTEXISTS) {
return cib_ok;
}
if(rc != cib_ok) {
return rc;
}
if(attr_id == NULL) {
local_attr_id = crm_element_value_copy(xml_match, XML_ATTR_ID);
attr_id = local_attr_id;
}
xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR);
crm_xml_add(xml_obj, XML_ATTR_ID, attr_id);
crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name);
crm_log_xml_debug(xml_obj, "Delete");
rc = cib->cmds->delete(cib, XML_CIB_TAG_RESOURCES, xml_obj, NULL,
cib_options);
free_xml(xml_obj);
free_xml(xml_match);
crm_free(local_attr_id);
return rc;
}
static int
dump_resource_prop(
const char *rsc, const char *attr, pe_working_set_t *data_set)
{
const char *value = NULL;
resource_t *the_rsc = pe_find_resource(data_set->resources, rsc);
if(the_rsc == NULL) {
return cib_NOTEXISTS;
}
value = crm_element_value(the_rsc->xml, attr);
if(value != NULL) {
fprintf(stdout, "%s\n", value);
return 0;
}
return cib_NOTEXISTS;
}
static void
resource_ipc_connection_destroy(gpointer user_data)
{
crm_info("Connection to CRMd was terminated");
exit(1);
}
static gboolean
crmd_msg_callback(IPC_Channel * server, void *private_data)
{
int lpc = 0;
IPC_Message *msg = NULL;
gboolean hack_return_good = TRUE;
while (server->ch_status != IPC_DISCONNECT
&& server->ops->is_message_pending(server) == TRUE) {
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++;
msg->msg_done(msg);
}
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;
xmlNode *cmd = NULL;
xmlNode *xml_rsc = NULL;
const char *value = NULL;
xmlNode *params = NULL;
xmlNode *msg_data = NULL;
resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
if(rsc == NULL) {
CMD_ERR("Resource %s not found\n", rsc_id);
return cib_NOTEXISTS;
} else if(rsc->variant != pe_native) {
CMD_ERR("We can only process primitive resources, not %s\n", rsc_id);
return cib_invalid_argument;
} else if(host_uname == NULL) {
CMD_ERR("Please supply a hostname with -H\n");
return cib_invalid_argument;
}
key = crm_concat("0:0:crm-resource", our_pid, '-');
msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key);
xml_rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE);
crm_xml_add(xml_rsc, XML_ATTR_ID, rsc->id);
crm_xml_add(xml_rsc, XML_ATTR_ID_LONG, rsc->long_name);
value = crm_element_value(rsc->xml, XML_ATTR_TYPE);
crm_xml_add(xml_rsc, XML_ATTR_TYPE, value);
if(value == NULL) {
CMD_ERR("%s has no type! Aborting...\n", rsc_id);
return cib_NOTEXISTS;
}
value = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, value);
if(value == NULL) {
CMD_ERR("%s has no class! Aborting...\n", rsc_id);
return cib_NOTEXISTS;
}
value = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER, value);
params = create_xml_node(msg_data, XML_TAG_ATTRS);
crm_xml_add(params, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
crm_xml_add(params, CRM_META"_"XML_LRM_ATTR_INTERVAL, "60000"); /* 1 minute */
cmd = create_request(op, msg_data, host_uname,
CRM_SYSTEM_CRMD, crm_system_name, our_pid);
/* crm_log_xml_warn(cmd, "send_lrm_rsc_op"); */
free_xml(msg_data);
crm_free(key);
if(send_ipc_message(crmd_channel, cmd)) {
rc = 0;
sleep(1); /* dont exit striaght away, give the crmd time
* to process our request
*/
} else {
CMD_ERR("Could not send %s op to the crmd", op);
}
free_xml(cmd);
return rc;
}
static int
delete_lrm_rsc(IPC_Channel *crmd_channel, const char *host_uname,
const char *rsc_id, pe_working_set_t *data_set)
{
return send_lrm_rsc_op(crmd_channel, CRM_OP_LRM_DELETE, host_uname, rsc_id, TRUE, data_set);
}
static int
fail_lrm_rsc(IPC_Channel *crmd_channel, const char *host_uname,
const char *rsc_id, pe_working_set_t *data_set)
{
crm_warn("Failing: %s", rsc_id);
return send_lrm_rsc_op(crmd_channel, CRM_OP_LRM_FAIL, host_uname, rsc_id, FALSE, data_set);
}
static int
refresh_lrm(IPC_Channel *crmd_channel, const char *host_uname)
{
xmlNode *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;
}
free_xml(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;
xmlNode *cib = NULL;
xmlNode *rule = NULL;
xmlNode *expr = NULL;
xmlNode *constraints = NULL;
xmlNode *fragment = NULL;
xmlNode *lifetime = NULL;
xmlNode *can_run = NULL;
xmlNode *dont_run = NULL;
fragment = create_cib_fragment(NULL, NULL);
cib = fragment;
CRM_DEV_ASSERT(safe_str_eq(crm_element_name(cib), XML_TAG_CIB));
constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib);
id = crm_concat("cli-prefer", rsc_id, '-');
can_run = create_xml_node(NULL, XML_CONS_TAG_RSC_LOCATION);
crm_xml_add(can_run, XML_ATTR_ID, id);
crm_free(id);
id = crm_concat("cli-standby", rsc_id, '-');
dont_run = create_xml_node(NULL, XML_CONS_TAG_RSC_LOCATION);
crm_xml_add(dont_run, XML_ATTR_ID, id);
crm_free(id);
if(migrate_lifetime) {
char *life = crm_strdup(migrate_lifetime);
char *life_mutable = life;
ha_time_t *now = NULL;
ha_time_t *later = NULL;
ha_time_t *duration = parse_time_duration(&life_mutable);
if(duration == NULL) {
CMD_ERR("Invalid duration specified: %s\n",
migrate_lifetime);
CMD_ERR("Please refer to"
" http://en.wikipedia.org/wiki/ISO_8601#Duration"
" for examples of valid durations\n");
crm_free(life);
return cib_invalid_argument;
}
now = new_ha_date(TRUE);
later = add_time(now, duration);
log_date(LOG_INFO, "now ", now, ha_log_date|ha_log_time);
log_date(LOG_INFO, "later ", later, ha_log_date|ha_log_time);
log_date(LOG_INFO, "duration", duration, ha_log_date|ha_log_time|ha_log_local);
later_s = date_to_string(later, ha_log_date|ha_log_time);
printf("Migration will take effect until: %s\n", later_s);
free_ha_date(duration);
free_ha_date(later);
free_ha_date(now);
crm_free(life);
}
if(existing_node == NULL) {
crm_log_xml_notice(can_run, "Deleting");
rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_CONSTRAINTS,
dont_run, NULL, cib_options);
if(rc == cib_NOTEXISTS) {
rc = cib_ok;
} else if(rc != cib_ok) {
goto bail;
}
} else {
if(BE_QUIET == FALSE) {
fprintf(stderr,
"WARNING: Creating rsc_location constraint '%s'"
" with a score of -INFINITY for resource %s"
" on %s.\n",
ID(dont_run), rsc_id, existing_node);
CMD_ERR("\tThis will prevent %s from running"
" on %s until the constraint is removed using"
" the 'crm_resource -U' command or manually"
" with cibadmin\n", rsc_id, existing_node);
CMD_ERR("\tThis will be the case even if %s is"
" the last node in the cluster\n", existing_node);
CMD_ERR("\tThis messgae can be disabled with -Q\n");
}
crm_xml_add(dont_run, "rsc", rsc_id);
if(later_s) {
lifetime = create_xml_node(dont_run, "lifetime");
rule = create_xml_node(lifetime, XML_TAG_RULE);
id = crm_concat("cli-standby-lifetime", rsc_id, '-');
crm_xml_add(rule, XML_ATTR_ID, id);
crm_free(id);
expr = create_xml_node(rule, "date_expression");
id = crm_concat("cli-standby-lifetime-end",rsc_id,'-');
crm_xml_add(expr, XML_ATTR_ID, id);
crm_free(id);
crm_xml_add(expr, "operation", "lt");
crm_xml_add(expr, "end", later_s);
}
rule = create_xml_node(dont_run, XML_TAG_RULE);
expr = create_xml_node(rule, XML_TAG_EXPRESSION);
id = crm_concat("cli-standby-rule", rsc_id, '-');
crm_xml_add(rule, XML_ATTR_ID, id);
crm_free(id);
crm_xml_add(rule, XML_RULE_ATTR_SCORE, MINUS_INFINITY_S);
id = crm_concat("cli-standby-expr", rsc_id, '-');
crm_xml_add(expr, XML_ATTR_ID, id);
crm_free(id);
crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, "#uname");
crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq");
crm_xml_add(expr, XML_EXPR_ATTR_VALUE, existing_node);
crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string");
add_node_copy(constraints, dont_run);
}
if(preferred_node == NULL) {
crm_log_xml_notice(can_run, "Deleting");
rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_CONSTRAINTS,
can_run, NULL, cib_options);
if(rc == cib_NOTEXISTS) {
rc = cib_ok;
} else if(rc != cib_ok) {
goto bail;
}
} else {
crm_xml_add(can_run, "rsc", rsc_id);
if(later_s) {
lifetime = create_xml_node(can_run, "lifetime");
rule = create_xml_node(lifetime, XML_TAG_RULE);
id = crm_concat("cli-prefer-lifetime", rsc_id, '-');
crm_xml_add(rule, XML_ATTR_ID, id);
crm_free(id);
expr = create_xml_node(rule, "date_expression");
id = crm_concat("cli-prefer-lifetime-end", rsc_id, '-');
crm_xml_add(expr, XML_ATTR_ID, id);
crm_free(id);
crm_xml_add(expr, "operation", "lt");
crm_xml_add(expr, "end", later_s);
}
rule = create_xml_node(can_run, XML_TAG_RULE);
expr = create_xml_node(rule, XML_TAG_EXPRESSION);
id = crm_concat("cli-prefer-rule", rsc_id, '-');
crm_xml_add(rule, XML_ATTR_ID, id);
crm_free(id);
crm_xml_add(rule, XML_RULE_ATTR_SCORE, INFINITY_S);
id = crm_concat("cli-prefer-expr", rsc_id, '-');
crm_xml_add(expr, XML_ATTR_ID, id);
crm_free(id);
crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, "#uname");
crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq");
crm_xml_add(expr, XML_EXPR_ATTR_VALUE, preferred_node);
crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string");
add_node_copy(constraints, can_run);
}
if(preferred_node != NULL || existing_node != NULL) {
crm_log_xml_notice(fragment, "CLI Update");
rc = cib_conn->cmds->update(cib_conn, XML_CIB_TAG_CONSTRAINTS,
fragment, NULL, cib_options);
}
bail:
free_xml(fragment);
free_xml(dont_run);
free_xml(can_run);
crm_free(later_s);
return rc;
}
static int
list_resource_operations(const char *rsc_id, const char *host_uname, gboolean active, pe_working_set_t *data_set)
{
resource_t *rsc = NULL;
int opts = pe_print_printf|pe_print_rsconly|pe_print_suppres_nl;
GListPtr ops = find_operations(rsc_id, host_uname, active, data_set);
slist_iter(xml_op, xmlNode, ops, lpc,
const char *op_rsc = crm_element_value(xml_op, "resource");
const char *last = crm_element_value(xml_op, "last_run");
const char *status_s = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS);
int status = crm_parse_int(status_s, "0");
rsc = pe_find_resource(data_set->resources, op_rsc);
rsc->fns->print(rsc, "", opts, stdout);
fprintf(stdout, ": %s (node=%s, call=%s, rc=%s",
ID(xml_op),
crm_element_value(xml_op, XML_ATTR_UNAME),
crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
crm_element_value(xml_op, XML_LRM_ATTR_RC));
if(last) {
time_t run_at = crm_parse_int(last, "0");
fprintf(stdout, ", last-run=%s, exec=%sms\n",
ctime(&run_at), crm_element_value(xml_op, "exec_time"));
}
fprintf(stdout, "): %s\n", op_status2text(status));
);
return cib_ok;
}
int
main(int argc, char **argv)
{
pe_working_set_t data_set;
xmlNode *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'},
{"list-cts", 0, 0, 'c'},
{"refresh", 0, 0, 'R'},
{"reprobe", 0, 0, 'P'},
- {"query-xml", 0, 0, 'x'},
+ {"query-xml", 0, 0, 'q'},
{"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'}, /* legacy */
{"node", 1, 0, 'N'},
{"lifetime", 1, 0, 'u'},
{"fail", 0, 0, 'F'},
{"force", 0, 0, 'f'},
{"meta", 0, 0, 'm'},
{"list-operations", 0, 0, 'O'},
{"list-all-operations", 0, 0, 'o'},
{"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'},
{"set-name", 1, 0, 's'},
{"resource-type", 1, 0, 't'},
- {"xml-file", 0, 0, 'X'},
+ {"xml-file", 0, 0, 'x'},
{0, 0, 0, 0}
};
#endif
crm_log_init(basename(argv[0]), LOG_ERR, FALSE, FALSE, argc, argv);
if(argc < 2) {
usage(crm_system_name, LSB_EXIT_EINVAL);
}
while (1) {
#ifdef HAVE_GETOPT_H
flag = getopt_long(argc, argv, OPTARGS,
long_options, &option_index);
#else
flag = getopt(argc, argv, OPTARGS);
#endif
if (flag == -1)
break;
switch(flag) {
case 'V':
cl_log_enable_stderr(TRUE);
alter_debug(DEBUG_INC);
break;
case '?':
usage(crm_system_name, LSB_EXIT_OK);
break;
case 'X':
xml_file = crm_strdup(optarg);
break;
case 'Q':
BE_QUIET = TRUE;
break;
case 'm':
attr_set_type = XML_TAG_META_SETS;
break;
case 'L':
case 'c':
case 'l':
case 'R':
- case 'x':
+ case 'q':
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 'O':
case 'o':
crm_debug_2("Option %c => %s", flag, 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':
case 'H':
crm_debug_2("Option %c => %s", flag, optarg);
host_uname = optarg;
break;
default:
CMD_ERR("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag);
++argerr;
break;
}
}
if (optind < argc && argv[optind] != NULL) {
CMD_ERR("non-option ARGV-elements: ");
while (optind < argc && argv[optind] != NULL) {
CMD_ERR("%s ", argv[optind++]);
++argerr;
}
CMD_ERR("\n");
}
if (optind > argc) {
++argerr;
}
if (argerr) {
usage(crm_system_name, LSB_EXIT_GENERIC);
}
crm_malloc0(our_pid, 11);
if(our_pid != NULL) {
snprintf(our_pid, 10, "%d", getpid());
our_pid[10] = '\0';
}
if(do_force) {
crm_debug("Forcing...");
cib_options |= cib_scope_local|cib_quorum_override;
}
if(rsc_cmd == 'L'
|| rsc_cmd == 'O'
|| rsc_cmd == 'o'
|| rsc_cmd == 'W'
|| rsc_cmd == 'D'
- || rsc_cmd == 'x'
+ || rsc_cmd == 'q'
|| 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 == 'c'
|| rsc_cmd == 'l') {
resource_t *rsc = NULL;
if(xml_file != NULL) {
FILE *xml_strm = fopen(xml_file, "r");
if(strstr(xml_file, ".bz2") != NULL) {
cib_xml_copy = file2xml(xml_strm, TRUE);
} else {
cib_xml_copy = file2xml(xml_strm, FALSE);
}
if(xml_strm != NULL) {
fclose(xml_strm);
}
} else {
cib_conn = cib_new();
rc = cib_conn->cmds->signon(
cib_conn, crm_system_name, cib_command_synchronous);
if(rc != cib_ok) {
CMD_ERR("Error signing on to the CIB service: %s\n",
cib_error2string(rc));
return rc;
}
cib_xml_copy = get_cib_copy(cib_conn);
}
set_working_set_defaults(&data_set);
data_set.input = cib_xml_copy;
data_set.now = new_ha_date(TRUE);
cluster_status(&data_set);
rsc = pe_find_resource(data_set.resources, rsc_id);
if(rsc != NULL) {
rsc_id = rsc->id;
} else {
rc = cib_NOTEXISTS;
}
}
if(rsc_cmd == 'R'
|| rsc_cmd == 'C'
|| rsc_cmd == 'F'
|| rsc_cmd == 'P') {
GCHSource *src = NULL;
src = init_client_ipc_comms(CRM_SYSTEM_CRMD, crmd_msg_callback,
NULL, &crmd_channel);
if(src == NULL) {
CMD_ERR("Error signing on to the CRMd service\n");
return 1;
}
send_hello_message(
crmd_channel, our_pid, crm_system_name, "0", "1");
set_IPC_Channel_dnotify(src, resource_ipc_connection_destroy);
}
crm_warn("here i am - 3");
if(rsc_cmd == 'L') {
rc = cib_ok;
do_find_resource_list(&data_set, FALSE);
} else if(rsc_cmd == 'l') {
int found = 0;
rc = cib_ok;
slist_iter(
rsc, resource_t, data_set.resources, lpc,
found++;
print_raw_rsc(rsc);
);
if(found == 0) {
printf("NO resources configured\n");
return cib_NOTEXISTS;
}
} else if(rsc_cmd == 'c') {
int found = 0;
rc = cib_ok;
slist_iter(
rsc, resource_t, data_set.resources, lpc,
found++;
print_cts_rsc(rsc);
);
print_cts_constraints(&data_set);
} else if(rsc_cmd == 'C') {
rc = delete_lrm_rsc(crmd_channel, host_uname, rsc_id, &data_set);
if(rc == cib_ok) {
char *host_uuid = NULL;
char *attr_name = crm_concat("fail-count", rsc_id, '-');
rc = query_node_uuid(cib_conn, host_uname, &host_uuid);
if(rc != cib_ok) {
fprintf(stderr,"Could not map uname=%s to a UUID: %s\n",
host_uname, cib_error2string(rc));
} else {
crm_info("Mapped %s to %s", host_uname, crm_str(host_uuid));
rc = delete_attr(cib_conn, cib_sync_call, XML_CIB_TAG_STATUS, host_uuid, NULL,
NULL, attr_name, NULL, TRUE);
}
}
} else if(rsc_cmd == 'F') {
rc = fail_lrm_rsc(crmd_channel, host_uname, rsc_id, &data_set);
} else if(rsc_cmd == 'O') {
rc = list_resource_operations(rsc_id, host_uname, TRUE, &data_set);
} else if(rsc_cmd == 'o') {
rc = list_resource_operations(rsc_id, host_uname, FALSE, &data_set);
} else if(rc == cib_NOTEXISTS) {
CMD_ERR("Resource %s not found: %s\n",
crm_str(rsc_id), cib_error2string(rc));
} else if(rsc_cmd == 'W') {
if(rsc_id == NULL) {
CMD_ERR("Must supply a resource id with -r\n");
return cib_NOTEXISTS;
}
rc = do_find_resource(rsc_id, &data_set);
- } else if(rsc_cmd == 'x') {
+ } else if(rsc_cmd == 'q') {
if(rsc_id == NULL) {
CMD_ERR("Must supply a resource id with -r\n");
return cib_NOTEXISTS;
}
rc = dump_resource(rsc_id, &data_set);
} else if(rsc_cmd == 'U') {
if(rsc_id == NULL) {
CMD_ERR("Must supply a resource id with -r\n");
return cib_NOTEXISTS;
}
rc = migrate_resource(rsc_id, NULL, NULL, cib_conn);
} else if(rsc_cmd == 'M') {
node_t *dest = NULL;
node_t *current = NULL;
const char *current_uname = NULL;
resource_t *rsc = pe_find_resource(data_set.resources, rsc_id);
if(rsc != NULL && rsc->running_on != NULL) {
current = rsc->running_on->data;
if(current != NULL) {
current_uname = current->details->uname;
}
}
if(host_uname != NULL) {
dest = pe_find_node(data_set.nodes, host_uname);
}
if(rsc == NULL) {
CMD_ERR("Resource %s not migrated:"
" not found\n", rsc_id);
} else if(rsc->variant == pe_native
&& g_list_length(rsc->running_on) > 1) {
CMD_ERR("Resource %s not migrated:"
" active on multiple nodes\n", rsc_id);
} else if(host_uname != NULL && dest == NULL) {
CMD_ERR("Error performing operation: "
"%s is not a known node\n", host_uname);
} else if(host_uname != NULL
&& safe_str_eq(current_uname, host_uname)) {
CMD_ERR("Error performing operation: "
"%s is already active on %s\n",
rsc_id, host_uname);
} else if(current_uname != NULL
&& (do_force || host_uname == NULL)) {
rc = migrate_resource(rsc_id, current_uname,
host_uname, cib_conn);
} else if(host_uname != NULL) {
rc = migrate_resource(
rsc_id, NULL, host_uname, cib_conn);
} else {
CMD_ERR("Resource %s not migrated: "
"not-active and no prefered location"
" specified.\n", rsc_id);
}
} else if(rsc_cmd == 'G') {
if(rsc_id == NULL) {
CMD_ERR("Must supply a resource id with -r\n");
return cib_NOTEXISTS;
}
rc = dump_resource_prop(rsc_id, prop_name, &data_set);
} else if(rsc_cmd == 'S') {
xmlNode *msg_data = NULL;
if(prop_value == NULL || strlen(prop_value) == 0) {
CMD_ERR("You need to supply a value with the -v option\n");
return CIBRES_MISSING_FIELD;
} else if(cib_conn == NULL) {
return cib_connection;
}
if(rsc_id == NULL) {
CMD_ERR("Must supply a resource id with -r\n");
return cib_NOTEXISTS;
}
CRM_DEV_ASSERT(rsc_type != NULL);
CRM_DEV_ASSERT(prop_name != NULL);
CRM_DEV_ASSERT(prop_value != NULL);
msg_data = create_xml_node(NULL, rsc_type);
crm_xml_add(msg_data, XML_ATTR_ID, rsc_id);
crm_xml_add(msg_data, prop_name, prop_value);
rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_RESOURCES,
msg_data, NULL, cib_options);
free_xml(msg_data);
} else if(rsc_cmd == 'g') {
if(rsc_id == NULL) {
CMD_ERR("Must supply a resource id with -r\n");
return cib_NOTEXISTS;
}
rc = dump_resource_attr(rsc_id, prop_name, &data_set);
} else if(rsc_cmd == 'p') {
if(rsc_id == NULL) {
CMD_ERR("Must supply a resource id with -r\n");
return cib_NOTEXISTS;
}
if(prop_value == NULL || strlen(prop_value) == 0) {
CMD_ERR("You need to supply a value with the -v option\n");
return CIBRES_MISSING_FIELD;
}
rc = set_resource_attr(rsc_id, prop_set, prop_id, prop_name,
prop_value, cib_conn, &data_set);
} else if(rsc_cmd == 'd') {
if(rsc_id == NULL) {
CMD_ERR("Must supply a resource id with -r\n");
return cib_NOTEXISTS;
}
rc = delete_resource_attr(rsc_id, prop_set, prop_id, prop_name,
cib_conn, &data_set);
} else if(rsc_cmd == 'P') {
xmlNode *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);
free_xml(cmd);
} else if(rsc_cmd == 'R') {
refresh_lrm(crmd_channel, host_uname);
} else if(rsc_cmd == 'D') {
xmlNode *msg_data = NULL;
if(rsc_id == NULL) {
CMD_ERR("Must supply a resource id with -r\n");
return cib_NOTEXISTS;
}
if(rsc_type == NULL) {
CMD_ERR("You need to specify a resource type with -t");
return cib_NOTEXISTS;
} else if(cib_conn == NULL) {
return cib_connection;
}
msg_data = create_xml_node(NULL, rsc_type);
crm_xml_add(msg_data, XML_ATTR_ID, rsc_id);
rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_RESOURCES,
msg_data, NULL, cib_options);
free_xml(msg_data);
} else {
CMD_ERR("Unknown command: %c\n", rsc_cmd);
}
if(cib_conn != NULL) {
cleanup_calculations(&data_set);
cib_conn->cmds->signoff(cib_conn);
}
if(rc == cib_no_quorum) {
CMD_ERR("Error performing operation: %s\n",
cib_error2string(rc));
CMD_ERR("Try using -f\n");
} else if(rc != cib_ok) {
CMD_ERR("Error performing operation: %s\n",
cib_error2string(rc));
}
return rc;
}
void
usage(const char *cmd, int exit_status)
{
FILE *stream;
stream = exit_status ? stderr : stdout;
fprintf(stream, "usage: %s [-?VS] -(L|Q|W|D|C|P|p) [options]\n", cmd);
fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?');
fprintf(stream, "\t--%s (-%c)\t: "
"turn on debug info. additional instances increase verbosity\n",
"verbose", 'V');
fprintf(stream, "\t--%s (-%c)\t: Print only the value on stdout (for use with -W)\n",
"quiet", 'Q');
fprintf(stream, "\nCommands\n");
fprintf(stream, "\t--%s (-%c)\t: List all resources\n", "list", 'L');
fprintf(stream, "\t--%s (-%c)\t: Query a resource\n"
- "\t\t\t Requires: -r\n", "query-xml", 'x');
+ "\t\t\t Requires: -r\n", "query-xml", '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: 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) <string>\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) <string>\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) <string>: "
"Delete the named parameter for a resource\n"
"\t\t\t Requires: -r. Optional: -i, --meta\n", "delete-parameter", 'd');
fprintf(stream, "\t--%s (-%c) <string>: "
"List the active resource operations. Optionally filtered by resource and/or node.\n"
"\t\t\t Optional: -H, -r\n", "list-operations", 'O');
fprintf(stream, "\t--%s (-%c) <string>: "
"List all resource operations. Optionally filtered by resource and/or node.\n"
"\t\t\t Optional: -N, -r\n", "list-all-operations", 'o');
fprintf(stream, "\nOptions\n");
fprintf(stream, "\t--%s (-%c) <string>\t: Resource ID\n", "resource", 'r');
fprintf(stream, "\t--%s (-%c) <string>\t: "
"Resource type (primitive, clone, group, ...)\n",
"resource-type", 't');
fprintf(stream, "\t--%s (-%c) <string>\t: "
"Property value\n", "property-value", 'v');
fprintf(stream, "\t--%s (-%c) <string>\t: Host uname\n", "node", 'N');
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) <string>\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 <string>\t: (Advanced Use Only) ID of the instance_attributes object to change\n", 's');
fprintf(stream, "\t-%c <string>\t: (Advanced Use Only) ID of the nvpair object to change/delete\n", 'i');
fflush(stream);
exit(exit_status);
}
diff --git a/crm/admin/crm_verify.c b/crm/admin/crm_verify.c
index 3c0d41dab5..b6f47939bd 100644
--- a/crm/admin/crm_verify.c
+++ b/crm/admin/crm_verify.c
@@ -1,320 +1,321 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <crm_internal.h>
#include <crm/crm.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <crm/common/xml.h>
#include <crm/common/util.h>
#include <crm/msg_xml.h>
#include <clplumbing/cl_signal.h>
#include <crm/cib.h>
#include <clplumbing/lsb_exitcodes.h>
#define OPTARGS "V?X:x:pLS:D:"
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
#include <glib.h>
#include <crm/pengine/status.h>
gboolean USE_LIVE_CIB = FALSE;
char *cib_save = NULL;
void usage(const char *cmd, int exit_status);
extern gboolean stage0(pe_working_set_t *data_set);
extern void cleanup_alloc_calculations(pe_working_set_t *data_set);
extern xmlNode * do_calculations(
pe_working_set_t *data_set, xmlNode *xml_input, ha_time_t *now);
const char *dtd_file = DTD_DIRECTORY"/crm.dtd";
int
main(int argc, char **argv)
{
xmlNode *cib_object = NULL;
xmlNode *status = NULL;
int argerr = 0;
int flag;
pe_working_set_t data_set;
cib_t * cib_conn = NULL;
int rc = cib_ok;
gboolean xml_stdin = FALSE;
const char *xml_file = NULL;
const char *xml_string = NULL;
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*/
crm_log_init(basename(argv[0]), LOG_ERR, FALSE, TRUE, 0, NULL);
CL_SIGNAL(DEBUG_INC, alter_debug);
CL_SIGNAL(DEBUG_DEC, alter_debug);
while (1) {
#ifdef HAVE_GETOPT_H
int option_index = 0;
static struct option long_options[] = {
/* Top-level Options */
- {F_CRM_DATA, 1, 0, 'X'},
{"dtd-file", 1, 0, 'D'},
+ {F_CRM_DATA, 1, 0, 'X'}, /* legacy */
+ {"xml-text", 1, 0, 'X'},
{"xml-file", 1, 0, 'x'},
{"xml-pipe", 0, 0, 'p'},
{"save-xml", 1, 0, 'S'},
{"live-check", 0, 0, 'L'},
{"help", 0, 0, '?'},
{0, 0, 0, 0}
};
#endif
#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");
break;
#endif
case 'D':
crm_debug_2("Option %c => %s", flag, optarg);
dtd_file = optarg;
break;
case 'X':
crm_debug_2("Option %c => %s", flag, optarg);
xml_string = crm_strdup(optarg);
break;
case 'x':
crm_debug_2("Option %c => %s", flag, optarg);
xml_file = crm_strdup(optarg);
break;
case 'p':
xml_stdin = TRUE;
break;
case 'S':
cib_save = crm_strdup(optarg);
break;
case 'V':
alter_debug(DEBUG_INC);
break;
case 'L':
USE_LIVE_CIB = TRUE;
break;
case '?':
usage(crm_system_name, LSB_EXIT_OK);
break;
default:
printf("?? getopt returned character code 0%o ??\n", flag);
++argerr;
break;
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc) {
printf("%s ", argv[optind++]);
}
printf("\n");
}
if (optind > argc) {
++argerr;
}
if (argerr) {
crm_err("%d errors in option parsing", argerr);
usage(crm_system_name, LSB_EXIT_GENERIC);
}
crm_info("=#=#=#=#= Getting XML =#=#=#=#=");
if(USE_LIVE_CIB) {
cib_conn = cib_new();
rc = cib_conn->cmds->signon(
cib_conn, crm_system_name, cib_command_synchronous);
}
if(USE_LIVE_CIB) {
if(rc == cib_ok) {
int options = cib_scope_local|cib_sync_call;
crm_info("Reading XML from: live cluster");
rc = cib_conn->cmds->query(
cib_conn, NULL, &cib_object, options);
}
if(rc != cib_ok) {
fprintf(stderr, "Live CIB query failed: %s\n",
cib_error2string(rc));
return 3;
}
if(cib_object == NULL) {
fprintf(stderr, "Live CIB query failed: empty result\n");
return 3;
}
} else if(xml_file != NULL) {
FILE *xml_strm = fopen(xml_file, "r");
cib_object = file2xml(xml_strm, FALSE);
if(cib_object == NULL) {
fprintf(stderr,
"Couldn't parse input file: %s\n", xml_file);
return 1;
}
fclose(xml_strm);
} else if(xml_string != NULL) {
cib_object = string2xml(xml_string);
if(cib_object == NULL) {
fprintf(stderr,
"Couldn't parse input string: %s\n", xml_string);
return 1;
}
} else if(xml_stdin) {
cib_object = stdin2xml();
if(cib_object == NULL) {
fprintf(stderr, "Couldn't parse input from STDIN.\n");
return 1;
}
} else {
fprintf(stderr, "No configuration source specified."
" Use --help for usage information.\n");
return 3;
}
if(cib_save != NULL) {
write_xml_file(cib_object, cib_save, FALSE);
}
status = get_object_root(XML_CIB_TAG_STATUS, cib_object);
if(status == NULL) {
create_xml_node(cib_object, XML_CIB_TAG_STATUS);
}
#if CRM_DEPRECATED_SINCE_2_0_4
xml_child_iter_filter(status, node_state, XML_CIB_TAG_STATE,
xml_remove_prop(node_state, XML_CIB_TAG_LRM);
);
#endif
crm_notice("Required feature set: %s", feature_set(cib_object));
if(do_id_check(cib_object, NULL, FALSE, FALSE)) {
crm_config_err("ID Check failed");
}
if(validate_with_dtd(cib_object, FALSE, dtd_file) == FALSE) {
crm_config_err("CIB did not pass DTD validation");
}
if(USE_LIVE_CIB) {
/* we will always have a status section and can do a full simulation */
do_calculations(&data_set, cib_object, NULL);
} else {
set_working_set_defaults(&data_set);
data_set.now = new_ha_date(TRUE);
data_set.input = cib_object;
stage0(&data_set);
}
cleanup_alloc_calculations(&data_set);
if(crm_config_error) {
fprintf(stderr, "Errors found during check: config not valid\n");
if(crm_log_level < LOG_WARNING) {
fprintf(stderr, " -V may provide more details\n");
}
rc = 2;
} else if(crm_config_warning) {
fprintf(stderr, "Warnings found during check: config may not be valid\n");
if(crm_log_level < LOG_WARNING) {
fprintf(stderr, " Use -V for more details\n");
}
rc = 1;
}
if(USE_LIVE_CIB) {
cib_conn->cmds->signoff(cib_conn);
cib_delete(cib_conn);
}
return rc;
}
void
usage(const char *cmd, int exit_status)
{
FILE *stream;
stream = exit_status ? stderr : stdout;
fprintf(stream, "usage: %s [-V] [-D] -(?|L|X|x|p)\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: Connect to the running cluster\n",
"live-check", 'L');
fprintf(stream, "\t--%s (-%c) <string>\t: Use the configuration in the supplied string\n",
F_CRM_DATA, 'X');
fprintf(stream, "\t--%s (-%c) <file>\t: Use the configuration in the named file\n",
"xml-file", 'x');
fprintf(stream, "\t--%s (-%c) \t: Use the configuration piped in via stdin\n",
"xml-pipe", 'p');
fprintf(stream, "\t--%s (-%c) \t: Use the named dtd file instead of %s\n",
"dtd-file", 'D', dtd_file);
fflush(stream);
exit(exit_status);
}
diff --git a/pengine/ptest.c b/pengine/ptest.c
index 86b92b88ae..fc305822d0 100644
--- a/pengine/ptest.c
+++ b/pengine/ptest.c
@@ -1,516 +1,517 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <crm_internal.h>
#include <crm/crm.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <crm/transition.h>
#include <crm/common/xml.h>
#include <crm/common/util.h>
#include <crm/msg_xml.h>
#include <crm/cib.h>
#define OPTARGS "V?X:D:G:I:Lwxd:aSs"
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
#include <glib.h>
#include <pengine.h>
#include <lib/crm/pengine/utils.h>
#include <allocate.h>
#if HAVE_LIBXML2
# include <libxml/parser.h>
#endif
gboolean use_stdin = FALSE;
gboolean do_simulation = FALSE;
gboolean inhibit_exit = FALSE;
gboolean all_actions = FALSE;
extern xmlNode * do_calculations(
pe_working_set_t *data_set, xmlNode *xml_input, ha_time_t *now);
extern void cleanup_calculations(pe_working_set_t *data_set);
char *use_date = NULL;
FILE *dot_strm = NULL;
#define DOT_PREFIX "PE_DOT: "
/* #define DOT_PREFIX "" */
#define dot_write(fmt...) if(dot_strm != NULL) { \
fprintf(dot_strm, fmt); \
fprintf(dot_strm, "\n"); \
} else { \
crm_debug(DOT_PREFIX""fmt); \
}
static void
init_dotfile(void)
{
dot_write(" digraph \"g\" {");
/* dot_write(" size = \"30,30\""); */
/* dot_write(" graph ["); */
/* dot_write(" fontsize = \"12\""); */
/* dot_write(" fontname = \"Times-Roman\""); */
/* dot_write(" fontcolor = \"black\""); */
/* dot_write(" bb = \"0,0,398.922306,478.927856\""); */
/* dot_write(" color = \"black\""); */
/* dot_write(" ]"); */
/* dot_write(" node ["); */
/* dot_write(" fontsize = \"12\""); */
/* dot_write(" fontname = \"Times-Roman\""); */
/* dot_write(" fontcolor = \"black\""); */
/* dot_write(" shape = \"ellipse\""); */
/* dot_write(" color = \"black\""); */
/* dot_write(" ]"); */
/* dot_write(" edge ["); */
/* dot_write(" fontsize = \"12\""); */
/* dot_write(" fontname = \"Times-Roman\""); */
/* dot_write(" fontcolor = \"black\""); */
/* dot_write(" color = \"black\""); */
/* dot_write(" ]"); */
}
static void
usage(const char *cli, int exitcode)
{
FILE *out = exitcode?stderr:stdout;
fprintf(out, "Usage: %s -(?|L|X|x) [-V] [-D] [-G] [-I]\n", cli);
fprintf(out, " --%s (-%c): This text\n\n", "help", '?');
fprintf(out, " --%s (-%c): Increase verbosity (can be supplied multiple times)\n\n", "verbose", 'V');
fprintf(out, " --%s (-%c): Connect to the CIB and use the current contents as input\n", "live-check", 'L');
fprintf(out, " --%s (-%c): Look for xml on stdin\n", "xml-stream", 'x');
fprintf(out, " --%s (-%c): Display resource allocation scores\n", "show-scores", 's');
fprintf(out, " --%s (-%c)\t<filename> : Look for xml in the named file\n\n", "xml-file", 'X');
fprintf(out, " --%s (-%c)\t<filename> : Save the transition graph to the named file\n", "save-graph", 'G');
fprintf(out, " --%s (-%c)\t<filename> : Save the DOT formatted transition graph to the named file\n", "save-dotfile", 'D');
fprintf(out, " --%s (-%c)\t<filename> : Save the input to the named file\n", "save-input", 'I');
exit(exitcode);
}
static char *
create_action_name(action_t *action)
{
char *action_name = NULL;
const char *action_host = NULL;
if(action->node) {
action_host = action->node->details->uname;
action_name = crm_concat(action->uuid, action_host, ' ');
} else if(action->pseudo) {
action_name = crm_strdup(action->uuid);
} else {
action_host = "<none>";
action_name = crm_concat(action->uuid, action_host, ' ');
}
if(safe_str_eq(action->task, RSC_CANCEL)) {
char *tmp_action_name = action_name;
action_name = crm_concat("Cancel", tmp_action_name, ' ');
crm_free(tmp_action_name);
}
return action_name;
}
gboolean USE_LIVE_CIB = FALSE;
int
main(int argc, char **argv)
{
gboolean all_good = TRUE;
gboolean show_scores = FALSE;
enum transition_status graph_rc = -1;
crm_graph_t *transition = NULL;
ha_time_t *a_date = NULL;
cib_t * cib_conn = NULL;
xmlNode * cib_object = NULL;
int argerr = 0;
int flag;
char *msg_buffer = NULL;
gboolean optional = FALSE;
pe_working_set_t data_set;
const char *source = NULL;
const char *xml_file = NULL;
const char *dot_file = NULL;
const char *graph_file = NULL;
const char *input_file = NULL;
cl_log_set_entity("ptest");
cl_log_set_facility(LOG_USER);
set_crm_log_level(LOG_CRIT-1);
while (1) {
#ifdef HAVE_GETOPT_H
int option_index = 0;
static struct option long_options[] = {
/* Top-level Options */
{"help", 0, 0, '?'},
{"verbose", 0, 0, 'V'},
{"live-check", 0, 0, 'L'},
- {"xml-stream", 0, 0, 'x'},
{"show-scores", 0, 0, 's'},
- {"xml-file", 1, 0, 'X'},
+ {"xml-text", 0, 0, 'X'},
+ {"xml-file", 1, 0, 'x'},
+ {"xml-pipe", 1, 0, 'p'},
{"simulate", 0, 0, 'S'},
{"save-graph", 1, 0, 'G'},
{"save-dotfile",1, 0, 'D'},
{"save-input", 1, 0, 'I'},
{0, 0, 0, 0}
};
#endif
#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");
break;
#endif
case 'S':
do_simulation = TRUE;
break;
case 'a':
all_actions = TRUE;
break;
case 'w':
inhibit_exit = TRUE;
break;
case 'x':
use_stdin = TRUE;
break;
case 's':
show_scores = TRUE;
scores_log_level = crm_log_level;
break;
case 'X':
xml_file = optarg;
break;
case 'd':
use_date = optarg;
break;
case 'D':
dot_file = optarg;
break;
case 'G':
graph_file = optarg;
break;
case 'I':
input_file = optarg;
break;
case 'V':
cl_log_enable_stderr(TRUE);
alter_debug(DEBUG_INC);
if(show_scores) {
scores_log_level = crm_log_level;
}
break;
case 'L':
USE_LIVE_CIB = TRUE;
break;
case '?':
usage("ptest", 0);
break;
default:
printf("?? getopt returned character code 0%o ??\n", flag);
++argerr;
break;
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc) {
printf("%s ", argv[optind++]);
}
printf("\n");
}
if (optind > argc) {
++argerr;
}
if (argerr) {
crm_err("%d errors in option parsing", argerr);
usage("ptest", 1);
}
crm_info("=#=#=#=#= Getting XML =#=#=#=#=");
if(USE_LIVE_CIB) {
int rc = cib_ok;
source = "live cib";
cib_conn = cib_new();
rc = cib_conn->cmds->signon(
cib_conn, "ptest", cib_command_synchronous);
if(rc == cib_ok) {
crm_info("Reading XML from: live cluster");
cib_object = get_cib_copy(cib_conn);
} else {
fprintf(stderr, "Live CIB query failed: %s\n",
cib_error2string(rc));
return 3;
}
if(cib_object == NULL) {
fprintf(stderr, "Live CIB query failed: empty result\n");
return 3;
}
} else if(xml_file != NULL) {
FILE *xml_strm = fopen(xml_file, "r");
source = xml_file;
if(xml_strm == NULL) {
cl_perror("Could not open %s for reading", xml_file);
} else {
if(strstr(xml_file, ".bz2") != NULL) {
cib_object = file2xml(xml_strm, TRUE);
} else {
cib_object = file2xml(xml_strm, FALSE);
}
fclose(xml_strm);
}
} else if(use_stdin) {
source = "stdin";
cib_object = stdin2xml();
}
if(cib_object == NULL && source) {
fprintf(stderr, "Could not parse configuration input from: %s\n", source);
return 4;
} else if(cib_object == NULL) {
fprintf(stderr, "Not configuration specified\n");
usage("ptest", 1);
}
crm_notice("Required feature set: %s", feature_set(cib_object));
do_id_check(cib_object, NULL, FALSE, FALSE);
if(!validate_with_dtd(cib_object,FALSE,DTD_DIRECTORY"/crm.dtd")) {
crm_crit("%s does not contain a valid configuration", xml_file?xml_file:"<stdin>");
all_good = FALSE;
}
if(input_file != NULL) {
FILE *input_strm = fopen(input_file, "w");
if(input_strm == NULL) {
cl_perror("Could not open %s for writing", input_file);
} else {
msg_buffer = dump_xml_formatted(cib_object);
if(fprintf(input_strm, "%s\n", msg_buffer) < 0) {
cl_perror("Write to %s failed", input_file);
}
fflush(input_strm);
fclose(input_strm);
crm_free(msg_buffer);
}
}
if(use_date != NULL) {
a_date = parse_date(&use_date);
log_date(LOG_WARNING, "Set fake 'now' to",
a_date, ha_log_date|ha_log_time);
log_date(LOG_WARNING, "Set fake 'now' to (localtime)",
a_date, ha_log_date|ha_log_time|ha_log_local);
}
do_calculations(&data_set, cib_object, a_date);
msg_buffer = dump_xml_formatted(data_set.graph);
if(safe_str_eq(graph_file, "-")) {
fprintf(stdout, "%s\n", msg_buffer);
fflush(stdout);
} else if(graph_file != NULL) {
FILE *graph_strm = fopen(graph_file, "w");
if(graph_strm == NULL) {
cl_perror("Could not open %s for writing", graph_file);
} else {
if(fprintf(graph_strm, "%s\n", msg_buffer) < 0) {
cl_perror("Write to %s failed", graph_file);
}
fflush(graph_strm);
fclose(graph_strm);
}
}
crm_free(msg_buffer);
if(dot_file != NULL) {
dot_strm = fopen(dot_file, "w");
if(dot_strm == NULL) {
cl_perror("Could not open %s for writing", dot_file);
}
}
if(dot_strm == NULL) {
goto simulate;
}
init_dotfile();
slist_iter(
action, action_t, data_set.actions, lpc,
const char *style = "filled";
const char *font = "black";
const char *color = "black";
const char *fill = NULL;
char *action_name = create_action_name(action);
crm_debug_3("Action %d: %p", action->id, action);
if(action->pseudo) {
font = "orange";
}
style = "dashed";
if(action->dumped) {
style = "bold";
color = "green";
} else if(action->rsc != NULL
&& is_not_set(action->rsc->flags, pe_rsc_managed)) {
color = "purple";
if(all_actions == FALSE) {
goto dont_write;
}
} else if(action->optional) {
color = "blue";
if(all_actions == FALSE) {
goto dont_write;
}
} else {
color = "red";
CRM_CHECK(action->runnable == FALSE, ;);
}
action->dumped = TRUE;
dot_write("\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\" %s%s]",
action_name, style, color, font, fill?"fillcolor=":"", fill?fill:"");
dont_write:
crm_free(action_name);
);
slist_iter(
action, action_t, data_set.actions, lpc,
slist_iter(
before, action_wrapper_t, action->actions_before, lpc2,
char *before_name = NULL;
char *after_name = NULL;
const char *style = "dashed";
optional = TRUE;
if(before->state == pe_link_dumped) {
optional = FALSE;
style = "bold";
} else if(action->pseudo
&& (before->type & pe_order_stonith_stop)) {
continue;
} else if(before->state == pe_link_dup) {
continue;
} else if(action->dumped && before->action->dumped) {
optional = FALSE;
}
if(all_actions || optional == FALSE) {
before_name = create_action_name(before->action);
after_name = create_action_name(action);
dot_write("\"%s\" -> \"%s\" [ style = %s]",
before_name, after_name, style);
crm_free(before_name);
crm_free(after_name);
}
);
);
dot_write("}");
if(dot_strm != NULL) {
fflush(dot_strm);
fclose(dot_strm);
}
simulate:
if(do_simulation == FALSE) {
goto cleanup;
}
transition = unpack_graph(data_set.graph);
transition->batch_limit = 0;
print_graph(LOG_DEBUG, transition);
do {
graph_rc = run_graph(transition);
} while(graph_rc == transition_active);
if(graph_rc != transition_complete) {
crm_crit("Transition failed: %s", transition_status(graph_rc));
print_graph(LOG_ERR, transition);
}
destroy_graph(transition);
CRM_CHECK(graph_rc == transition_complete, all_good = FALSE; crm_err("An invalid transition was produced"));
cleanup:
cleanup_alloc_calculations(&data_set);
#if HAVE_LIBXML2
xmlCleanupParser();
#endif
/* required for MallocDebug.app */
if(inhibit_exit) {
GMainLoop* mainloop = g_main_new(FALSE);
g_main_run(mainloop);
}
if(all_good) {
return 0;
}
return 5;
}
diff --git a/pengine/regression.core.sh b/pengine/regression.core.sh
index e7575475e4..06a07d3744 100755
--- a/pengine/regression.core.sh
+++ b/pengine/regression.core.sh
@@ -1,178 +1,178 @@
#!/bin/bash
# Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
#
# 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
#
verbose=$1
io_dir=testcases
diff_opts="--ignore-all-space -u -N"
failed=.regression.failed.diff
# zero out the error log
> $failed
num_failed=0
function ptest() {
if [ "x$VALGRIND_CMD" != "x" ]; then
ptest_cmd=`which ptest`
elif [ -x ptest ]; then
ptest_cmd=./ptest
else
echo No ptest executable in current directory using installed version
ptest_cmd=`which ptest`
fi
#echo $VALGRIND_CMD $ptest_cmd $*
$VALGRIND_CMD $ptest_cmd $*
}
function do_test {
base=$1; shift
name=$1; shift
input=$io_dir/${base}.xml
output=$io_dir/${base}.pe.out
expected=$io_dir/${base}.exp
te_output=$io_dir/${base}.te.out
te_expected=$io_dir/${base}.te.exp
dot_output=$io_dir/${base}.pe.dot
dot_expected=$io_dir/${base}.dot
dot_png=$io_dir/${base}.png
if [ ! -f $input ]; then
echo "Test $name ($base)... Error (PE : input)";
num_failed=`expr $num_failed + 1`
return;
fi
echo "Test $base : $name";
if [ "$create_mode" != "true" -a ! -f $expected ]; then
echo " Error (PE : expected)";
# return;
fi
# ../admin/crm_verify -X $input
- ptest -V -X $input -D $dot_output -G $output -S $*
+ ptest -V -x $input -D $dot_output -G $output -S $*
if [ $? != 0 ]; then
echo " * Failed (PE : rc)";
num_failed=`expr $num_failed + 1`
fi
if [ -s core ]; then
echo " Moved core to core.${base}";
num_failed=`expr $num_failed + 1`
rm -f core.$base
mv core core.$base
fi
if [ ! -s $output ]; then
echo " Error (PE : no graph)";
num_failed=`expr $num_failed + 1`
rm $output
return;
fi
if [ ! -s $dot_output ]; then
echo " Error (PE : no dot-file)";
num_failed=`expr $num_failed + 1`
rm $output
return;
else
echo "digraph \"g\" {" > $dot_output.sort
LC_ALL=POSIX sort -u $dot_output | grep -v -e ^}$ -e digraph >> $dot_output.sort
echo "}" >> $dot_output.sort
mv -f $dot_output.sort $dot_output
fi
if [ "$create_mode" = "true" ]; then
cp "$output" "$expected"
cp "$dot_output" "$dot_expected"
echo " Created expected output (PE)"
fi
diff $diff_opts $dot_expected $dot_output >/dev/null
rc=$?
if [ $rc != 0 ]; then
echo " * Failed (PE : dot)";
diff $diff_opts $dot_expected $dot_output 2>/dev/null >> $failed
echo "" >> $failed
num_failed=`expr $num_failed + 1`
else
rm $dot_output
fi
diff $diff_opts $expected $output >/dev/null
rc2=$?
if [ $rc2 != 0 ]; then
echo " * Failed (PE : raw)";
diff $diff_opts $expected $output 2>/dev/null >> $failed
echo "" >> $failed
num_failed=`expr $num_failed + 1`
else
rm $output
fi
if [ "$test_te" = "true" ]; then
../tengine/ttest -X $output 2> $te_output
# if [ "$create_mode" = "true" ]; then
if [ "$create_mode" = "true" -a ! -f $te_expected ]; then
cp "$te_output" "$te_expected"
fi
if [ -f $te_expected ]; then
diff $diff_opts -q $te_expected $te_output >/dev/null
rc=$?
fi
if [ "$create_mode" = "true" ]; then
echo "Test $name ($base)... Created expected output (PE)"
elif [ ! -f $te_expected ]; then
echo "==== Raw results for TE test ($base) ====" >> $failed
cat $te_output 2>/dev/null >> $failed
elif [ "$rc" = 0 ]; then
:
elif [ "$rc" = 1 ]; then
echo "Test $name ($base)... * Failed (TE)";
diff $diff_opts $te_expected $te_output 2>/dev/null >> $failed
diff $diff_opts $te_expected $te_output
else
echo "Test $name ($base)... Error TE (diff: $rc)";
echo "==== Raw results for test ($base) TE ====" >> $failed
cat $te_output 2>/dev/null >> $failed
fi
fi
rm -f $output $te_output
}
function test_results {
if [ $num_failed != 0 ]; then
if [ -s $failed ]; then
if [ "$verbose" = "-v" ]; then
echo "Results of $num_failed failed tests...."
less $failed
else
echo "Results of $num_failed failed tests are in $failed...."
echo "Use $0 -v to display them automatically."
fi
else
echo "$num_failed tests failed (no diff results)"
rm $failed
fi
fi
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Jun 25, 2:34 AM (13 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1951887
Default Alt Text
(109 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment