Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/crm/admin/crm_resource.c b/crm/admin/crm_resource.c
index f53ed786e2..0310ba61cb 100644
--- a/crm/admin/crm_resource.c
+++ b/crm/admin/crm_resource.c
@@ -1,1240 +1,1241 @@
/* $Id: crm_resource.c,v 1.46 2006/08/17 07:17:15 andrew Exp $ */
/*
* 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 <portability.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 <heartbeat.h>
#include <hb_api.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 *crm_system_name = NULL;
const char *prop_name = NULL;
const char *prop_value = NULL;
const char *rsc_type = NULL;
const char *prop_id = NULL;
const char *prop_set = NULL;
char *migrate_lifetime = NULL;
char rsc_cmd = 'L';
char *our_pid = NULL;
IPC_Channel *crmd_channel = NULL;
char *xml_file = NULL;
#define OPTARGS "V?LRQxDCPp:WMUr:H:v:t:p:g:d:i:s:G:S:fX:lmu:"
static int
do_find_resource(const char *rsc, pe_working_set_t *data_set)
{
int found = 0;
resource_t *the_rsc = pe_find_resource(data_set->resources, rsc);
if(the_rsc == NULL) {
return cib_NOTEXISTS;
}
slist_iter(node, node_t, the_rsc->running_on, lpc,
crm_debug_3("resource %s is running on: %s",
rsc, node->details->uname);
if(BE_QUIET) {
fprintf(stdout, "%s\n", node->details->uname);
} else {
fprintf(stdout, "resource %s is running on: %s\n",
rsc, node->details->uname);
}
found++;
);
if(BE_QUIET == FALSE && found == 0) {
fprintf(stderr, "resource %s is NOT running\n", rsc);
}
return 0;
}
static void
print_raw_rsc(resource_t *rsc, int level)
{
int lpc = 0;
GListPtr children = NULL;
for(; lpc < level; lpc++) {
printf(" ");
}
printf(" * %s\n", rsc->id);
children = rsc->fns->children(rsc);
slist_iter(child, resource_t, children, lpc,
print_raw_rsc(child, level+1);
);
}
static int
do_find_resource_list(pe_working_set_t *data_set, gboolean raw)
{
int found = 0;
slist_iter(
rsc, resource_t, data_set->resources, lpc,
if(raw) {
found++;
print_raw_rsc(rsc, 0);
continue;
} else if(rsc->orphan && rsc->fns->active(rsc, TRUE) == FALSE) {
continue;
}
rsc->fns->print(
rsc, NULL, pe_print_printf|pe_print_rsconly, stdout);
found++;
);
if(found == 0) {
printf("NO resources configured\n");
return cib_NOTEXISTS;
}
return 0;
}
static int
dump_resource(const char *rsc, pe_working_set_t *data_set)
{
char *rsc_xml = NULL;
resource_t *the_rsc = pe_find_resource(data_set->resources, rsc);
if(the_rsc == NULL) {
return cib_NOTEXISTS;
}
the_rsc->fns->print(the_rsc, NULL, pe_print_printf, stdout);
rsc_xml = dump_xml_formatted(the_rsc->xml);
fprintf(stdout, "raw xml:\n%s", rsc_xml);
crm_free(rsc_xml);
return 0;
}
static int
dump_resource_attr(
const char *rsc, const char *attr, pe_working_set_t *data_set)
{
node_t *current = NULL;
resource_t *the_rsc = pe_find_resource(data_set->resources, rsc);
const char *value = NULL;
if(the_rsc == NULL) {
return cib_NOTEXISTS;
}
if(g_list_length(the_rsc->running_on) == 1) {
current = the_rsc->running_on->data;
} else if(g_list_length(the_rsc->running_on) > 1) {
fprintf(stderr, "%s is active on more than one node,"
" returning the default value for %s\n",
the_rsc->id, crm_str(value));
}
unpack_instance_attributes(
the_rsc->xml, attr_set_type, current?current->details->attrs:NULL,
the_rsc->parameters, NULL, data_set->now);
if(the_rsc->parameters != NULL) {
crm_debug("Looking up %s in %s", attr, the_rsc->id);
value = g_hash_table_lookup(the_rsc->parameters, attr);
}
if(value != NULL) {
fprintf(stdout, "%s\n", value);
return 0;
}
return cib_NOTEXISTS;
}
static int
set_resource_attr(const char *rsc_id, const char *attr_set, const char *attr_id,
const char *attr_name, const char *attr_value,
cib_t *cib, pe_working_set_t *data_set)
{
int rc = cib_ok;
int matches = 0;
int cib_options = cib_sync_call;
char *local_attr_id = NULL;
char *local_attr_set = NULL;
crm_data_t *xml_top = NULL;
crm_data_t *xml_obj = NULL;
crm_data_t *nv_children = NULL;
crm_data_t *set_children = NULL;
resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
if(do_force) {
crm_debug("Forcing...");
cib_options |= cib_scope_local|cib_quorum_override;
}
if(rsc == NULL) {
return cib_NOTEXISTS;
}
/* filter by set name */
if(attr_set != NULL) {
matches = find_xml_children(
&set_children, rsc->xml,
attr_set_type, XML_ATTR_ID, attr_set, TRUE);
crm_log_xml_debug(set_children, "search by set:");
}
matches = 0;
if(attr_id == NULL) {
matches = find_xml_children(
&nv_children, set_children?set_children:rsc->xml,
XML_CIB_TAG_NVPAIR, XML_NVPAIR_ATTR_NAME, attr_name, FALSE);
crm_log_xml_debug(nv_children, "search by name:");
} else if(attr_id != NULL) {
matches = find_xml_children(
&nv_children, set_children?set_children:rsc->xml,
XML_CIB_TAG_NVPAIR, XML_ATTR_ID, attr_id, FALSE);
crm_log_xml_debug(nv_children, "search by id:");
}
if(matches > 1) {
fprintf(stderr, "Multiple attributes match name=%s for the resource %s:\n",
attr_name, rsc->id);
if(set_children == NULL) {
free_xml(set_children);
set_children = NULL;
find_xml_children(
&set_children, rsc->xml,
attr_set_type, NULL, NULL, FALSE);
xml_child_iter(
set_children, set,
free_xml(nv_children);
nv_children = NULL;
find_xml_children(
&nv_children, set,
XML_CIB_TAG_NVPAIR, XML_NVPAIR_ATTR_NAME, attr_name, FALSE);
xml_child_iter(
nv_children, child,
fprintf(stderr," Set: %s,\tValue: %s,\tID: %s\n",
ID(set),
crm_element_value(child, XML_NVPAIR_ATTR_VALUE),
ID(child));
);
);
} else {
xml_child_iter(
nv_children, child,
fprintf(stderr," ID: %s, Value: %s\n", ID(child),
crm_element_value(child, XML_NVPAIR_ATTR_VALUE));
);
}
if(BE_QUIET == FALSE) {
fprintf(stderr, "\nThe following text can be suppressed with the -Q option:\n");
if(attr_set == NULL) {
fprintf(stderr, " * To choose an existing entry to change, please supply one of the set names above using the -s option.\n");
} else {
fprintf(stderr, " * To choose an existing entry to change, please supply one of the IDs above using the -i option.\n");
}
fprintf(stderr, " * To create a new value with a default ID, please supply a different set name using the -s option.\n");
fprintf(stderr, "You can also use --query-xml to display the complete resource definition.\n");
}
return cib_unknown;
} else if(matches == 0) {
if(attr_set == NULL) {
local_attr_set = crm_strdup(rsc->id);
attr_set = local_attr_set;
}
if(attr_id == NULL) {
local_attr_id = crm_concat(attr_set, attr_name, '-');
attr_id = local_attr_id;
}
xml_top = create_xml_node(NULL, crm_element_name(rsc->xml));
crm_xml_add(xml_top, XML_ATTR_ID, rsc->id);
xml_obj = create_xml_node(xml_top, attr_set_type);
crm_xml_add(xml_obj, XML_ATTR_ID, attr_set);
xml_obj = create_xml_node(xml_obj, XML_TAG_ATTRS);
xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR);
} else {
if(attr_id == NULL) {
/* extract it */
xml_child_iter(nv_children, child, attr_id = ID(child));
}
xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR);
xml_top = xml_obj;
}
crm_xml_add(xml_obj, XML_ATTR_ID, attr_id);
crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name);
crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value);
crm_log_xml_debug(xml_top, "Update");
rc = cib->cmds->modify(cib, XML_CIB_TAG_RESOURCES, xml_top, NULL,
cib_options);
free_xml(xml_top);
crm_free(local_attr_id);
crm_free(local_attr_set);
return rc;
}
static int
delete_resource_attr(
const char *rsc_id, const char *attr_set, const char *attr_id,
const char *attr_name, cib_t *cib, pe_working_set_t *data_set)
{
crm_data_t *xml_obj = NULL;
crm_data_t *xml_match = NULL;
int rc = cib_ok;
char *local_attr_id = NULL;
int cib_options = cib_sync_call;
resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
if(do_force) {
crm_debug("Forcing...");
cib_options |= cib_scope_local|cib_quorum_override;
}
if(rsc == NULL) {
return cib_NOTEXISTS;
}
xml_match = find_attr_details(
rsc->xml, NULL, attr_set, attr_id, attr_name);
if(xml_match == NULL) {
return cib_missing_data;
}
if(attr_id == NULL) {
local_attr_id = crm_element_value_copy(xml_match, XML_ATTR_ID);
attr_id = local_attr_id;
}
xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR);
crm_xml_add(xml_obj, XML_ATTR_ID, attr_id);
crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name);
crm_log_xml_debug(xml_obj, "Delete");
rc = cib->cmds->delete(cib, XML_CIB_TAG_RESOURCES, xml_obj, NULL,
cib_options);
free_xml(xml_obj);
free_xml(xml_match);
crm_free(local_attr_id);
return rc;
}
static int
dump_resource_prop(
const char *rsc, const char *attr, pe_working_set_t *data_set)
{
const char *value = NULL;
resource_t *the_rsc = pe_find_resource(data_set->resources, rsc);
if(the_rsc == NULL) {
return cib_NOTEXISTS;
}
value = crm_element_value(the_rsc->xml, attr);
if(value != NULL) {
fprintf(stdout, "%s\n", value);
return 0;
}
return cib_NOTEXISTS;
}
static void
resource_ipc_connection_destroy(gpointer user_data)
{
crm_info("Connection to CRMd was terminated");
exit(1);
}
static gboolean
crmd_msg_callback(IPC_Channel * server, void *private_data)
{
int lpc = 0;
IPC_Message *msg = NULL;
ha_msg_input_t *new_input = NULL;
gboolean hack_return_good = TRUE;
while (server->ch_status != IPC_DISCONNECT
&& server->ops->is_message_pending(server) == TRUE) {
if(new_input != NULL) {
delete_ha_msg_input(new_input);
new_input = NULL;
}
if (server->ops->recv(server, &msg) != IPC_OK) {
perror("Receive failure:");
return !hack_return_good;
}
if (msg == NULL) {
crm_debug_4("No message this time");
continue;
}
lpc++;
new_input = new_ipc_msg_input(msg);
crm_log_message(LOG_MSG, new_input->msg);
msg->msg_done(msg);
if (validate_crm_message(
new_input->msg, crm_system_name, our_pid,
XML_ATTR_RESPONSE) == FALSE) {
crm_info("Message was not a CRM response. Discarding.");
}
- delete_ha_msg_input(new_input);
+ delete_ha_msg_input(new_input);
+ new_input = NULL;
}
if (server->ch_status == IPC_DISCONNECT) {
crm_debug_2("admin_msg_callback: received HUP");
return !hack_return_good;
}
return hack_return_good;
}
static int
delete_lrm_rsc(
IPC_Channel *crmd_channel, const char *host_uname,
const char *rsc_id, const char *rsc_long_id)
{
int rc = cib_send_failed;
HA_Message *cmd = NULL;
crm_data_t *msg_data = NULL;
crm_data_t *rsc = NULL;
HA_Message *params = NULL;
char *key = crm_concat(crm_system_name, our_pid, '-');
CRM_DEV_ASSERT(rsc_id != NULL);
msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key);
rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE);
crm_xml_add(rsc, XML_ATTR_ID, rsc_id);
crm_xml_add(rsc, XML_ATTR_ID_LONG, rsc_long_id);
params = create_xml_node(msg_data, XML_TAG_ATTRS);
crm_xml_add(params, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
cmd = create_request(CRM_OP_LRM_DELETE, msg_data, host_uname,
CRM_SYSTEM_CRMD, crm_system_name, our_pid);
free_xml(msg_data);
crm_free(key);
if(send_ipc_message(crmd_channel, cmd)) {
rc = 0;
}
crm_msg_del(cmd);
return rc;
}
static int
refresh_lrm(IPC_Channel *crmd_channel, const char *host_uname)
{
HA_Message *cmd = NULL;
int rc = cib_send_failed;
cmd = create_request(CRM_OP_LRM_REFRESH, NULL, host_uname,
CRM_SYSTEM_CRMD, crm_system_name, our_pid);
if(send_ipc_message(crmd_channel, cmd)) {
rc = 0;
}
crm_msg_del(cmd);
return rc;
}
static int
migrate_resource(
const char *rsc_id,
const char *existing_node, const char *preferred_node,
cib_t * cib_conn)
{
char *later_s = NULL;
enum cib_errors rc = cib_ok;
char *id = NULL;
crm_data_t *cib = NULL;
crm_data_t *rule = NULL;
crm_data_t *expr = NULL;
crm_data_t *constraints = NULL;
crm_data_t *fragment = NULL;
crm_data_t *lifetime = NULL;
crm_data_t *can_run = NULL;
crm_data_t *dont_run = NULL;
fragment = create_cib_fragment(NULL, NULL);
cib = fragment;
CRM_DEV_ASSERT(safe_str_eq(crm_element_name(cib), XML_TAG_CIB));
constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib);
id = crm_concat("cli-prefer", rsc_id, '-');
can_run = create_xml_node(NULL, XML_CONS_TAG_RSC_LOCATION);
crm_xml_add(can_run, XML_ATTR_ID, id);
crm_free(id);
id = crm_concat("cli-standby", rsc_id, '-');
dont_run = create_xml_node(NULL, XML_CONS_TAG_RSC_LOCATION);
crm_xml_add(dont_run, XML_ATTR_ID, id);
crm_free(id);
if(migrate_lifetime) {
char *life = crm_strdup(migrate_lifetime);
char *life_mutable = life;
ha_time_t *now = NULL;
ha_time_t *later = NULL;
ha_time_t *duration = parse_time_duration(&life_mutable);
if(duration == NULL) {
fprintf(stderr, "Invalid duration specified: %s\n",
migrate_lifetime);
fprintf(stderr, "Please refer to"
" http://en.wikipedia.org/wiki/ISO_8601#Duration"
" for examples of valid durations\n");
crm_free(life);
return cib_invalid_argument;
}
now = new_ha_date(TRUE);
later = add_time(now, duration);
log_date(LOG_INFO, "now ", now, ha_log_date|ha_log_time);
log_date(LOG_INFO, "later ", later, ha_log_date|ha_log_time);
log_date(LOG_INFO, "duration", duration, ha_log_date|ha_log_time|ha_log_local);
later_s = date_to_string(later, ha_log_date|ha_log_time);
printf("Migration will take effect until: %s\n", later_s);
free_ha_date(duration);
free_ha_date(later);
free_ha_date(now);
crm_free(life);
}
if(existing_node == NULL) {
crm_log_xml_notice(can_run, "Deleting");
rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_CONSTRAINTS,
dont_run, NULL, cib_sync_call);
if(rc == cib_NOTEXISTS) {
rc = cib_ok;
} else if(rc != cib_ok) {
goto bail;
}
} else {
if(BE_QUIET == FALSE) {
fprintf(stderr,
"WARNING: Creating rsc_location constraint '%s'"
" with a score of -INFINITY for resource %s"
" on %s.\n",
ID(dont_run), rsc_id, existing_node);
fprintf(stderr, "\tThis will prevent %s from running"
" on %s until the constraint is removed using"
" the 'crm_resource -U' command or manually"
" with cibadmin\n", rsc_id, existing_node);
fprintf(stderr, "\tThis will be the case even if %s is"
" the last node in the cluster\n", existing_node);
fprintf(stderr, "\tThis messgae can be disabled with -Q\n");
}
crm_xml_add(dont_run, "rsc", rsc_id);
if(later_s) {
lifetime = create_xml_node(dont_run, "lifetime");
rule = create_xml_node(lifetime, XML_TAG_RULE);
id = crm_concat("cli-standby-lifetime", rsc_id, '-');
crm_xml_add(rule, XML_ATTR_ID, id);
crm_free(id);
expr = create_xml_node(rule, "date_expression");
id = crm_concat("cli-standby-lifetime-end",rsc_id,'-');
crm_xml_add(expr, XML_ATTR_ID, id);
crm_free(id);
crm_xml_add(expr, "operation", "lt");
crm_xml_add(expr, "end", later_s);
}
rule = create_xml_node(dont_run, XML_TAG_RULE);
expr = create_xml_node(rule, XML_TAG_EXPRESSION);
id = crm_concat("cli-standby-rule", rsc_id, '-');
crm_xml_add(rule, XML_ATTR_ID, id);
crm_free(id);
crm_xml_add(rule, XML_RULE_ATTR_SCORE, MINUS_INFINITY_S);
id = crm_concat("cli-standby-expr", rsc_id, '-');
crm_xml_add(expr, XML_ATTR_ID, id);
crm_free(id);
crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, "#uname");
crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq");
crm_xml_add(expr, XML_EXPR_ATTR_VALUE, existing_node);
crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string");
add_node_copy(constraints, dont_run);
}
if(preferred_node == NULL) {
crm_log_xml_notice(can_run, "Deleting");
rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_CONSTRAINTS,
can_run, NULL, cib_sync_call);
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_sync_call);
}
bail:
free_xml(fragment);
free_xml(dont_run);
free_xml(can_run);
crm_free(later_s);
return rc;
}
int
main(int argc, char **argv)
{
pe_working_set_t data_set;
crm_data_t *cib_xml_copy = NULL;
cib_t * cib_conn = NULL;
enum cib_errors rc = cib_ok;
int argerr = 0;
int flag;
#ifdef HAVE_GETOPT_H
int option_index = 0;
static struct option long_options[] = {
/* Top-level Options */
{"verbose", 0, 0, 'V'},
{"help", 0, 0, '?'},
{"quiet", 0, 0, 'Q'},
{"list", 0, 0, 'L'},
{"list-raw", 0, 0, 'l'},
{"refresh", 0, 0, 'R'},
{"reprobe", 0, 0, 'P'},
{"query-xml", 0, 0, 'x'},
{"delete", 0, 0, 'D'},
{"cleanup", 0, 0, 'C'},
{"locate", 0, 0, 'W'},
{"migrate", 0, 0, 'M'},
{"un-migrate", 0, 0, 'U'},
{"resource", 1, 0, 'r'},
{"host-uname", 1, 0, 'H'},
{"lifetime", 1, 0, 'u'},
{"force", 0, 0, 'f'},
{"meta", 0, 0, 'm'},
{"set-parameter", 1, 0, 'p'},
{"get-parameter", 1, 0, 'g'},
{"delete-parameter",1, 0, 'd'},
{"property-value", 1, 0, 'v'},
{"get-property", 1, 0, 'G'},
{"set-property", 1, 0, 'S'},
{"resource-type", 1, 0, 't'},
{"xml-file", 0, 0, 'X'},
{0, 0, 0, 0}
};
#endif
crm_system_name = basename(argv[0]);
cl_log_set_entity(crm_system_name);
cl_log_set_facility(LOG_USER);
set_crm_log_level(LOG_ERR);
cl_log_enable_stderr(TRUE);
if(argc < 2) {
usage(crm_system_name, LSB_EXIT_EINVAL);
}
while (1) {
#ifdef HAVE_GETOPT_H
flag = getopt_long(argc, argv, OPTARGS,
long_options, &option_index);
#else
flag = getopt(argc, argv, OPTARGS);
#endif
if (flag == -1)
break;
switch(flag) {
case 'V':
cl_log_enable_stderr(TRUE);
alter_debug(DEBUG_INC);
break;
case '?':
usage(crm_system_name, LSB_EXIT_OK);
break;
case 'X':
xml_file = crm_strdup(optarg);
break;
case 'Q':
BE_QUIET = TRUE;
break;
case 'm':
attr_set_type = XML_TAG_META_SETS;
break;
case 'L':
case 'l':
case 'R':
case 'x':
case 'D':
case 'C':
case 'P':
case 'W':
case 'M':
case 'U':
rsc_cmd = flag;
break;
case 'u':
migrate_lifetime = crm_strdup(optarg);
break;
case 'p':
crm_debug_2("Option %c => %s", flag, optarg);
prop_name = optarg;
rsc_cmd = flag;
break;
case 'g':
crm_debug_2("Option %c => %s", flag, optarg);
prop_name = optarg;
rsc_cmd = flag;
break;
case 'd':
crm_debug_2("Option %c => %s", flag, optarg);
prop_name = optarg;
rsc_cmd = flag;
break;
case 'S':
crm_debug_2("Option %c => %s", flag, optarg);
prop_name = optarg;
rsc_cmd = flag;
break;
case 'G':
crm_debug_2("Option %c => %s", flag, optarg);
prop_name = optarg;
rsc_cmd = flag;
break;
case 'f':
do_force = TRUE;
break;
case 'i':
crm_debug_2("Option %c => %s", flag, optarg);
prop_id = optarg;
break;
case 's':
crm_debug_2("Option %c => %s", flag, optarg);
prop_set = optarg;
break;
case 'r':
crm_debug_2("Option %c => %s", flag, optarg);
rsc_id = optarg;
break;
case 'v':
crm_debug_2("Option %c => %s", flag, optarg);
prop_value = optarg;
break;
case 't':
crm_debug_2("Option %c => %s", flag, optarg);
rsc_type = optarg;
break;
case 'H':
crm_debug_2("Option %c => %s", flag, optarg);
host_uname = optarg;
break;
default:
fprintf(stderr, "Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag);
++argerr;
break;
}
}
if (optind < argc) {
fprintf(stderr, "non-option ARGV-elements: ");
while (optind < argc) {
fprintf(stderr, "%s ", argv[optind++]);
}
fprintf(stderr, "\n");
}
if (optind > argc) {
++argerr;
}
if (argerr) {
usage(crm_system_name, LSB_EXIT_GENERIC);
}
crm_malloc0(our_pid, 11);
if(our_pid != NULL) {
snprintf(our_pid, 10, "%d", getpid());
our_pid[10] = '\0';
}
if(rsc_cmd == 'L' || rsc_cmd == 'W' || rsc_cmd == 'D' || rsc_cmd == 'x'
|| rsc_cmd == 'M' || rsc_cmd == 'U' || rsc_cmd == 'C'
|| rsc_cmd == 'p' || rsc_cmd == 'd' || rsc_cmd == 'g'
|| rsc_cmd == 'G' || rsc_cmd == 'S' || rsc_cmd == 'l') {
resource_t *rsc = NULL;
if(xml_file != NULL) {
FILE *xml_strm = fopen(xml_file, "r");
if(strstr(xml_file, ".bz2") != NULL) {
cib_xml_copy = file2xml(xml_strm, TRUE);
} else {
cib_xml_copy = file2xml(xml_strm, FALSE);
}
} else {
cib_conn = cib_new();
rc = cib_conn->cmds->signon(
cib_conn, crm_system_name, cib_command_synchronous);
if(rc != cib_ok) {
fprintf(stderr, "Error signing on to the CIB service: %s\n",
cib_error2string(rc));
return rc;
}
cib_xml_copy = get_cib_copy(cib_conn);
}
set_working_set_defaults(&data_set);
data_set.input = cib_xml_copy;
data_set.now = new_ha_date(TRUE);
cluster_status(&data_set);
rsc = pe_find_resource(data_set.resources, rsc_id);
if(rsc != NULL) {
rsc_id = rsc->id;
} else {
rc = cib_NOTEXISTS;
}
}
if(rsc_cmd == 'R' || rsc_cmd == 'C' || rsc_cmd == 'P') {
GCHSource *src = NULL;
src = init_client_ipc_comms(CRM_SYSTEM_CRMD, crmd_msg_callback,
NULL, &crmd_channel);
if(src == NULL) {
fprintf(stderr,
"Error signing on to the CRMd service\n");
return 1;
}
send_hello_message(
crmd_channel, our_pid, crm_system_name, "0", "1");
set_IPC_Channel_dnotify(src, resource_ipc_connection_destroy);
}
if(rsc_cmd == 'L') {
rc = cib_ok;
do_find_resource_list(&data_set, FALSE);
} else if(rsc_cmd == 'l') {
rc = cib_ok;
do_find_resource_list(&data_set, TRUE);
} else if(rsc_cmd == 'C') {
resource_t *rsc = pe_find_resource(data_set.resources, rsc_id);
delete_lrm_rsc(crmd_channel, host_uname,
rsc?rsc->id:rsc_id, rsc?rsc->long_name:NULL);
sleep(5);
refresh_lrm(crmd_channel, host_uname);
if(rsc != NULL) {
char *now_s = NULL;
time_t now = time(NULL);
/* force the TE to start a transition */
sleep(5); /* wait for the refresh */
now_s = crm_itoa(now);
update_attr(cib_conn, cib_sync_call,
XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, "last-lrm-refresh", now_s);
crm_free(now_s);
}
} else if(rc == cib_NOTEXISTS) {
fprintf(stderr, "Resource %s not found: %s\n",
crm_str(rsc_id), cib_error2string(rc));
} else if(rsc_cmd == 'W') {
CRM_DEV_ASSERT(rsc_id != NULL);
rc = do_find_resource(rsc_id, &data_set);
} else if(rsc_cmd == 'x') {
CRM_DEV_ASSERT(rsc_id != NULL);
rc = dump_resource(rsc_id, &data_set);
} else if(rsc_cmd == 'U') {
rc = migrate_resource(rsc_id, NULL, NULL, cib_conn);
} else if(rsc_cmd == 'M') {
node_t *dest = NULL;
node_t *current = NULL;
const char *current_uname = NULL;
resource_t *rsc = pe_find_resource(data_set.resources, rsc_id);
if(rsc != NULL && rsc->running_on != NULL) {
current = rsc->running_on->data;
if(current != NULL) {
current_uname = current->details->uname;
}
}
if(host_uname != NULL) {
dest = pe_find_node(data_set.nodes, host_uname);
}
if(rsc == NULL) {
fprintf(stderr, "Resource %s not migrated:"
" not found\n", rsc_id);
} else if(rsc->variant == pe_native
&& g_list_length(rsc->running_on) > 1) {
fprintf(stderr, "Resource %s not migrated:"
" active on multiple nodes\n", rsc_id);
} else if(host_uname != NULL && dest == NULL) {
fprintf(stderr, "Error performing operation: "
"%s is not a known node\n", host_uname);
} else if(host_uname != NULL
&& safe_str_eq(current_uname, host_uname)) {
fprintf(stderr, "Error performing operation: "
"%s is already active on %s\n",
rsc_id, host_uname);
} else if(current_uname != NULL
&& (do_force || host_uname == NULL)) {
rc = migrate_resource(rsc_id, current_uname,
host_uname, cib_conn);
} else if(host_uname != NULL) {
rc = migrate_resource(
rsc_id, NULL, host_uname, cib_conn);
} else {
fprintf(stderr, "Resource %s not migrated: "
"not-active and no prefered location"
" specified.\n", rsc_id);
}
} else if(rsc_cmd == 'G') {
CRM_DEV_ASSERT(rsc_id != NULL);
rc = dump_resource_prop(rsc_id, prop_name, &data_set);
} else if(rsc_cmd == 'S') {
crm_data_t *msg_data = NULL;
if(prop_value == NULL) {
fprintf(stderr, "You need to supply a value with the -v option\n");
return CIBRES_MISSING_FIELD;
} else if(cib_conn == NULL) {
return cib_connection;
}
CRM_DEV_ASSERT(rsc_id != NULL);
CRM_DEV_ASSERT(rsc_type != NULL);
CRM_DEV_ASSERT(prop_name != NULL);
CRM_DEV_ASSERT(prop_value != NULL);
msg_data = create_xml_node(NULL, rsc_type);
crm_xml_add(msg_data, XML_ATTR_ID, rsc_id);
crm_xml_add(msg_data, prop_name, prop_value);
rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_RESOURCES,
msg_data, NULL, cib_sync_call);
free_xml(msg_data);
} else if(rsc_cmd == 'g') {
CRM_DEV_ASSERT(rsc_id != NULL);
rc = dump_resource_attr(rsc_id, prop_name, &data_set);
} else if(rsc_cmd == 'p') {
CRM_DEV_ASSERT(rsc_id != NULL);
if(prop_value == NULL) {
fprintf(stderr, "You need to supply a value with the -v option\n");
return CIBRES_MISSING_FIELD;
}
rc = set_resource_attr(rsc_id, prop_set, prop_id, prop_name,
prop_value, cib_conn, &data_set);
} else if(rsc_cmd == 'd') {
CRM_DEV_ASSERT(rsc_id != NULL);
rc = delete_resource_attr(rsc_id, prop_id, prop_set, prop_name,
cib_conn, &data_set);
} else if(rsc_cmd == 'P') {
HA_Message *cmd = NULL;
cmd = create_request(CRM_OP_REPROBE, NULL, host_uname,
CRM_SYSTEM_CRMD, crm_system_name, our_pid);
send_ipc_message(crmd_channel, cmd);
crm_msg_del(cmd);
} else if(rsc_cmd == 'R') {
refresh_lrm(crmd_channel, host_uname);
} else if(rsc_cmd == 'D') {
crm_data_t *msg_data = NULL;
int cib_options = cib_sync_call;
CRM_CHECK(rsc_id != NULL, return cib_NOTEXISTS);
if(rsc_type == NULL) {
fprintf(stderr, "You need to specify a resource type with -t");
return cib_NOTEXISTS;
} else if(cib_conn == NULL) {
return cib_connection;
}
if(do_force) {
cib_options |= cib_scope_local|cib_quorum_override;
}
msg_data = create_xml_node(NULL, rsc_type);
crm_xml_add(msg_data, XML_ATTR_ID, rsc_id);
rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_RESOURCES,
msg_data, NULL, cib_options);
free_xml(msg_data);
} else {
fprintf(stderr, "Unknown command: %c\n", rsc_cmd);
}
if(cib_conn != NULL) {
cleanup_calculations(&data_set);
cib_conn->cmds->signoff(cib_conn);
}
if(rc == cib_no_quorum) {
fprintf(stderr, "Error performing operation: %s\n",
cib_error2string(rc));
fprintf(stderr, "Try using -f\n");
} else if(rc != cib_ok) {
fprintf(stderr, "Error performing operation: %s\n",
cib_error2string(rc));
}
return rc;
}
void
usage(const char *cmd, int exit_status)
{
FILE *stream;
stream = exit_status ? stderr : stdout;
fprintf(stream, "usage: %s [-?VS] -(L|Q|W|D|C|P|p) [options]\n", cmd);
fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?');
fprintf(stream, "\t--%s (-%c)\t: "
"turn on debug info. additional instances increase verbosity\n",
"verbose", 'V');
fprintf(stream, "\t--%s (-%c)\t: Print only the value on stdout (for use with -W)\n",
"quiet", 'Q');
fprintf(stream, "\nCommands\n");
fprintf(stream, "\t--%s (-%c)\t: List all resources\n", "list", 'L');
fprintf(stream, "\t--%s (-%c)\t: Query a resource\n"
"\t\t\t Requires: -r\n", "query-xml", 'x');
fprintf(stream, "\t--%s (-%c)\t: Locate a resource\n"
"\t\t\t Requires: -r\n", "locate", 'W');
fprintf(stream, "\t--%s (-%c)\t: Migrate a resource from it current"
" location. Use -H to specify a destination\n"
"\t\tIf -H is not specified, we will force the resource to move by"
" creating a rule for the current location and a score of -INFINITY\n"
"\t\tNOTE: This will prevent the resource from running on this"
" node until the constraint is removed with -U\n"
"\t\t\t Requires: -r, Optional: -H, -f, --lifetime\n", "migrate", 'M');
fprintf(stream, "\t--%s (-%c)\t: Remove all constraints created by -M\n"
"\t\t\t Requires: -r\n", "un-migrate", 'U');
fprintf(stream, "\t--%s (-%c)\t: Delete a resource from the CIB\n"
"\t\t\t Requires: -r, -t\n", "delete", 'D');
fprintf(stream, "\t--%s (-%c)\t: Delete a resource from the LRM\n"
"\t\t\t Requires: -r. Optional: -H\n", "cleanup", 'C');
fprintf(stream, "\t--%s (-%c)\t: Recheck for resources started outside of the CRM\n"
"\t\t\t Optional: -H\n", "reprobe", 'P');
fprintf(stream, "\t--%s (-%c)\t: Refresh the CIB from the LRM\n"
"\t\t\t Optional: -H\n", "refresh", 'R');
fprintf(stream, "\t--%s (-%c) <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, "\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\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-relocation", '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/crmadmin.c b/crm/admin/crmadmin.c
index 25d45812c0..dbd33e6b27 100644
--- a/crm/admin/crmadmin.c
+++ b/crm/admin/crmadmin.c
@@ -1,731 +1,732 @@
/* $Id: crmadmin.c,v 1.76 2006/07/06 09:30:27 andrew Exp $ */
/*
* 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 <portability.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 <heartbeat.h>
#include <hb_api.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
int message_timer_id = -1;
int message_timeout_ms = 30*1000;
GMainLoop *mainloop = NULL;
IPC_Channel *crmd_channel = NULL;
char *admin_uuid = NULL;
void usage(const char *cmd, int exit_status);
ll_cluster_t *do_init(void);
int do_work(ll_cluster_t * hb_cluster);
void crmd_ipc_connection_destroy(gpointer user_data);
gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data);
char *pluralSection(const char *a_section);
crm_data_t *handleCibMod(void);
int do_find_node_list(crm_data_t *xml_node);
gboolean admin_message_timeout(gpointer data);
gboolean is_node_online(crm_data_t *node_state);
enum debug {
debug_none,
debug_dec,
debug_inc
};
gboolean BE_VERBOSE = FALSE;
int expected_responses = 1;
gboolean BASH_EXPORT = FALSE;
gboolean DO_HEALTH = FALSE;
gboolean DO_RESET = FALSE;
gboolean DO_RESOURCE = FALSE;
gboolean DO_ELECT_DC = FALSE;
gboolean DO_WHOIS_DC = FALSE;
gboolean DO_NODE_LIST = FALSE;
gboolean BE_SILENT = FALSE;
gboolean DO_RESOURCE_LIST = FALSE;
enum debug DO_DEBUG = debug_none;
const char *crmd_operation = NULL;
crm_data_t *msg_options = NULL;
const char *standby_on_off = "on";
const char *admin_verbose = XML_BOOLEAN_FALSE;
char *id = NULL;
char *this_msg_reference = NULL;
char *disconnect = NULL;
char *dest_node = NULL;
char *rsc_name = NULL;
char *crm_option = NULL;
int operation_status = 0;
const char *sys_to = NULL;
const char *crm_system_name = NULL;
#define OPTARGS "V?K:S:HE:Dd:i:RNqt:Bv"
int
main(int argc, char **argv)
{
int argerr = 0;
int flag;
ll_cluster_t *hb_cluster = NULL;
#ifdef HAVE_GETOPT_H
int option_index = 0;
static struct option long_options[] = {
/* Top-level Options */
{"verbose", 0, 0, 'V'},
{"help", 0, 0, '?'},
{"quiet", 0, 0, 'q'},
{"reference", 1, 0, 0},
{XML_ATTR_TIMEOUT, 1, 0, 't'},
{"bash-export", 0, 0, 'B'},
/* daemon options */
{"kill", 1, 0, 'K'}, /* stop a node */
{"die", 0, 0, 0}, /* kill a node, no respawn */
{"debug_inc", 1, 0, 'i'},
{"debug_dec", 1, 0, 'd'},
{"status", 1, 0, 'S'},
{"standby", 1, 0, 's'},
{"active", 1, 0, 'a'},
{"health", 0, 0, 'H'},
{"election", 0, 0, 'E'},
{"dc_lookup", 0, 0, 'D'},
{"nodes", 0, 0, 'N'},
{"option", 1, 0, 'o'},
{"version", 0, 0, 'v'},
{0, 0, 0, 0}
};
#endif
crm_system_name = basename(argv[0]);
crm_log_init(crm_system_name);
if(argc < 2) {
usage(crm_system_name, LSB_EXIT_EINVAL);
}
while (1) {
#ifdef HAVE_GETOPT_H
flag = getopt_long(argc, argv, OPTARGS,
long_options, &option_index);
#else
flag = getopt(argc, argv, OPTARGS);
#endif
if (flag == -1)
break;
switch(flag) {
#ifdef HAVE_GETOPT_H
case 0:
printf("option %s", long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
if (strcasecmp("reference",
long_options[option_index].name) == 0) {
this_msg_reference =
crm_strdup(optarg);
} else if (strcasecmp("die",
long_options[option_index].name) == 0) {
DO_RESET = TRUE;
crmd_operation = CRM_OP_DIE;
} else {
printf( "?? Long option (--%s) is not yet properly supported ??\n",
long_options[option_index].name);
++argerr;
}
break;
#endif
/* a sample test for multiple instance
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
*/
case 'v':
fprintf(stdout, "HA Version %s, CRM Version %s (CIB feature set %s)\n",
VERSION, CRM_FEATURE_SET, CIB_FEATURE_SET);
exit(0);
break;
case 'V':
BE_VERBOSE = TRUE;
admin_verbose = XML_BOOLEAN_TRUE;
cl_log_enable_stderr(TRUE);
alter_debug(DEBUG_INC);
break;
case 't':
message_timeout_ms = atoi(optarg);
if(message_timeout_ms < 1) {
message_timeout_ms = 30*1000;
}
break;
case '?':
usage(crm_system_name, LSB_EXIT_OK);
break;
case 'D':
DO_WHOIS_DC = TRUE;
break;
case 'B':
BASH_EXPORT = TRUE;
break;
case 'K':
DO_RESET = TRUE;
crm_debug_2("Option %c => %s", flag, optarg);
dest_node = crm_strdup(optarg);
crmd_operation = CRM_OP_LOCAL_SHUTDOWN;
break;
case 'q':
BE_SILENT = TRUE;
break;
case 'i':
DO_DEBUG = debug_inc;
crm_debug_2("Option %c => %s", flag, optarg);
dest_node = crm_strdup(optarg);
break;
case 'd':
DO_DEBUG = debug_dec;
crm_debug_2("Option %c => %s", flag, optarg);
dest_node = crm_strdup(optarg);
break;
case 'S':
DO_HEALTH = TRUE;
crm_debug_2("Option %c => %s", flag, optarg);
dest_node = crm_strdup(optarg);
break;
case 'E':
DO_ELECT_DC = TRUE;
break;
case 'N':
DO_NODE_LIST = TRUE;
break;
case 'H':
DO_HEALTH = TRUE;
break;
default:
printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag);
++argerr;
break;
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
if (optind > argc) {
++argerr;
}
if (argerr) {
usage(crm_system_name, LSB_EXIT_GENERIC);
}
hb_cluster = do_init();
if (hb_cluster != NULL) {
int res = do_work(hb_cluster);
if(res == 0) {
} else if (res > 0) {
/* wait for the reply by creating a mainloop and running it until
* the callbacks are invoked...
*/
mainloop = g_main_new(FALSE);
expected_responses++;
crm_debug_2("Waiting for %d replies from the local CRM", expected_responses);
message_timer_id = Gmain_timeout_add(
message_timeout_ms, admin_message_timeout, NULL);
g_main_run(mainloop);
return_to_orig_privs();
} else {
crm_err("No message to send");
operation_status = -1;
}
} else {
crm_warn("Init failed, could not perform requested operations");
operation_status = -2;
}
crm_debug_2("%s exiting normally", crm_system_name);
return operation_status;
}
int
do_work(ll_cluster_t * hb_cluster)
{
int ret = 1;
/* construct the request */
crm_data_t *msg_data = NULL;
gboolean all_is_good = TRUE;
msg_options = create_xml_node(NULL, XML_TAG_OPTIONS);
crm_xml_add(msg_options, XML_ATTR_VERBOSE, admin_verbose);
crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
if (DO_HEALTH == TRUE) {
crm_debug_2("Querying the system");
sys_to = CRM_SYSTEM_DC;
if (dest_node != NULL) {
sys_to = CRM_SYSTEM_CRMD;
crmd_operation = CRM_OP_PING;
if (BE_VERBOSE) {
expected_responses = 1;
}
crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
} else {
crm_info("Cluster-wide health not available yet");
all_is_good = FALSE;
}
} else if(DO_ELECT_DC) {
/* tell the local node to initiate an election */
sys_to = CRM_SYSTEM_CRMD;
crmd_operation = CRM_OP_VOTE;
crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
dest_node = NULL;
ret = 0; /* no return message */
} else if(DO_WHOIS_DC) {
sys_to = CRM_SYSTEM_DC;
crmd_operation = CRM_OP_PING;
crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
dest_node = NULL;
} else if(DO_NODE_LIST) {
cib_t * the_cib = cib_new();
crm_data_t *output = NULL;
enum cib_errors rc = the_cib->cmds->signon(
the_cib, crm_system_name, cib_command_synchronous);
if(rc != cib_ok) {
return -1;
}
output = get_cib_copy(the_cib);
do_find_node_list(output);
free_xml(output);
the_cib->cmds->signoff(the_cib);
exit(rc);
} else if(DO_RESET) {
/* tell dest_node to initiate the shutdown proceedure
*
* if dest_node is NULL, the request will be sent to the
* local node
*/
sys_to = CRM_SYSTEM_CRMD;
crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
ret = 0; /* no return message */
} else if(DO_DEBUG == debug_inc) {
/* tell dest_node to increase its debug level
*
* if dest_node is NULL, the request will be sent to the
* local node
*/
sys_to = CRM_SYSTEM_CRMD;
crmd_operation = CRM_OP_DEBUG_UP;
ret = 0; /* no return message */
} else if(DO_DEBUG == debug_dec) {
/* tell dest_node to increase its debug level
*
* if dest_node is NULL, the request will be sent to the
* local node
*/
sys_to = CRM_SYSTEM_CRMD;
crmd_operation = CRM_OP_DEBUG_DOWN;
ret = 0; /* no return message */
} else {
crm_err("Unknown options");
all_is_good = FALSE;
}
if(all_is_good == FALSE) {
crm_err("Creation of request failed. No message to send");
return -1;
}
/* send it */
if (crmd_channel == NULL) {
crm_err("The IPC connection is not valid, cannot send anything");
return -1;
}
if(sys_to == NULL) {
if (dest_node != NULL) {
sys_to = CRM_SYSTEM_CRMD;
} else {
sys_to = CRM_SYSTEM_DC;
}
}
{
HA_Message *cmd = create_request(
crmd_operation, msg_data, dest_node, sys_to,
crm_system_name, admin_uuid);
if(this_msg_reference != NULL) {
ha_msg_mod(cmd, XML_ATTR_REFERENCE, this_msg_reference);
}
send_ipc_message(crmd_channel, cmd);
crm_msg_del(cmd);
}
return ret;
}
void
crmd_ipc_connection_destroy(gpointer user_data)
{
crm_info("Connection to CRMd was terminated");
exit(1);
}
ll_cluster_t *
do_init(void)
{
int facility;
GCHSource *src = NULL;
ll_cluster_t *hb_cluster = NULL;
/* change the logging facility to the one used by heartbeat daemon */
hb_cluster = ll_cluster_new("heartbeat");
crm_debug_2("Switching to Heartbeat logger");
if (( facility =
hb_cluster->llc_ops->get_logfacility(hb_cluster)) > 0) {
cl_log_set_facility(facility);
}
crm_malloc0(admin_uuid, 11);
if(admin_uuid != NULL) {
snprintf(admin_uuid, 10, "%d", getpid());
admin_uuid[10] = '\0';
}
src = init_client_ipc_comms(
CRM_SYSTEM_CRMD, admin_msg_callback, NULL, &crmd_channel);
if(DO_RESOURCE || DO_RESOURCE_LIST || DO_NODE_LIST) {
return hb_cluster;
} else if(crmd_channel != NULL) {
send_hello_message(
crmd_channel, admin_uuid, crm_system_name,"0", "1");
set_IPC_Channel_dnotify(src, crmd_ipc_connection_destroy);
return hb_cluster;
}
return NULL;
}
gboolean
admin_msg_callback(IPC_Channel * server, void *private_data)
{
int lpc = 0;
IPC_Message *msg = NULL;
ha_msg_input_t *new_input = NULL;
gboolean hack_return_good = TRUE;
static int received_responses = 0;
char *filename = NULL;
int filename_len = 0;
const char *result = NULL;
Gmain_timeout_remove(message_timer_id);
while (server->ch_status != IPC_DISCONNECT
&& server->ops->is_message_pending(server) == TRUE) {
if(new_input != NULL) {
delete_ha_msg_input(new_input);
new_input = NULL;
}
if (server->ops->recv(server, &msg) != IPC_OK) {
perror("Receive failure:");
return !hack_return_good;
}
if (msg == NULL) {
crm_debug_4("No message this time");
continue;
}
lpc++;
received_responses++;
new_input = new_ipc_msg_input(msg);
crm_log_message(LOG_MSG, new_input->msg);
msg->msg_done(msg);
if (new_input->xml == NULL) {
crm_info("XML in IPC message was not valid... "
"discarding.");
goto cleanup;
} else if (validate_crm_message(
new_input->msg, crm_system_name, admin_uuid,
XML_ATTR_RESPONSE) == FALSE) {
crm_debug_2("Message was not a CRM response. Discarding.");
goto cleanup;
}
result = cl_get_string(new_input->msg, XML_ATTR_RESULT);
if(result == NULL || strcasecmp(result, "ok") == 0) {
result = "pass";
} else {
result = "fail";
}
if(DO_HEALTH) {
const char *state = crm_element_value(
new_input->xml, "crmd_state");
printf("Status of %s@%s: %s (%s)\n",
crm_element_value(new_input->xml,XML_PING_ATTR_SYSFROM),
cl_get_string(new_input->msg, F_CRM_HOST_FROM),
state,
crm_element_value(new_input->xml,XML_PING_ATTR_STATUS));
if(BE_SILENT && state != NULL) {
fprintf(stderr, "%s\n", state);
}
} else if(DO_WHOIS_DC) {
const char *dc = cl_get_string(
new_input->msg, F_CRM_HOST_FROM);
printf("Designated Controller is: %s\n", dc);
if(BE_SILENT && dc != NULL) {
fprintf(stderr, "%s\n", dc);
}
}
if (this_msg_reference != NULL) {
/* in testing mode... */
/* 31 = "test-_.xml" + an_int_as_string + '\0' */
filename_len = 31 + strlen(this_msg_reference);
crm_malloc0(filename, filename_len);
if(filename != NULL) {
sprintf(filename, "%s-%s_%d.xml",
result, this_msg_reference,
received_responses);
filename[filename_len - 1] = '\0';
if (0 > write_xml_file(
new_input->xml, filename, FALSE)) {
crm_crit("Could not save response to"
" %s", filename);
}
}
}
cleanup:
delete_ha_msg_input(new_input);
+ new_input = NULL;
}
if (server->ch_status == IPC_DISCONNECT) {
crm_debug_2("admin_msg_callback: received HUP");
return !hack_return_good;
}
if (received_responses >= expected_responses) {
crm_debug_2(
"Recieved expected number (%d) of messages from Heartbeat."
" Exiting normally.", expected_responses);
g_main_quit(mainloop);
return !hack_return_good;
}
message_timer_id = Gmain_timeout_add(
message_timeout_ms, admin_message_timeout, NULL);
return hack_return_good;
}
gboolean
admin_message_timeout(gpointer data)
{
fprintf(stderr, "No messages received in %d seconds.. aborting\n",
(int)message_timeout_ms/1000);
crm_err("No messages received in %d seconds",
(int)message_timeout_ms/1000);
g_main_quit(mainloop);
return FALSE;
}
gboolean
is_node_online(crm_data_t *node_state)
{
const char *uname = crm_element_value(node_state,XML_ATTR_UNAME);
const char *join_state = crm_element_value(node_state,XML_CIB_ATTR_JOINSTATE);
const char *exp_state = crm_element_value(node_state,XML_CIB_ATTR_EXPSTATE);
const char *crm_state = crm_element_value(node_state,XML_CIB_ATTR_CRMDSTATE);
const char *ha_state = crm_element_value(node_state,XML_CIB_ATTR_HASTATE);
const char *ccm_state = crm_element_value(node_state,XML_CIB_ATTR_INCCM);
if(safe_str_neq(join_state, CRMD_JOINSTATE_DOWN)
&& (ha_state == NULL || safe_str_eq(ha_state, ACTIVESTATUS))
&& crm_is_true(ccm_state)
&& safe_str_eq(crm_state, ONLINESTATUS)) {
crm_debug_3("Node %s is online", uname);
return TRUE;
}
crm_debug_3("Node %s: ha=%s ccm=%s join=%s exp=%s crm=%s",
uname, crm_str(ha_state), crm_str(ccm_state),
crm_str(join_state), crm_str(exp_state),
crm_str(crm_state));
crm_debug_3("Node %s is offline", uname);
return FALSE;
}
int
do_find_node_list(crm_data_t *xml_node)
{
int found = 0;
crm_data_t *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node);
xml_child_iter_filter(
nodes, node, XML_CIB_TAG_NODE,
if(BASH_EXPORT) {
printf("export %s=%s\n",
crm_element_value(node, XML_ATTR_UNAME),
crm_element_value(node, XML_ATTR_ID));
} else {
printf("%s node: %s (%s)\n",
crm_element_value(node, XML_ATTR_TYPE),
crm_element_value(node, XML_ATTR_UNAME),
crm_element_value(node, XML_ATTR_ID));
}
found++;
);
if(found == 0) {
printf("NO nodes configured\n");
}
return found;
}
void
usage(const char *cmd, int exit_status)
{
FILE *stream;
stream = exit_status ? stderr : stdout;
fprintf(stream, "usage: %s [-?Vs] [command] [command args]\n", cmd);
fprintf(stream, "Options\n");
fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?');
fprintf(stream, "\t--%s (-%c)\t: version details\n", "version", 'v');
fprintf(stream, "\t--%s (-%c)\t: "
"turn on debug info. additional instances increase verbosity\n",
"verbose", 'V');
fprintf(stream, "\t--%s (-%c)\t: be very *very* quiet\n", "quiet", 'q');
fprintf(stream, "\t--%s (-%c)\t: Only applies to -N.\n"
"\t\tCreate Bash export entries of the form \"export uname=uuid\"\n", "bash-export", 'B');
fprintf(stream, "\nCommands\n");
fprintf(stream, "\t--%s (-%c) <node>\t: "
"increment the CRMd debug level on <node>\n", CRM_OP_DEBUG_UP,'i');
fprintf(stream, "\t--%s (-%c) <node>\t: "
"decrement the CRMd debug level on <node>\n", CRM_OP_DEBUG_DOWN,'d');
fprintf(stream, "\t--%s (-%c) <node>\t: "
"shutdown the CRMd on <node>\n", "kill", 'K');
fprintf(stream, "\t--%s (-%c) <node>\t: "
"request the status of <node>\n", "status", 'S');
#if 0
fprintf(stream, "\t--%s (-%c)\t\t: "
"request the status of all nodes\n", "health", 'H');
#endif
fprintf(stream, "\t--%s (-%c) <node>\t: "
"initiate an election from <node>\n", "election", 'E');
fprintf(stream, "\t--%s (-%c)\t: "
"request the uname of the DC\n", "dc_lookup", 'D');
fprintf(stream, "\t--%s (-%c)\t\t: "
"request the uname of all member nodes\n", "nodes", 'N');
/* fprintf(stream, "\t--%s (-%c)\t\n", "disconnect", 'D'); */
fflush(stream);
exit(exit_status);
}
diff --git a/crm/crmd/callbacks.c b/crm/crmd/callbacks.c
index 9eb81f9d72..48a0de3f50 100644
--- a/crm/crmd/callbacks.c
+++ b/crm/crmd/callbacks.c
@@ -1,677 +1,676 @@
/*
* 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 <portability.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <string.h>
#include <crmd_fsa.h>
#include <heartbeat.h>
#include <hb_api.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <crm/cib.h>
#include <crmd.h>
#include <crmd_messages.h>
#include <crmd_callbacks.h>
GHashTable *crmd_peer_state = NULL;
crm_data_t *find_xml_in_hamessage(const HA_Message * msg);
void crmd_ha_connection_destroy(gpointer user_data);
/* From join_dc... */
extern gboolean check_join_state(
enum crmd_fsa_state cur_state, const char *source);
/* #define MAX_EMPTY_CALLBACKS 20 */
/* int empty_callbacks = 0; */
#define trigger_fsa(source) crm_debug_3("Triggering FSA: %s", __FUNCTION__); \
G_main_set_trigger(source);
gboolean
crmd_ha_msg_dispatch(ll_cluster_t *cluster_conn, gpointer user_data)
{
IPC_Channel *channel = NULL;
gboolean stay_connected = TRUE;
crm_debug_3("Invoked");
if(cluster_conn != NULL) {
channel = cluster_conn->llc_ops->ipcchan(cluster_conn);
}
CRM_CHECK(cluster_conn != NULL, ;);
CRM_CHECK(channel != NULL, ;);
if(channel != NULL && IPC_ISRCONN(channel)) {
if(cluster_conn->llc_ops->msgready(cluster_conn) == 0) {
crm_debug_2("no message ready yet");
}
/* invoke the callbacks but dont block */
cluster_conn->llc_ops->rcvmsg(cluster_conn, 0);
}
if (channel == NULL || channel->ch_status != IPC_CONNECT) {
if(is_set(fsa_input_register, R_HA_DISCONNECTED) == FALSE) {
crm_crit("Lost connection to heartbeat service.");
} else {
crm_info("Lost connection to heartbeat service.");
}
trigger_fsa(fsa_source);
stay_connected = FALSE;
}
return stay_connected;
}
void
crmd_ha_connection_destroy(gpointer user_data)
{
crm_debug_3("Invoked");
if(is_set(fsa_input_register, R_HA_DISCONNECTED)) {
/* we signed out, so this is expected */
crm_info("Heartbeat disconnection complete");
return;
}
crm_crit("Lost connection to heartbeat service!");
register_fsa_input(C_HA_DISCONNECT, I_ERROR, NULL);
trigger_fsa(fsa_source);
}
void
crmd_ha_msg_callback(HA_Message * msg, void* private_data)
{
int level = LOG_DEBUG;
ha_msg_input_t *new_input = NULL;
oc_node_t *from_node = NULL;
const char *from = ha_msg_value(msg, F_ORIG);
const char *seq = ha_msg_value(msg, F_SEQ);
const char *op = ha_msg_value(msg, F_CRM_TASK);
const char *sys_to = ha_msg_value(msg, F_CRM_SYS_TO);
const char *sys_from = ha_msg_value(msg, F_CRM_SYS_FROM);
CRM_DEV_ASSERT(from != NULL);
crm_debug_2("HA[inbound]: %s from %s", op, from);
if(fsa_membership_copy == NULL) {
crm_debug("Ignoring HA messages until we are"
" connected to the CCM (%s op from %s)", op, from);
crm_log_message_adv(
LOG_MSG, "HA[inbound]: Ignore (No CCM)", msg);
return;
}
from_node = g_hash_table_lookup(fsa_membership_copy->members, from);
if(from_node == NULL) {
if(safe_str_eq(op, CRM_OP_VOTE)) {
level = LOG_WARNING;
} else if(AM_I_DC && safe_str_eq(op, CRM_OP_JOIN_ANNOUNCE)) {
level = LOG_WARNING;
} else if(safe_str_eq(sys_from, CRM_SYSTEM_DC)) {
level = LOG_WARNING;
}
do_crm_log(level,
"Ignoring HA message (op=%s) from %s: not in our"
" membership list (size=%d)", op, from,
g_hash_table_size(fsa_membership_copy->members));
crm_log_message_adv(LOG_MSG, "HA[inbound]: CCM Discard", msg);
} else if(safe_str_eq(sys_to, CRM_SYSTEM_DC) && AM_I_DC == FALSE) {
crm_debug_2("Ignoring message for the DC [F_SEQ=%s]", seq);
return;
} else if(safe_str_eq(sys_from, CRM_SYSTEM_DC)) {
if(AM_I_DC && safe_str_neq(from, fsa_our_uname)) {
crm_err("Another DC detected: %s (op=%s)", from, op);
/* make sure the election happens NOW */
level = LOG_WARNING;
if(fsa_state != S_ELECTION) {
new_input = new_ha_msg_input(msg);
register_fsa_error_adv(
C_FSA_INTERNAL, I_ELECTION, NULL,
new_input, __FUNCTION__);
}
#if 0
/* still thinking about this one...
* could create a timing issue if we dont notice the
* election before a new DC is elected.
*/
} else if(fsa_our_dc != NULL && safe_str_neq(from,fsa_our_dc)){
crm_warn("Ignoring message from wrong DC: %s vs. %s ",
from, fsa_our_dc);
return;
#endif
} else {
crm_debug_2("Processing DC message from %s [F_SEQ=%s]",
from, seq);
}
}
if(new_input == NULL) {
crm_log_message_adv(LOG_MSG, "HA[inbound]", msg);
new_input = new_ha_msg_input(msg);
route_message(C_HA_MESSAGE, new_input);
}
delete_ha_msg_input(new_input);
trigger_fsa(fsa_source);
return;
}
/*
* Apparently returning TRUE means "stay connected, keep doing stuff".
* Returning FALSE means "we're all done, close the connection"
*/
gboolean
crmd_ipc_msg_callback(IPC_Channel *client, gpointer user_data)
{
int lpc = 0;
HA_Message *msg = NULL;
ha_msg_input_t *new_input = NULL;
crmd_client_t *curr_client = (crmd_client_t*)user_data;
gboolean stay_connected = TRUE;
crm_debug_2("Invoked: %s",
curr_client->table_key);
while(IPC_ISRCONN(client)) {
if(client->ops->is_message_pending(client) == 0) {
break;
}
msg = msgfromIPC_noauth(client);
if (msg == NULL) {
crm_info("%s: no message this time",
curr_client->table_key);
continue;
}
lpc++;
new_input = new_ha_msg_input(msg);
crm_msg_del(msg);
crm_debug_2("Processing msg from %s", curr_client->table_key);
crm_log_message_adv(LOG_DEBUG_2, "CRMd[inbound]", new_input->msg);
if(crmd_authorize_message(new_input, curr_client)) {
route_message(C_IPC_MESSAGE, new_input);
}
delete_ha_msg_input(new_input);
-
+ new_input = NULL;
msg = NULL;
- new_input = NULL;
if(client->ch_status != IPC_CONNECT) {
break;
}
}
crm_debug_2("Processed %d messages", lpc);
if (client->ch_status != IPC_CONNECT) {
stay_connected = FALSE;
process_client_disconnect(curr_client);
}
trigger_fsa(fsa_source);
return stay_connected;
}
extern GCHSource *lrm_source;
gboolean
lrm_dispatch(IPC_Channel *src_not_used, gpointer user_data)
{
/* ?? src == lrm_channel ?? */
ll_lrm_t *lrm = (ll_lrm_t*)user_data;
IPC_Channel *lrm_channel = lrm->lrm_ops->ipcchan(lrm);
crm_debug_3("Invoked");
lrm->lrm_ops->rcvmsg(lrm, FALSE);
if(lrm_channel->ch_status != IPC_CONNECT) {
if(is_set(fsa_input_register, R_LRM_CONNECTED)) {
crm_crit("LRM Connection failed");
register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL);
clear_bit_inplace(fsa_input_register, R_LRM_CONNECTED);
} else {
crm_info("LRM Connection disconnected");
}
lrm_source = NULL;
return FALSE;
}
return TRUE;
}
extern gboolean process_lrm_event(lrm_op_t *op);
void
lrm_op_callback(lrm_op_t* op)
{
CRM_CHECK(op != NULL, return);
process_lrm_event(op);
}
void
crmd_ha_status_callback(
const char *node, const char * status, void* private_data)
{
crm_data_t *update = NULL;
crm_notice("Status update: Node %s now has status [%s]",node,status);
if(safe_str_eq(status, DEADSTATUS)) {
/* this node is taost */
update = create_node_state(
node, status, XML_BOOLEAN_NO, OFFLINESTATUS,
CRMD_STATE_INACTIVE, NULL, TRUE, __FUNCTION__);
if(update) {
crm_xml_add(update, XML_CIB_ATTR_REPLACE,
XML_TAG_TRANSIENT_NODEATTRS);
}
} else if(safe_str_eq(status, ACTIVESTATUS)) {
update = create_node_state(
node, status, NULL, NULL, NULL, NULL,
FALSE, __FUNCTION__);
}
if(update != NULL) {
/* this change should not be broadcast */
fsa_cib_anon_update(
XML_CIB_TAG_STATUS, update,
cib_inhibit_bcast|cib_scope_local|cib_quorum_override);
trigger_fsa(fsa_source);
free_xml(update);
} else {
crm_info("Ping node %s is %s", node, status);
}
}
void
crmd_client_status_callback(const char * node, const char * client,
const char * status, void * private)
{
const char *join = NULL;
crm_data_t *update = NULL;
gboolean clear_shutdown = FALSE;
crm_debug_3("Invoked");
if(safe_str_neq(client, CRM_SYSTEM_CRMD)) {
return;
}
if(safe_str_eq(status, JOINSTATUS)){
status = ONLINESTATUS;
clear_shutdown = TRUE;
} else if(safe_str_eq(status, LEAVESTATUS)){
status = OFFLINESTATUS;
join = CRMD_STATE_INACTIVE;
/* clear_shutdown = TRUE; */
}
set_bit_inplace(fsa_input_register, R_PEER_DATA);
g_hash_table_replace(
crmd_peer_state, crm_strdup(node), crm_strdup(status));
if(is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) {
return;
} else if(fsa_state == S_STOPPING) {
return;
}
crm_notice("Status update: Client %s/%s now has status [%s]",
node, client, status);
if(safe_str_eq(status, ONLINESTATUS)) {
/* remove the cached value in case it changed */
crm_info("Uncaching UUID for %s", node);
unget_uuid(node);
}
if(safe_str_eq(node, fsa_our_dc) && safe_str_eq(status, OFFLINESTATUS)){
/* did our DC leave us */
crm_info("Got client status callback - our DC is dead");
register_fsa_input(C_CRMD_STATUS_CALLBACK, I_ELECTION, NULL);
} else {
crm_debug_3("Got client status callback");
update = create_node_state(
node, NULL, NULL, status, join,
NULL, clear_shutdown, __FUNCTION__);
if(clear_shutdown) {
crm_xml_add(update, XML_CIB_ATTR_REPLACE,
XML_TAG_TRANSIENT_NODEATTRS);
}
/* it is safe to keep these updates on the local node
* each node updates their own CIB
*/
fsa_cib_anon_update(
XML_CIB_TAG_STATUS, update,
cib_inhibit_bcast|cib_scope_local|cib_quorum_override);
free_xml(update);
if(AM_I_DC && safe_str_eq(status, OFFLINESTATUS)) {
g_hash_table_remove(confirmed_nodes, node);
g_hash_table_remove(finalized_nodes, node);
g_hash_table_remove(integrated_nodes, node);
g_hash_table_remove(welcomed_nodes, node);
check_join_state(fsa_state, __FUNCTION__);
}
}
trigger_fsa(fsa_source);
}
void
crmd_ipc_connection_destroy(gpointer user_data)
{
GCHSource *source = NULL;
crmd_client_t *client = user_data;
/* Calling this function on an _active_ connection results in:
* crmd_ipc_connection_destroy (callbacks.c:431)
* -> G_main_del_IPC_Channel (GSource.c:478)
* -> g_source_unref
* -> G_CH_destroy_int (GSource.c:647)
* -> crmd_ipc_connection_destroy (callbacks.c:437)\
*
* A better alternative is to call G_main_del_IPC_Channel() directly
*/
if(client == NULL) {
crm_debug_4("No client to delete");
return;
}
crm_debug("Disconnecting client %s (%p)", client->table_key, client);
source = client->client_source;
client->client_source = NULL;
if(source != NULL) {
crm_debug("Deleting %s (%p) from mainloop",
client->table_key, source);
G_main_del_IPC_Channel(source);
}
crm_free(client->table_key);
crm_free(client->sub_sys);
crm_free(client->uuid);
crm_free(client);
return;
}
gboolean
crmd_client_connect(IPC_Channel *client_channel, gpointer user_data)
{
crm_debug_3("Invoked");
if (client_channel == NULL) {
crm_err("Channel was NULL");
} else if (client_channel->ch_status == IPC_DISCONNECT) {
crm_err("Channel was disconnected");
} else {
crmd_client_t *blank_client = NULL;
crm_debug_3("Channel connected");
crm_malloc0(blank_client, sizeof(crmd_client_t));
CRM_ASSERT(blank_client != NULL);
crm_debug_2("Created client: %p", blank_client);
client_channel->ops->set_recv_qlen(client_channel, 100);
client_channel->ops->set_send_qlen(client_channel, 100);
blank_client->client_channel = client_channel;
blank_client->sub_sys = NULL;
blank_client->uuid = NULL;
blank_client->table_key = NULL;
blank_client->client_source =
G_main_add_IPC_Channel(
G_PRIORITY_LOW, client_channel,
FALSE, crmd_ipc_msg_callback,
blank_client, crmd_ipc_connection_destroy);
}
return TRUE;
}
gboolean ccm_dispatch(int fd, gpointer user_data)
{
int rc = 0;
oc_ev_t *ccm_token = (oc_ev_t*)user_data;
gboolean was_error = FALSE;
crm_debug_3("Invoked");
rc = oc_ev_handle_event(ccm_token);
if(rc != 0) {
if(is_set(fsa_input_register, R_CCM_DISCONNECTED) == FALSE) {
/* we signed out, so this is expected */
register_fsa_input(C_CCM_CALLBACK, I_ERROR, NULL);
crm_err("CCM connection appears to have failed: rc=%d.",
rc);
}
was_error = TRUE;
}
trigger_fsa(fsa_source);
return !was_error;
}
static gboolean fsa_have_quorum = FALSE;
void
crmd_ccm_msg_callback(
oc_ed_t event, void *cookie, size_t size, const void *data)
{
int instance = -1;
gboolean update_cache = FALSE;
struct crmd_ccm_data_s *event_data = NULL;
const oc_ev_membership_t *membership = data;
gboolean update_quorum = FALSE;
gboolean trigger_transition = FALSE;
crm_debug_3("Invoked");
if(data != NULL) {
instance = membership->m_instance;
}
crm_info("Quorum %s after event=%s (id=%d)",
ccm_have_quorum(event)?"(re)attained":"lost",
ccm_event_name(event), instance);
/*
* OC_EV_MS_NEW_MEMBERSHIP: membership with quorum
* OC_EV_MS_MS_INVALID: membership without quorum
* OC_EV_MS_NOT_PRIMARY: previous membership no longer valid
* OC_EV_MS_PRIMARY_RESTORED: previous membership restored
* OC_EV_MS_EVICTED: the client is evicted from ccm.
*/
switch(event) {
case OC_EV_MS_NEW_MEMBERSHIP:
case OC_EV_MS_INVALID:
update_cache = TRUE;
update_quorum = TRUE;
break;
case OC_EV_MS_NOT_PRIMARY:
#if UNTESTED
if(AM_I_DC == FALSE) {
break;
}
/* tell the TE to pretend it had completed and stop */
/* side effect: we'll end up in S_IDLE */
register_fsa_action(A_TE_HALT, TRUE);
#endif
break;
case OC_EV_MS_PRIMARY_RESTORED:
fsa_membership_copy->id = instance;
if(AM_I_DC && need_transition(fsa_state)) {
trigger_transition = TRUE;
}
break;
case OC_EV_MS_EVICTED:
update_quorum = TRUE;
register_fsa_input(C_FSA_INTERNAL, I_STOP, NULL);
crm_err("Shutting down after CCM event: %s",
ccm_event_name(event));
break;
default:
crm_err("Unknown CCM event: %d", event);
}
if(update_quorum && ccm_have_quorum(event) == FALSE) {
/* did we just loose quorum? */
if(fsa_have_quorum && need_transition(fsa_state)) {
crm_info("Quorum lost: triggering transition (%s)",
ccm_event_name(event));
trigger_transition = TRUE;
}
fsa_have_quorum = FALSE;
} else if(update_quorum) {
crm_debug_2("Updating quorum after event %s",
ccm_event_name(event));
fsa_have_quorum = TRUE;
}
if(trigger_transition) {
crm_debug_2("Scheduling transition after event %s",
ccm_event_name(event));
/* make sure that when we query the CIB that it has
* the changes that triggered the transition
*/
switch(event) {
case OC_EV_MS_NEW_MEMBERSHIP:
case OC_EV_MS_INVALID:
case OC_EV_MS_PRIMARY_RESTORED:
fsa_membership_copy->id = instance;
break;
default:
break;
}
if(update_cache == FALSE) {
/* a stand-alone transition */
register_fsa_action(A_TE_CANCEL);
}
}
if(update_cache) {
crm_debug_2("Updating cache after event %s",
ccm_event_name(event));
crm_malloc0(event_data, sizeof(struct crmd_ccm_data_s));
if(event_data == NULL) { return; }
event_data->event = event;
if(data != NULL) {
event_data->oc = copy_ccm_oc_data(data);
}
register_fsa_input_adv(
C_CCM_CALLBACK, I_CCM_EVENT, event_data,
trigger_transition?A_TE_CANCEL:A_NOTHING,
TRUE, __FUNCTION__);
delete_ccm_data(event_data);
}
oc_ev_callback_done(cookie);
return;
}
void
crmd_cib_connection_destroy(gpointer user_data)
{
crm_debug_3("Invoked");
trigger_fsa(fsa_source);
if(is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) {
crm_info("Connection to the CIB terminated...");
return;
}
/* eventually this will trigger a reconnect, not a shutdown */
crm_err("Connection to the CIB terminated...");
register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL);
clear_bit_inplace(fsa_input_register, R_CIB_CONNECTED);
return;
}
longclock_t fsa_start = 0;
longclock_t fsa_stop = 0;
longclock_t fsa_diff = 0;
gboolean
crm_fsa_trigger(gpointer user_data)
{
unsigned int fsa_diff_ms = 0;
if(fsa_diff_max_ms > 0) {
fsa_start = time_longclock();
}
crm_debug_2("Invoked (queue len: %d)", g_list_length(fsa_message_queue));
s_crmd_fsa(C_FSA_INTERNAL);
crm_debug_2("Exited (queue len: %d)", g_list_length(fsa_message_queue));
if(fsa_diff_max_ms > 0) {
fsa_stop = time_longclock();
fsa_diff = sub_longclock(fsa_stop, fsa_start);
fsa_diff_ms = longclockto_ms(fsa_diff);
if(fsa_diff_ms > fsa_diff_max_ms) {
crm_err("FSA took %dms to complete", fsa_diff_ms);
} else if(fsa_diff_ms > fsa_diff_warn_ms) {
crm_warn("FSA took %dms to complete", fsa_diff_ms);
}
}
return TRUE;
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 3:12 AM (41 m, 52 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1018088
Default Alt Text
(70 KB)

Event Timeline