Page MenuHomeClusterLabs Projects

No OneTemporary

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

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)

Event Timeline