Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/crm/admin/cibadmin.c b/crm/admin/cibadmin.c
index 6b912650b7..fab5619dd6 100644
--- a/crm/admin/cibadmin.c
+++ b/crm/admin/cibadmin.c
@@ -1,566 +1,567 @@
/*
* 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:pP5"
+#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'},
+ {"host", 0, 0, 'h'}, /* legacy */
+ {"node", 0, 0, 'N'},
{F_CRM_DATA, 1, 0, 'X'},
{"xml-file", 1, 0, 'x'},
{"xml-pipe", 0, 0, 'p'},
{"verbose", 0, 0, 'V'},
{"help", 0, 0, '?'},
{"reference", 1, 0, 0},
{"timeout", 1, 0, 't'},
/* common options */
{"obj_type", 1, 0, 'o'},
{0, 0, 0, 0}
};
#endif
crm_log_init("cibadmin", LOG_CRIT, FALSE, FALSE, argc, argv);
if(argc < 2) {
usage(crm_system_name, LSB_EXIT_EINVAL);
}
while (1) {
#ifdef HAVE_GETOPT_H
flag = getopt_long(argc, argv, OPTARGS,
long_options, &option_index);
#else
flag = getopt(argc, argv, OPTARGS);
#endif
if (flag == -1)
break;
switch(flag) {
#ifdef HAVE_GETOPT_H
case 0:
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_attribute.c b/crm/admin/crm_attribute.c
index 43ef4d99c0..bc6858738e 100644
--- a/crm/admin/crm_attribute.c
+++ b/crm/admin/crm_attribute.c
@@ -1,494 +1,492 @@
/*
* 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 <time.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 <sys/utsname.h>
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
void usage(const char *cmd, int exit_status);
gboolean BE_QUIET = FALSE;
gboolean DO_WRITE = TRUE;
gboolean DO_DELETE = FALSE;
char *dest_node = NULL;
char *set_name = NULL;
char *attr_id = NULL;
char *attr_name = NULL;
const char *type = NULL;
const char *rsc_id = NULL;
const char *dest_uname = NULL;
const char *attr_value = NULL;
-#define OPTARGS "V?GDQU:u:s:n:v:l:t:i:!r:"
+#define OPTARGS "V?GDQN:U:u:s:n:v:l:t:i:!r:"
int
main(int argc, char **argv)
{
gboolean is_done = FALSE;
cib_t * the_cib = NULL;
enum cib_errors rc = cib_ok;
int cib_opts = cib_sync_call;
int argerr = 0;
int flag;
#ifdef HAVE_GETOPT_H
int option_index = 0;
static struct option long_options[] = {
/* Top-level Options */
{"verbose", 0, 0, 'V'},
{"help", 0, 0, '?'},
{"quiet", 0, 0, 'Q'},
{"get-value", 0, 0, 'G'},
{"delete-attr", 0, 0, 'D'},
- {"node-uname", 1, 0, 'U'},
- {"node-uuid", 1, 0, 'u'},
+ {"node", 1, 0, 'N'},
+ {"node-uname", 1, 0, 'U'}, /* legacy */
+ {"node-uuid", 1, 0, 'u'}, /* legacy */
{"set-name", 1, 0, 's'},
{"attr-id", 1, 0, 'i'},
{"attr-name", 1, 0, 'n'},
{"attr-value", 1, 0, 'v'},
{"resource-id", 1, 0, 'r'},
{"lifetime", 1, 0, 'l'},
{"type", 1, 0, 't'},
{"inhibit-policy-engine", 0, 0, '!'},
{0, 0, 0, 0}
};
#endif
crm_log_init(basename(argv[0]), LOG_ERR, FALSE, FALSE, argc, argv);
if(argc < 2) {
usage(crm_system_name, LSB_EXIT_EINVAL);
}
while (1) {
#ifdef HAVE_GETOPT_H
flag = getopt_long(argc, argv, OPTARGS,
long_options, &option_index);
#else
flag = getopt(argc, argv, OPTARGS);
#endif
if (flag == -1)
break;
switch(flag) {
case 'V':
cl_log_enable_stderr(TRUE);
alter_debug(DEBUG_INC);
break;
case '?':
usage(crm_system_name, LSB_EXIT_OK);
break;
case 'G':
DO_WRITE = FALSE;
break;
case 'Q':
BE_QUIET = TRUE;
break;
case 'D':
DO_DELETE = TRUE;
break;
case 'U':
+ case 'N':
crm_debug_2("Option %c => %s", flag, optarg);
dest_uname = optarg;
break;
case 'u':
crm_debug_2("Option %c => %s", flag, optarg);
dest_node = crm_strdup(optarg);
break;
case 's':
crm_debug_2("Option %c => %s", flag, optarg);
set_name = crm_strdup(optarg);
break;
case 'l':
crm_debug_2("Option %c => %s", flag, optarg);
type = optarg;
break;
case 't':
crm_debug_2("Option %c => %s", flag, optarg);
type = optarg;
break;
case 'n':
crm_debug_2("Option %c => %s", flag, optarg);
attr_name = crm_strdup(optarg);
break;
case 'i':
crm_debug_2("Option %c => %s", flag, optarg);
attr_id = crm_strdup(optarg);
break;
case 'v':
crm_debug_2("Option %c => %s", flag, optarg);
attr_value = optarg;
break;
case 'r':
crm_debug_2("Option %c => %s", flag, optarg);
rsc_id = optarg;
break;
case '!':
crm_warn("Inhibiting notifications for this update");
cib_opts |= cib_inhibit_notify;
break;
default:
printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag);
++argerr;
break;
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
if (optind > argc) {
++argerr;
}
if (argerr) {
usage(crm_system_name, LSB_EXIT_GENERIC);
}
the_cib = cib_new();
rc = the_cib->cmds->signon(
the_cib, crm_system_name, cib_command_synchronous);
if(rc != cib_ok) {
fprintf(stderr, "Error signing on to the CIB service: %s\n",
cib_error2string(rc));
return rc;
}
if(safe_str_eq(crm_system_name, "crm_attribute")
&& type == NULL && dest_uname == NULL) {
/* we're updating cluster options - dont populate dest_node */
type = XML_CIB_TAG_CRMCONFIG;
} else if(dest_uname == NULL) {
struct utsname name;
if(uname(&name) < 0) {
cl_perror("uname(2) call failed");
return 1;
}
dest_uname = name.nodename;
crm_info("Detected uname: %s", dest_uname);
}
if(dest_node == NULL && dest_uname != NULL) {
rc = query_node_uuid(the_cib, dest_uname, &dest_node);
if(rc != cib_ok) {
fprintf(stderr,"Could not map uname=%s to a UUID: %s\n",
dest_uname, cib_error2string(rc));
return rc;
} else {
crm_info("Mapped %s to %s",
dest_uname, crm_str(dest_node));
}
}
if(safe_str_eq(crm_system_name, "crm_master")) {
int len = 0;
if(safe_str_eq(type, "reboot")) {
type = XML_CIB_TAG_STATUS;
} else {
type = XML_CIB_TAG_NODES;
}
rsc_id = getenv("OCF_RESOURCE_INSTANCE");
if(rsc_id == NULL && dest_node == NULL) {
fprintf(stderr, "This program should only ever be "
"invoked from inside an OCF resource agent.\n");
fprintf(stderr, "DO NOT INVOKE MANUALLY FROM THE COMMAND LINE.\n");
return 1;
} else if(dest_node == NULL) {
fprintf(stderr, "Could not determine node UUID.\n");
return 1;
} else if(rsc_id == NULL) {
fprintf(stderr, "Could not determine resource name.\n");
return 1;
}
len = 8 + strlen(rsc_id);
crm_malloc0(attr_name, len);
snprintf(attr_name, len, "master-%s", rsc_id);
len = 3 + strlen(type) + strlen(attr_name) + strlen(dest_node);
crm_malloc0(attr_id, len);
snprintf(attr_id, len, "%s-%s-%s", type, attr_name, dest_node);
len = 8 + strlen(dest_node);
crm_malloc0(set_name, len);
snprintf(set_name, len, "master-%s", dest_node);
} else if(safe_str_eq(crm_system_name, "crm_failcount")) {
type = XML_CIB_TAG_STATUS;
if(rsc_id == NULL) {
fprintf(stderr,"Please specify a resource with -r\n");
return 1;
}
if(dest_node == NULL) {
fprintf(stderr,"Please specify a node with -U or -u\n");
return 1;
}
set_name = NULL;
attr_name = crm_concat("fail-count", rsc_id, '-');
} else if(safe_str_eq(crm_system_name, "crm_standby")) {
if(dest_node == NULL) {
fprintf(stderr,"Please specify a node with -U or -u\n");
return 1;
} else if(DO_DELETE) {
rc = delete_standby(
the_cib, dest_node, type, attr_value);
} else if(DO_WRITE) {
if(attr_value == NULL) {
fprintf(stderr, "Please specify 'true' or 'false' with -v\n");
return 1;
}
rc = set_standby(the_cib, dest_node, type, attr_value);
} else {
char *read_value = NULL;
char *scope = NULL;
if(type) {
scope = crm_strdup(type);
}
rc = query_standby(
the_cib, dest_node, &scope, &read_value);
if(BE_QUIET == FALSE) {
if(attr_id) {
fprintf(stdout, "id=%s ", attr_id);
}
if(attr_name) {
fprintf(stdout, "name=%s ", attr_name);
}
fprintf(stdout, "scope=%s value=%s\n",
scope, read_value?read_value:"(null)");
} else if(read_value != NULL) {
fprintf(stdout, "%s\n", read_value);
} else if(rc == cib_NOTEXISTS) {
fprintf(stdout, "off\n");
rc = cib_ok;
}
crm_free(scope);
}
is_done = TRUE;
} else if (type == NULL) {
type = XML_CIB_TAG_NODES;
return 1;
}
if(safe_str_eq(type, XML_CIB_TAG_CRMCONFIG)) {
dest_node = NULL;
}
if(is_done) {
} else if(DO_DELETE) {
rc = delete_attr(the_cib, cib_opts, type, dest_node, set_name,
attr_id, attr_name, attr_value, TRUE);
if(rc == cib_NOTEXISTS) {
/* Nothing to delete...
* which means its not there...
* which is what the admin wanted
*/
rc = cib_ok;
} else if(rc != cib_missing_data
&& safe_str_eq(crm_system_name, "crm_failcount")) {
char *now_s = NULL;
time_t now = time(NULL);
now_s = crm_itoa(now);
update_attr(the_cib, cib_sync_call,
XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL,
"last-lrm-refresh", now_s, TRUE);
crm_free(now_s);
}
} else if(DO_WRITE) {
CRM_DEV_ASSERT(type != NULL);
CRM_DEV_ASSERT(attr_name != NULL);
CRM_DEV_ASSERT(attr_value != NULL);
rc = update_attr(the_cib, cib_opts, type, dest_node, set_name,
attr_id, attr_name, attr_value, TRUE);
} else {
char *read_value = NULL;
rc = read_attr(the_cib, type, dest_node, set_name,
attr_id, attr_name, &read_value, TRUE);
if(rc == cib_NOTEXISTS
&& safe_str_eq(crm_system_name, "crm_failcount")) {
rc = cib_ok;
read_value = crm_strdup("0");
}
crm_info("Read %s=%s %s%s",
attr_name, crm_str(read_value),
set_name?"in ":"", set_name?set_name:"");
if(rc == cib_missing_data) {
rc = cib_ok;
} else if(BE_QUIET == FALSE) {
fprintf(stdout, "%s%s %s%s value=%s\n",
attr_id?"id=":"", attr_id?attr_id:"",
attr_name?"name=":"", attr_name?attr_name:"",
read_value?read_value:"(null)");
} else if(read_value != NULL) {
fprintf(stdout, "%s\n", read_value);
}
}
the_cib->cmds->signoff(the_cib);
if(rc == cib_missing_data) {
printf("Please choose from one of the matches above and suppy the 'id' with --attr-id\n");
} else if(rc != cib_ok) {
fprintf(stderr, "Error performing operation: %s\n",
cib_error2string(rc));
}
return rc;
}
void
usage(const char *cmd, int exit_status)
{
FILE *stream;
stream = exit_status ? stderr : stdout;
if(safe_str_eq(cmd, "crm_master")) {
fprintf(stream, "usage: %s [-?VQ] -(D|G|v) [-l]\n", cmd);
} else if(safe_str_eq(cmd, "crm_standby")) {
fprintf(stream, "usage: %s [-?V] -(u|U) -(D|G|v) [-l]\n", cmd);
} else if(safe_str_eq(cmd, "crm_failcount")) {
fprintf(stream, "usage: %s [-?V] -(u|U) -(D|G|v) -r\n", cmd);
} else {
fprintf(stream, "usage: %s [-?V] -(D|G|v) [options]\n", cmd);
}
fprintf(stream, "Options\n");
fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?');
fprintf(stream, "\t--%s (-%c)\t: "
"turn on debug info. additional instances increase verbosity\n",
"verbose", 'V');
fprintf(stream, "\t--%s (-%c)\t: Print only the value on stdout"
" (use with -G)\n", "quiet", 'Q');
fprintf(stream, "\t--%s (-%c)\t: "
"Retrieve rather than set the %s\n", "get-value", 'G',
safe_str_eq(cmd, "crm_master")?"named attribute":"preference to be promoted");
fprintf(stream, "\t--%s (-%c)\t: "
"Delete rather than set the attribute\n", "delete-attr", 'D');
fprintf(stream, "\t--%s (-%c) <string>\t: "
"Value to use (ignored with -G)\n", "attr-value", 'v');
fprintf(stream, "\t--%s (-%c) <string>\t: "
"The 'id' of the attribute. Advanced use only.\n", "attr-id", 'i');
if(safe_str_eq(cmd, "crm_master")) {
fprintf(stream, "\t--%s (-%c) <string>\t: "
"How long the preference lasts (reboot|forever)\n",
"lifetime", 'l');
exit(exit_status);
} else if(safe_str_eq(cmd, "crm_standby")) {
- fprintf(stream, "\t--%s (-%c) <node_uuid>\t: "
- "UUID of the node to change\n", "node-uuid", 'u');
fprintf(stream, "\t--%s (-%c) <node_uname>\t: "
- "uname of the node to change\n", "node-uname", 'U');
+ "uname of the node to change\n", "node", 'N');
fprintf(stream, "\t--%s (-%c) <string>\t: "
"How long the preference lasts (reboot|forever)\n"
"\t If a forever value exists, it is ALWAYS used by the CRM\n"
"\t instead of any reboot value\n", "lifetime", 'l');
exit(exit_status);
}
- fprintf(stream, "\t--%s (-%c) <node_uuid>\t: "
- "UUID of the node to change\n", "node-uuid", 'u');
fprintf(stream, "\t--%s (-%c) <node_uname>\t: "
- "uname of the node to change\n", "node-uname", 'U');
+ "uname of the node to change\n", "node-uname", 'h');
if(safe_str_eq(cmd, "crm_failcount")) {
fprintf(stream, "\t--%s (-%c) <resource name>\t: "
"name of the resource to operate on\n", "resource-id", 'r');
} else {
fprintf(stream, "\t--%s (-%c) <string>\t: "
"Set of attributes in which to read/write the attribute\n",
"set-name", 's');
fprintf(stream, "\t--%s (-%c) <string>\t: "
"Attribute to set\n", "attr-name", 'n');
fprintf(stream, "\t--%s (-%c) <string>\t: "
"Which section of the CIB to set the attribute: (%s|%s|%s)\n",
"type", 't',
XML_CIB_TAG_NODES, XML_CIB_TAG_STATUS, XML_CIB_TAG_CRMCONFIG);
- fprintf(stream, "\t -t=%s options: -(U|u) -n [-s]\n", XML_CIB_TAG_NODES);
- fprintf(stream, "\t -t=%s options: -(U|u) -n [-s]\n", XML_CIB_TAG_STATUS);
- fprintf(stream, "\t -t=%s options: -n [-s]\n", XML_CIB_TAG_CRMCONFIG);
+ fprintf(stream, "\t -t=%s options: -N -n [-s]\n", XML_CIB_TAG_NODES);
+ fprintf(stream, "\t -t=%s options: -N -n [-s]\n", XML_CIB_TAG_STATUS);
+ fprintf(stream, "\t -t=%s options: -N [-s]\n", XML_CIB_TAG_CRMCONFIG);
}
if(safe_str_neq(crm_system_name, "crm_standby")) {
fprintf(stream, "\t--%s (-%c)\t: "
"Make a change and prevent the TE/PE from seeing it straight away.\n"
"\t You may think you want this option but you don't."
" Advanced use only - you have been warned!\n", "inhibit-policy-engine", '!');
}
fflush(stream);
exit(exit_status);
}
diff --git a/crm/admin/crm_resource.c b/crm/admin/crm_resource.c
index c43e7031ba..cea59530f3 100644
--- a/crm/admin/crm_resource.c
+++ b/crm/admin/crm_resource.c
@@ -1,1463 +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: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:FOoc"
#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'},
{"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'},
+ {"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'},
{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 '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 == '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') {
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');
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: -H, -r\n", "list-all-operations", 'o');
+ "\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 name\n", "host-uname", 'H');
+ 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/tools/pingd.c b/tools/pingd.c
index 9e75e26b29..6abb9da13b 100644
--- a/tools/pingd.c
+++ b/tools/pingd.c
@@ -1,923 +1,925 @@
/*
* 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/Gmain_timeout.h>
#include <clplumbing/lsb_exitcodes.h>
#include <crm/common/ipc.h>
#include <attrd.h>
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/poll.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <sys/un.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <sys/socket.h>
#include <sys/uio.h>
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
#include <clplumbing/Gmain_timeout.h>
#include <clplumbing/lsb_exitcodes.h>
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
#if SUPPORT_HEARTBEAT
# include <hb_api.h>
ll_cluster_t *pingd_cluster = NULL;
void do_node_walk(ll_cluster_t *hb_cluster);
#endif
/* GMainLoop *mainloop = NULL; */
-#define OPTARGS "V?p:a:d:s:S:h:Dm:"
+#define OPTARGS "V?p:a:d:s:S:h:Dm:N:"
GListPtr ping_list = NULL;
IPC_Channel *attrd = NULL;
GMainLoop* mainloop = NULL;
GHashTable *ping_nodes = NULL;
const char *pingd_attr = "pingd";
gboolean do_filter = FALSE;
gboolean need_shutdown = FALSE;
gboolean stand_alone = FALSE;
const char *attr_set = NULL;
const char *attr_section = NULL;
const char *attr_dampen = NULL;
int attr_multiplier = 1;
int pings_per_host = 5;
int ping_timeout = 5;
int re_ping_interval = 10;
void pingd_nstatus_callback(
const char *node, const char *status, void *private_data);
void pingd_lstatus_callback(
const char *node, const char *link, const char *status,
void *private_data);
void send_update(int active);
int ident; /* our pid */
typedef struct ping_node_s {
int fd; /* ping socket */
int iseq; /* sequence number */
gboolean type;
union {
struct sockaddr raw;
struct sockaddr_in v4; /* ipv4 ping addr */
struct sockaddr_in6 v6; /* ipv6 ping addr */
} addr;
char dest[256];
char *host;
} ping_node;
/*
* in_cksum --
* Checksum routine for Internet Protocol family headers (C Version)
* This function taken from Mike Muuss' ping program.
*/
static int
in_cksum (u_short *addr, size_t len)
{
size_t nleft = len;
u_short * w = addr;
int sum = 0;
u_short answer = 0;
/*
* The IP checksum algorithm is simple: using a 32 bit accumulator (sum)
* add sequential 16 bit words to it, and at the end, folding back all
* the carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* Mop up an odd byte, if necessary */
if (nleft == 1) {
sum += *(u_char*)w;
}
/* Add back carry bits from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return answer;
}
static ping_node *ping_new(const char *host)
{
ping_node *node;
crm_malloc0(node, sizeof(ping_node));
if(strstr(host, ":")) {
node->type = AF_INET6;
} else {
node->type = AF_INET;
}
node->host = crm_strdup(host);
return node;
}
static gboolean ping_open(ping_node *node)
{
int ret_ga;
char *hostname;
struct addrinfo *res;
struct addrinfo hints;
/* getaddrinfo */
bzero(&hints, sizeof(struct addrinfo));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = node->type;
hints.ai_socktype = SOCK_RAW;
if(node->type == AF_INET6) {
hints.ai_protocol = IPPROTO_ICMPV6;
} else {
hints.ai_protocol = IPPROTO_ICMP;
}
ret_ga = getaddrinfo(node->host, NULL, &hints, &res);
if (ret_ga) {
crm_err("getaddrinfo: %s", gai_strerror(ret_ga));
return -1;
}
if (res->ai_canonname)
hostname = res->ai_canonname;
else
hostname = node->host;
crm_debug("Got address %s for %s", hostname, node->host);
if (!res->ai_addr) {
fprintf(stderr, "getaddrinfo failed");
exit(1);
}
memcpy(&(node->addr.raw), res->ai_addr, res->ai_addrlen);
node->fd = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol);
/* node->fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); */
if(node->fd < 0) {
cl_perror("Can't open socket to %s", hostname);
return FALSE;
}
if(node->type == AF_INET6) {
int sockopt;
inet_ntop(node->type, &node->addr.v6.sin6_addr, node->dest, sizeof(node->dest));
/* set recv buf for broadcast pings */
sockopt = 48 * 1024;
setsockopt(node->fd, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt, sizeof(sockopt));
} else {
inet_ntop(node->type, &node->addr.v4.sin_addr, node->dest, sizeof(node->dest));
}
if(ping_timeout > 0) {
struct timeval timeout_opt;
timeout_opt.tv_sec = ping_timeout;
timeout_opt.tv_usec = 0;
setsockopt(node->fd, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout_opt, sizeof(timeout_opt));
}
crm_debug("Opened connection to %s", node->dest);
return TRUE;
}
static gboolean ping_close(ping_node *node)
{
int tmp_fd = node->fd;
node->fd = -1;
if (tmp_fd >= 0) {
if(close(tmp_fd) < 0) {
cl_perror("Could not close ping socket");
} else {
tmp_fd = -1;
crm_debug("Closed connection to %s", node->dest);
}
}
return (tmp_fd == -1);
}
#define MAXPACKETLEN 131072
#define ICMP6ECHOLEN 8 /* icmp echo header len excluding time */
#define ICMP6ECHOTMLEN 20
#define DEFDATALEN ICMP6ECHOTMLEN
#define EXTRA 256 /* for AH and various other headers. weird. */
#define IP6LEN 40
static gboolean
dump_v6_echo(ping_node *node, u_char *buf, int bytes, struct msghdr *hdr)
{
int fromlen;
char dest[1024];
struct icmp6_hdr *icp;
struct sockaddr *from;
if (!hdr || !hdr->msg_name || hdr->msg_namelen != sizeof(struct sockaddr_in6)
|| ((struct sockaddr *)hdr->msg_name)->sa_family != AF_INET6) {
crm_warn("Invalid echo peer");
return FALSE;
}
fromlen = hdr->msg_namelen;
from = (struct sockaddr *)hdr->msg_name;
getnameinfo(from, fromlen, dest, sizeof(dest), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
if (bytes < (int)sizeof(struct icmp6_hdr)) {
crm_warn("Invalid echo packet (too short: %d bytes) from %s", bytes, dest);
return FALSE;
}
icp = (struct icmp6_hdr *)buf;
if (icp->icmp6_type == ICMP6_ECHO_REPLY && ntohs(icp->icmp6_id) == ident) {
u_int16_t seq = ntohs(icp->icmp6_seq);
crm_debug("%d bytes from %s, icmp_seq=%u: %s",
bytes, dest, seq, (char*)(buf + ICMP6ECHOLEN));
return TRUE;
}
crm_warn("Bad echo (%d): %d, code=%d, seq=%d, id=%d, check=%d",
ICMP6_ECHO_REPLY, icp->icmp6_type,
icp->icmp6_code, ntohs(icp->icmp6_seq), icp->icmp6_id, icp->icmp6_cksum);
return FALSE;
}
static gboolean
dump_v4_echo(ping_node *node, u_char *buf, int bytes, struct msghdr *hdr)
{
int iplen, fromlen;
char dest[1024];
struct ip *ip;
struct icmp *icp;
struct sockaddr *from;
if (hdr == NULL || !hdr->msg_name || hdr->msg_namelen != sizeof(struct sockaddr_in)
|| ((struct sockaddr *)hdr->msg_name)->sa_family != AF_INET) {
crm_warn("Invalid echo peer");
return FALSE;
}
fromlen = hdr->msg_namelen;
from = (struct sockaddr *)hdr->msg_name;
getnameinfo(from, fromlen, dest, sizeof(dest), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
ip = (struct ip*)buf;
iplen = ip->ip_hl * 4;
if (bytes < (iplen + sizeof(struct icmp))) {
crm_warn("Invalid echo packet (too short: %d bytes) from %s", bytes, dest);
return FALSE;
}
/* Check the IP header */
icp = (struct icmp*)(buf + iplen);
if (icp->icmp_type == ICMP_ECHOREPLY && ntohs(icp->icmp_id) == ident) {
crm_debug("%d bytes from %s, icmp_seq=%u: %s",
bytes, dest, ntohs(icp->icmp_seq), icp->icmp_data);
return TRUE;
}
crm_warn("Bad echo (%d): %d, code=%d, seq=%d, id=%d, check=%d",
ICMP_ECHOREPLY, icp->icmp_type,
icp->icmp_code, ntohs(icp->icmp_seq), icp->icmp_id, icp->icmp_cksum);
return FALSE;
}
static int
ping_read(ping_node *node, int *lenp)
{
int bytes;
int fromlen;
struct msghdr m;
struct cmsghdr *cm;
u_char buf[1024];
struct iovec iov[2];
int packlen;
u_char *packet;
packlen = DEFDATALEN + IP6LEN + ICMP6ECHOLEN + EXTRA;
crm_malloc0(packet, packlen);
if(node->type == AF_INET6) {
fromlen = sizeof(struct sockaddr_in6);
} else {
fromlen = sizeof(struct sockaddr_in);
}
m.msg_name = (caddr_t)&node->addr;
m.msg_namelen = fromlen;
memset(&iov, 0, sizeof(iov));
iov[0].iov_base = (caddr_t)packet;
iov[0].iov_len = packlen;
m.msg_iov = iov;
m.msg_iovlen = 1;
cm = (struct cmsghdr *)buf;
m.msg_control = (caddr_t)buf;
m.msg_controllen = sizeof(buf);
crm_debug_2("reading...");
bytes = recvmsg(node->fd, &m, 0);
crm_debug_2("Got %d bytes", bytes);
if (bytes > 0) {
if(node->type == AF_INET6) {
return dump_v6_echo(node, packet, bytes, &m);
} else {
return dump_v4_echo(node, packet, bytes, &m);
}
} else if(bytes < 0) {
cl_perror("recvmsg failed");
} else {
crm_err("Unexpected reply");
}
return FALSE;
}
static int
ping_write(ping_node *node, const char *data, size_t size)
{
struct iovec iov[2];
int rc, bytes, namelen;
static int ntransmitted = 5;
struct msghdr smsghdr;
u_char outpack[MAXPACKETLEN];
node->iseq = ntransmitted++;
if(node->type == AF_INET6) {
struct icmp6_hdr *icp;
namelen = sizeof(struct sockaddr_in6);
bytes = ICMP6ECHOLEN + DEFDATALEN;
icp = (struct icmp6_hdr *)outpack;
memset(icp, 0, sizeof(*icp));
icp->icmp6_code = 0;
icp->icmp6_cksum = 0;
icp->icmp6_type = ICMP6_ECHO_REQUEST;
icp->icmp6_id = htons(ident);
icp->icmp6_seq = ntohs(node->iseq);
memcpy(&outpack[ICMP6ECHOLEN], "beekhof-v6", 10);
} else {
struct icmp *icp;
namelen = sizeof(struct sockaddr_in);
bytes = sizeof(struct icmp) + 11;
icp = (struct icmp *)outpack;
memset(icp, 0, sizeof(*icp));
icp->icmp_code = 0;
icp->icmp_cksum = 0;
icp->icmp_type = ICMP_ECHO;
icp->icmp_id = htons(ident);
icp->icmp_seq = ntohs(node->iseq);
memcpy(icp->icmp_data, "beekhof-v4", 10);
icp->icmp_cksum = in_cksum((u_short *)icp, bytes);
}
memset(&smsghdr, 0, sizeof(smsghdr));
smsghdr.msg_name = (caddr_t)&(node->addr);
smsghdr.msg_namelen = namelen;
memset(&iov, 0, sizeof(iov));
iov[0].iov_base = (caddr_t)outpack;
iov[0].iov_len = bytes;
smsghdr.msg_iov = iov;
smsghdr.msg_iovlen = 1;
rc = sendmsg(node->fd, &smsghdr, 0);
if (rc < 0 || rc != bytes) {
cl_perror("Wrote %d of %d chars", rc, bytes);
} else {
crm_debug("Sent %d bytes to %s", rc, node->dest);
}
return(0);
}
static gboolean
pingd_shutdown(int nsig, gpointer unused)
{
need_shutdown = TRUE;
send_update(-1);
crm_info("Exiting");
if (mainloop != NULL && g_main_is_running(mainloop)) {
g_main_quit(mainloop);
} else {
exit(0);
}
return FALSE;
}
static void
usage(const char *cmd, int exit_status)
{
FILE *stream;
stream = exit_status ? stderr : stdout;
fprintf(stream, "usage: %s [-%s]\n", cmd, OPTARGS);
fprintf(stream, "\t--%s (-%c) \t\t\tThis text\n", "help", '?');
fprintf(stream, "\t--%s (-%c) \t\tRun in daemon mode\n", "daemonize", 'D');
fprintf(stream, "\t--%s (-%c) <filename>\tFile in which to store the process' PID\n"
"\t\t\t\t\t* Default=/tmp/pingd.pid\n", "pid-file", 'p');
fprintf(stream, "\t--%s (-%c) <string>\tName of the node attribute to set\n"
"\t\t\t\t\t* Default=pingd\n", "attr-name", 'a');
fprintf(stream, "\t--%s (-%c) <string>\tName of the set in which to set the attribute\n"
"\t\t\t\t\t* Default=cib-bootstrap-options\n", "attr-set", 's');
fprintf(stream, "\t--%s (-%c) <string>\tWhich part of the CIB to put the attribute in\n"
"\t\t\t\t\t* Default=status\n", "attr-section", 'S');
- fprintf(stream, "\t--%s (-%c) <single_host_name>\tMonitor a subset of the ping nodes listed in ha.cf (can be specified multiple times)\n", "ping-host", 'h');
+ fprintf(stream, "\t--%s (-%c) <single_host_name>\tMonitor a subset of the ping nodes listed in ha.cf (can be specified multiple times)\n", "node", 'N');
fprintf(stream, "\t--%s (-%c) <integer>\t\tHow long to wait for no further changes to occur before updating the CIB with a changed attribute\n", "attr-dampen", 'd');
fprintf(stream, "\t--%s (-%c) <integer>\tFor every connected node, add <integer> to the value set in the CIB\n"
"\t\t\t\t\t\t* Default=1\n", "value-multiplier", 'm');
fflush(stream);
exit(exit_status);
}
#if SUPPORT_HEARTBEAT
static gboolean
pingd_ha_dispatch(IPC_Channel *channel, gpointer user_data)
{
gboolean stay_connected = TRUE;
crm_debug_2("Invoked");
while(pingd_cluster != NULL && IPC_ISRCONN(channel)) {
if(pingd_cluster->llc_ops->msgready(pingd_cluster) == 0) {
crm_debug_2("no message ready yet");
break;
}
/* invoke the callbacks but dont block */
pingd_cluster->llc_ops->rcvmsg(pingd_cluster, 0);
}
if (pingd_cluster == NULL || channel->ch_status != IPC_CONNECT) {
if(need_shutdown == FALSE) {
crm_crit("Lost connection to heartbeat service.");
} else {
crm_info("Lost connection to heartbeat service.");
}
stay_connected = FALSE;
}
return stay_connected;
}
static void
pingd_ha_connection_destroy(gpointer user_data)
{
crm_debug_3("Invoked");
if(need_shutdown) {
/* we signed out, so this is expected */
crm_info("Heartbeat disconnection complete");
return;
}
crm_crit("Lost connection to heartbeat service!");
}
static gboolean
register_with_ha(void)
{
if(pingd_cluster == NULL) {
pingd_cluster = ll_cluster_new("heartbeat");
}
if(pingd_cluster == NULL) {
crm_err("Cannot create heartbeat object");
return FALSE;
}
crm_debug("Signing in with Heartbeat");
if (pingd_cluster->llc_ops->signon(
pingd_cluster, crm_system_name) != HA_OK) {
crm_err("Cannot sign on with heartbeat: %s",
pingd_cluster->llc_ops->errmsg(pingd_cluster));
crm_err("REASON: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster));
return FALSE;
}
do_node_walk(pingd_cluster);
crm_debug_3("Be informed of Node Status changes");
if (HA_OK != pingd_cluster->llc_ops->set_nstatus_callback(
pingd_cluster, pingd_nstatus_callback, NULL)) {
crm_err("Cannot set nstatus callback: %s",
pingd_cluster->llc_ops->errmsg(pingd_cluster));
crm_err("REASON: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster));
return FALSE;
}
if (pingd_cluster->llc_ops->set_ifstatus_callback(
pingd_cluster, pingd_lstatus_callback, NULL) != HA_OK) {
cl_log(LOG_ERR, "Cannot set if status callback");
crm_err("REASON: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster));
return FALSE;
}
crm_debug_3("Adding channel to mainloop");
G_main_add_IPC_Channel(
G_PRIORITY_HIGH, pingd_cluster->llc_ops->ipcchan(
pingd_cluster),
FALSE, pingd_ha_dispatch, pingd_cluster,
pingd_ha_connection_destroy);
return TRUE;
}
void
do_node_walk(ll_cluster_t *hb_cluster)
{
const char *ha_node = NULL;
/* Async get client status information in the cluster */
crm_debug_2("Invoked");
crm_debug_3("Requesting an initial dump of CRMD client_status");
hb_cluster->llc_ops->client_status(
hb_cluster, NULL, CRM_SYSTEM_CRMD, -1);
crm_info("Requesting the list of configured nodes");
hb_cluster->llc_ops->init_nodewalk(hb_cluster);
do {
const char *ha_node_type = NULL;
const char *ha_node_status = NULL;
ha_node = hb_cluster->llc_ops->nextnode(hb_cluster);
if(ha_node == NULL) {
continue;
}
ha_node_type = hb_cluster->llc_ops->node_type(
hb_cluster, ha_node);
if(safe_str_neq("ping", ha_node_type)) {
crm_debug("Node %s: skipping '%s'",
ha_node, ha_node_type);
continue;
}
if(do_filter
&& g_hash_table_lookup(ping_nodes, ha_node) == NULL) {
crm_debug("Filtering: %s", ha_node);
continue;
}
ha_node_status = hb_cluster->llc_ops->node_status(
hb_cluster, ha_node);
crm_debug("Adding: %s=%s", ha_node, ha_node_status);
g_hash_table_replace(ping_nodes, crm_strdup(ha_node),
crm_strdup(ha_node_status));
} while(ha_node != NULL);
hb_cluster->llc_ops->end_nodewalk(hb_cluster);
crm_debug_2("Complete");
send_update(-1);
}
#endif
static gboolean stand_alone_ping(gpointer data)
{
int len = 0;
int num_active = 0;
crm_debug("Checking connectivity");
slist_iter(
ping, ping_node, ping_list, num,
int lpc = 0;
int alive = 0;
ping_open(ping);
for(;lpc < pings_per_host; lpc++) {
ping_write(ping, "test", 4);
if(ping_read(ping, &len)) {
alive++;
}
sleep(1);
}
if(alive) {
crm_info("Node %s is alive (%d)", ping->host, alive);
num_active++;
}
ping_close(ping);
);
send_update(num_active);
CRM_ASSERT(Gmain_timeout_add(re_ping_interval*1000, stand_alone_ping, NULL) > 0);
return FALSE;
}
int
main(int argc, char **argv)
{
int lpc;
int argerr = 0;
int flag;
char *pid_file = NULL;
gboolean daemonize = FALSE;
ping_node *p = NULL;
#ifdef HAVE_GETOPT_H
int option_index = 0;
static struct option long_options[] = {
/* Top-level Options */
- {"verbose", 0, 0, 'V'},
- {"help", 0, 0, '?'},
+ {"verbose", 0, 0, 'V'},
+ {"help", 0, 0, '?'},
{"pid-file", 1, 0, 'p'},
- {"ping-host", 1, 0, 'h'},
+ {"node", 1, 0, 'N'},
+ {"ping-host", 1, 0, 'h'}, /* legacy */
{"attr-name", 1, 0, 'a'},
{"attr-set", 1, 0, 's'},
{"daemonize", 0, 0, 'D'},
{"attr-section", 1, 0, 'S'},
{"attr-dampen", 1, 0, 'd'},
{"value-multiplier", 1, 0, 'm'},
{0, 0, 0, 0}
};
#endif
pid_file = crm_strdup("/tmp/pingd.pid");
G_main_add_SignalHandler(
G_PRIORITY_HIGH, SIGTERM, pingd_shutdown, NULL, NULL);
ping_nodes = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
crm_log_init(basename(argv[0]), LOG_INFO, TRUE, FALSE, argc, argv);
while (1) {
#ifdef HAVE_GETOPT_H
flag = getopt_long(argc, argv, OPTARGS,
long_options, &option_index);
#else
flag = getopt(argc, argv, OPTARGS);
#endif
if (flag == -1)
break;
switch(flag) {
case 'V':
cl_log_enable_stderr(TRUE);
alter_debug(DEBUG_INC);
break;
case 'p':
pid_file = crm_strdup(optarg);
break;
case 'a':
pingd_attr = crm_strdup(optarg);
break;
+ case 'N':
case 'h':
stand_alone = TRUE;
crm_debug("Adding ping host %s", optarg);
p = ping_new(crm_strdup(optarg));
ping_list = g_list_append(ping_list, p);
break;
case 's':
attr_set = crm_strdup(optarg);
break;
case 'm':
attr_multiplier = crm_parse_int(optarg, "1");
break;
case 'S':
attr_section = crm_strdup(optarg);
break;
case 'd':
attr_dampen = crm_strdup(optarg);
break;
case 'n':
pings_per_host = crm_atoi(optarg, NULL);
break;
case 't':
ping_timeout = crm_atoi(optarg, NULL);
break;
case 'i':
re_ping_interval = crm_atoi(optarg, NULL);
break;
case 'D':
daemonize = TRUE;
break;
case '?':
usage(crm_system_name, LSB_EXIT_GENERIC);
break;
default:
printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag);
crm_err("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag);
++argerr;
break;
}
}
if (optind < argc) {
crm_err("non-option ARGV-elements: ");
printf("non-option ARGV-elements: ");
while (optind < argc) {
crm_err("%s ", argv[optind++]);
printf("%s ", argv[optind++]);
}
printf("\n");
}
if (argerr) {
usage(crm_system_name, LSB_EXIT_GENERIC);
}
crm_make_daemon(crm_system_name, daemonize, pid_file);
for(lpc = 0; attrd == NULL && lpc < 30; lpc++) {
crm_debug("attrd registration attempt: %d", lpc);
sleep(5);
attrd = init_client_ipc_comms_nodispatch(T_ATTRD);
}
if(attrd == NULL) {
crm_err("attrd registration failed");
cl_flush_logs();
exit(LSB_EXIT_GENERIC);
}
#if SUPPORT_AIS
if(is_openais_cluster()) {
stand_alone = TRUE;
}
#endif
#if SUPPORT_HEARTBEAT
if(stand_alone == FALSE && register_with_ha() == FALSE) {
crm_err("HA registration failed");
cl_flush_logs();
exit(LSB_EXIT_GENERIC);
}
#endif
if(stand_alone && ping_list == NULL) {
crm_err("You must specify a list of hosts to monitor");
exit(LSB_EXIT_GENERIC);
} else if(stand_alone) {
CRM_ASSERT(Gmain_timeout_add(re_ping_interval*1000, stand_alone_ping, NULL) > 0);
}
crm_info("Starting %s", crm_system_name);
mainloop = g_main_new(FALSE);
g_main_run(mainloop);
crm_info("Exiting %s", crm_system_name);
return 0;
}
static void count_ping_nodes(gpointer key, gpointer value, gpointer user_data)
{
int *num_active = user_data;
CRM_CHECK(num_active != NULL, return);
if(need_shutdown) {
return;
}
if(safe_str_eq(value, "ping")) {
(*num_active)++;
} else if(safe_str_eq(value, "up")) {
(*num_active)++;
}
}
void
send_update(int num_active)
{
xmlNode *update = create_xml_node(NULL, __FUNCTION__);
crm_xml_add(update, F_TYPE, T_ATTRD);
crm_xml_add(update, F_ORIG, crm_system_name);
crm_xml_add(update, F_ATTRD_TASK, "update");
crm_xml_add(update, F_ATTRD_ATTRIBUTE, pingd_attr);
if(num_active < 0) {
g_hash_table_foreach(ping_nodes, count_ping_nodes, &num_active);
}
crm_info("%d active ping nodes", num_active);
crm_xml_add_int(update, F_ATTRD_VALUE, attr_multiplier*num_active);
if(attr_set != NULL) {
crm_xml_add(update, F_ATTRD_SET, attr_set);
}
if(attr_section != NULL) {
crm_xml_add(update, F_ATTRD_SECTION, attr_section);
}
if(attr_dampen != NULL) {
crm_xml_add(update, F_ATTRD_DAMPEN, attr_dampen);
}
if(send_ipc_message(attrd, update) == FALSE) {
crm_err("Could not send update");
exit(1);
}
free_xml(update);
}
void
pingd_nstatus_callback(
const char *node, const char * status, void* private_data)
{
crm_notice("Status update: Ping node %s now has status [%s]",
node, status);
if(g_hash_table_lookup(ping_nodes, node) != NULL) {
g_hash_table_replace(
ping_nodes, crm_strdup(node), crm_strdup(status));
send_update(-1);
}
}
void
pingd_lstatus_callback(const char *node, const char *lnk, const char *status,
void *private)
{
crm_notice("Status update: Ping node %s now has status [%s]",
node, status);
pingd_nstatus_callback(node, status, private);
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Jun 25, 7:03 AM (11 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1952492
Default Alt Text
(94 KB)

Event Timeline