Page MenuHomeClusterLabs Projects

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/crm/admin/crm_resource.c b/crm/admin/crm_resource.c
index 1a22fbb82b..f53ed786e2 100644
--- a/crm/admin/crm_resource.c
+++ b/crm/admin/crm_resource.c
@@ -1,1244 +1,1240 @@
/* $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.");
- continue;
}
-
-/* result = cl_get_string(new_input->msg, XML_ATTR_RESULT); */
-/* if(result == NULL || strcasecmp(result, "ok") == 0) { */
-/* result = "pass"; */
-/* } else { */
-/* result = "fail"; */
-/* } */
-
+ delete_ha_msg_input(new_input);
}
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 *now = new_ha_date(TRUE);
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) {
- return rc;
+ 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) {
- return rc;
+ 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 f3db77e7ff..25d45812c0 100644
--- a/crm/admin/crmadmin.c
+++ b/crm/admin/crmadmin.c
@@ -1,729 +1,731 @@
/* $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.");
- continue;
-
+ 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.");
- continue;
+ 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);
}
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/ccm.c b/crm/crmd/ccm.c
index ceae076d3d..50b77d2728 100644
--- a/crm/crmd/ccm.c
+++ b/crm/crmd/ccm.c
@@ -1,675 +1,653 @@
/* $Id: ccm.c,v 1.106 2006/07/18 06:17:32 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
*/
/* put these first so that uuid_t is defined without conflicts */
#include <portability.h>
#include <ocf/oc_event.h>
#include <ocf/oc_membership.h>
#include <clplumbing/GSource.h>
#include <string.h>
#include <heartbeat.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crmd_messages.h>
#include <crmd_fsa.h>
#include <fsa_proto.h>
#include <crmd_callbacks.h>
void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int );
int register_with_ccm(ll_cluster_t *hb_cluster);
void msg_ccm_join(const HA_Message *msg, void *foo);
void crmd_ccm_msg_callback(oc_ed_t event,
void *cookie,
size_t size,
const void *data);
void ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data);
#define CCM_EVENT_DETAIL 0
#define CCM_EVENT_DETAIL_PARTIAL 0
oc_ev_t *fsa_ev_token;
int num_ccm_register_fails = 0;
int max_ccm_register_fails = 30;
/* A_CCM_CONNECT */
enum crmd_fsa_input
do_ccm_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
int ret;
int fsa_ev_fd;
gboolean did_fail = FALSE;
if(action & A_CCM_DISCONNECT){
set_bit_inplace(fsa_input_register, R_CCM_DISCONNECTED);
oc_ev_unregister(fsa_ev_token);
}
if(action & A_CCM_CONNECT) {
crm_debug_3("Registering with CCM");
clear_bit_inplace(fsa_input_register, R_CCM_DISCONNECTED);
ret = oc_ev_register(&fsa_ev_token);
if (ret != 0) {
crm_warn("CCM registration failed");
did_fail = TRUE;
}
if(did_fail == FALSE) {
crm_debug_3("Setting up CCM callbacks");
ret = oc_ev_set_callback(fsa_ev_token, OC_EV_MEMB_CLASS,
crmd_ccm_msg_callback, NULL);
if (ret != 0) {
crm_warn("CCM callback not set");
did_fail = TRUE;
}
}
if(did_fail == FALSE) {
oc_ev_special(fsa_ev_token, OC_EV_MEMB_CLASS, 0/*don't care*/);
crm_debug_3("Activating CCM token");
ret = oc_ev_activate(fsa_ev_token, &fsa_ev_fd);
if (ret != 0){
crm_warn("CCM Activation failed");
did_fail = TRUE;
}
}
if(did_fail) {
num_ccm_register_fails++;
oc_ev_unregister(fsa_ev_token);
if(num_ccm_register_fails < max_ccm_register_fails) {
crm_warn("CCM Connection failed"
" %d times (%d max)",
num_ccm_register_fails,
max_ccm_register_fails);
crm_timer_start(wait_timer);
crmd_fsa_stall(NULL);
return I_NULL;
} else {
crm_err("CCM Activation failed %d (max) times",
num_ccm_register_fails);
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
}
}
crm_info("CCM connection established..."
" waiting for first callback");
G_main_add_fd(G_PRIORITY_HIGH, fsa_ev_fd, FALSE, ccm_dispatch,
fsa_ev_token, default_ipc_connection_destroy);
}
if(action & ~(A_CCM_CONNECT|A_CCM_DISCONNECT)) {
crm_err("Unexpected action %s in %s",
fsa_action2string(action), __FUNCTION__);
}
return I_NULL;
}
extern GHashTable *voted;
/* A_CCM_EVENT */
enum crmd_fsa_input
do_ccm_event(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
enum crmd_fsa_input return_input = I_NULL;
oc_ed_t event;
const oc_ev_membership_t *oc = NULL;
struct crmd_ccm_data_s *ccm_data = fsa_typed_data(fsa_dt_ccm);
if(ccm_data == NULL) {
crm_err("No data provided to FSA function");
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
} else if(msg_data->fsa_cause != C_CCM_CALLBACK) {
crm_err("FSA function called in response to incorect input");
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
}
event = ccm_data->event;
oc = ccm_data->oc;
ccm_event_detail(oc, event);
if (OC_EV_MS_EVICTED == event) {
/* todo: drop back to S_PENDING instead */
/* get out... NOW!
*
* go via the error recovery process so that HA will
* restart us if required
*/
register_fsa_error(cause, I_ERROR, msg_data->data);
return I_NULL;
}
return return_input;
}
static void
check_dead_member(const char *uname, GHashTable *members)
{
CRM_CHECK(uname != NULL, return);
if(members != NULL && g_hash_table_lookup(members, uname) != NULL) {
crm_err("%s didnt really leave the membership!", uname);
return;
}
if(confirmed_nodes != NULL) {
g_hash_table_remove(confirmed_nodes, uname);
}
if(finalized_nodes != NULL) {
g_hash_table_remove(finalized_nodes, uname);
}
if(integrated_nodes != NULL) {
g_hash_table_remove(integrated_nodes, uname);
}
if(voted != NULL) {
g_hash_table_remove(voted, uname);
}
if(safe_str_eq(fsa_our_uname, uname)) {
crm_err("We're not part of the cluster anymore");
}
if(AM_I_DC == FALSE && safe_str_eq(uname, fsa_our_dc)) {
crm_warn("Our DC node (%s) left the cluster", uname);
register_fsa_input(C_FSA_INTERNAL, I_ELECTION, NULL);
}
}
/* A_CCM_UPDATE_CACHE */
/*
* Take the opportunity to update the node status in the CIB as well
*/
enum crmd_fsa_input
do_ccm_update_cache(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
enum crmd_fsa_input next_input = I_NULL;
unsigned int lpc;
int offset;
GHashTable *members = NULL;
oc_ed_t event;
const oc_ev_membership_t *oc = NULL;
oc_node_list_t *tmp = NULL, *membership_copy = NULL;
struct crmd_ccm_data_s *ccm_data = fsa_typed_data(fsa_dt_ccm);
HA_Message *no_op = create_request(
CRM_OP_NOOP, NULL, NULL, CRM_SYSTEM_CRMD,
AM_I_DC?CRM_SYSTEM_DC:CRM_SYSTEM_CRMD, NULL);
if(ccm_data == NULL) {
crm_err("No data provided to FSA function");
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
send_msg_via_ha(fsa_cluster_conn, no_op);
return I_NULL;
}
event = ccm_data->event;
oc = ccm_data->oc;
if(fsa_membership_copy != NULL
&& fsa_membership_copy->id >= oc->m_instance) {
crm_debug("Ignoring superceeded CCM event %d (%s).",
oc->m_instance, ccm_event_name(event));
return I_NULL;
}
crm_debug("Updating cache after CCM event %d (%s).",
oc->m_instance, ccm_event_name(event));
crm_debug_2("instance=%d, nodes=%d, new=%d, lost=%d n_idx=%d, "
"new_idx=%d, old_idx=%d",
oc->m_instance,
oc->m_n_member,
oc->m_n_in,
oc->m_n_out,
oc->m_memb_idx,
oc->m_in_idx,
oc->m_out_idx);
#define ALAN_DEBUG 1
#ifdef ALAN_DEBUG
{
/*
* Size (Size + 2) / 2
*
* 3 (3+2)/2 = 5 / 2 = 2
* 4 (4+2)/2 = 6 / 2 = 3
* 5 (5+2)/2 = 7 / 2 = 3
* 6 (6+2)/2 = 8 / 2 = 4
* 7 (7+2)/2 = 9 / 2 = 4
*/
unsigned int clsize = (oc->m_out_idx - oc->m_n_member);
unsigned int plsize = (clsize + 2)/2;
gboolean plurality = (oc->m_n_member >= plsize);
gboolean Q = ccm_have_quorum(event);
if(clsize == 2) {
if (!Q) {
crm_err("2 nodes w/o quorum");
}
} else if(Q && !plurality) {
crm_err("Quorum w/o plurality (%d/%d nodes)",
oc->m_n_member, clsize);
} else if(plurality && !Q) {
crm_err("Plurality w/o Quorum (%d/%d nodes)",
oc->m_n_member, clsize);
} else {
crm_debug_2("Quorum(%s) and plurality (%d/%d) agree.",
Q?"true":"false", oc->m_n_member, clsize);
}
}
#endif
crm_malloc0(membership_copy, sizeof(oc_node_list_t));
if(membership_copy == NULL) {
crm_crit("Couldnt create membership copy - out of memory");
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
return I_NULL;
}
membership_copy->id = oc->m_instance;
membership_copy->last_event = event;
crm_debug_3("Copying members");
/*--*-- All Member Nodes --*--*/
offset = oc->m_memb_idx;
membership_copy->members_size = oc->m_n_member;
if(membership_copy->members_size > 0) {
membership_copy->members =
g_hash_table_new(g_str_hash, g_str_equal);
members = membership_copy->members;
for(lpc=0; lpc < membership_copy->members_size; lpc++) {
oc_node_t *member = NULL;
- crm_debug_3("Copying member %d", lpc);
+ CRM_CHECK(oc->m_array[offset+lpc].node_uname != NULL,
+ continue);
+
crm_malloc0(member, sizeof(oc_node_t));
-
- if(member == NULL) {
- continue;
- }
- member->node_id =
- oc->m_array[offset+lpc].node_id;
+ member->node_id = oc->m_array[offset+lpc].node_id;
member->node_born_on =
oc->m_array[offset+lpc].node_born_on;
- member->node_uname = NULL;
- if(oc->m_array[offset+lpc].node_uname != NULL) {
- member->node_uname =
- crm_strdup(oc->m_array[offset+lpc].node_uname);
- } else {
- crm_err("Node %d had a NULL uname",
- member->node_id);
- }
+ member->node_uname =
+ crm_strdup(oc->m_array[offset+lpc].node_uname);
g_hash_table_insert(
members, member->node_uname, member);
}
} else {
membership_copy->members = NULL;
}
crm_debug_3("Copying new members");
/*--*-- New Member Nodes --*--*/
offset = oc->m_in_idx;
membership_copy->new_members_size = oc->m_n_in;
if(membership_copy->new_members_size > 0) {
membership_copy->new_members =
g_hash_table_new(g_str_hash, g_str_equal);
members = membership_copy->new_members;
for(lpc=0; lpc < membership_copy->new_members_size; lpc++) {
oc_node_t *member = NULL;
+ CRM_CHECK(oc->m_array[offset+lpc].node_uname != NULL,
+ continue);
+
crm_malloc0(member, sizeof(oc_node_t));
- if(member == NULL) {
- continue;
- }
-
- member->node_uname = NULL;
member->node_id = oc->m_array[offset+lpc].node_id;
+
member->node_born_on =
oc->m_array[offset+lpc].node_born_on;
+
+ member->node_uname =
+ crm_strdup(oc->m_array[offset+lpc].node_uname);
- if(oc->m_array[offset+lpc].node_uname != NULL) {
- member->node_uname =
- crm_strdup(oc->m_array[offset+lpc].node_uname);
- } else {
- crm_err("Node %d had a NULL uname",
- member->node_id);
- }
g_hash_table_insert(
members, member->node_uname, member);
g_hash_table_insert(members, member->node_uname, member);
}
} else {
membership_copy->new_members = NULL;
}
crm_debug_3("Copying dead members");
/*--*-- Recently Dead Member Nodes --*--*/
offset = oc->m_out_idx;
membership_copy->dead_members_size = oc->m_n_out;
if(membership_copy->dead_members_size > 0) {
membership_copy->dead_members =
g_hash_table_new(g_str_hash, g_str_equal);
members = membership_copy->dead_members;
for(lpc=0; lpc < membership_copy->dead_members_size; lpc++) {
oc_node_t *member = NULL;
+ CRM_CHECK(oc->m_array[offset+lpc].node_uname != NULL,
+ continue);
+
crm_malloc0(member, sizeof(oc_node_t));
- if(member == NULL) {
- continue;
- }
-
member->node_id = oc->m_array[offset+lpc].node_id;
member->node_born_on =
oc->m_array[offset+lpc].node_born_on;
- member->node_uname = NULL;
- CRM_DEV_ASSERT(oc->m_array[offset+lpc].node_uname != NULL);
-
- if(oc->m_array[offset+lpc].node_uname == NULL) {
- continue;
- }
-
member->node_uname =
crm_strdup(oc->m_array[offset+lpc].node_uname);
g_hash_table_insert(members, member->node_uname, member);
check_dead_member(
member->node_uname, membership_copy->members);
}
} else {
membership_copy->dead_members = NULL;
}
tmp = fsa_membership_copy;
fsa_membership_copy = membership_copy;
crm_debug_2("Updated membership cache with %d (%d new, %d lost) members",
g_hash_table_size(fsa_membership_copy->members),
g_hash_table_size(fsa_membership_copy->new_members),
g_hash_table_size(fsa_membership_copy->dead_members));
free_ccm_cache(tmp);
set_bit_inplace(fsa_input_register, R_CCM_DATA);
if(cur_state != S_STOPPING) {
crm_debug_3("Updating the CIB from CCM cache");
do_update_cib_nodes(FALSE, __FUNCTION__);
}
/* Membership changed, remind everyone we're here.
* This will aid detection of duplicate DCs
*/
send_msg_via_ha(fsa_cluster_conn, no_op);
return next_input;
}
void
ccm_event_detail(const oc_ev_membership_t *oc, oc_ed_t event)
{
int lpc;
gboolean member = FALSE;
member = FALSE;
crm_debug_2("-----------------------");
crm_info("%s: trans=%d, nodes=%d, new=%d, lost=%d n_idx=%d, "
"new_idx=%d, old_idx=%d",
ccm_event_name(event),
oc->m_instance,
oc->m_n_member,
oc->m_n_in,
oc->m_n_out,
oc->m_memb_idx,
oc->m_in_idx,
oc->m_out_idx);
#if !CCM_EVENT_DETAIL_PARTIAL
for(lpc=0; lpc < oc->m_n_member; lpc++) {
crm_info("\tCURRENT: %s [nodeid=%d, born=%d]",
oc->m_array[oc->m_memb_idx+lpc].node_uname,
oc->m_array[oc->m_memb_idx+lpc].node_id,
oc->m_array[oc->m_memb_idx+lpc].node_born_on);
if(safe_str_eq(fsa_our_uname,
oc->m_array[oc->m_memb_idx+lpc].node_uname)) {
member = TRUE;
}
}
if (member == FALSE) {
crm_warn("MY NODE IS NOT IN CCM THE MEMBERSHIP LIST");
}
#endif
for(lpc=0; lpc<(int)oc->m_n_in; lpc++) {
crm_info("\tNEW: %s [nodeid=%d, born=%d]",
oc->m_array[oc->m_in_idx+lpc].node_uname,
oc->m_array[oc->m_in_idx+lpc].node_id,
oc->m_array[oc->m_in_idx+lpc].node_born_on);
}
for(lpc=0; lpc<(int)oc->m_n_out; lpc++) {
crm_info("\tLOST: %s [nodeid=%d, born=%d]",
oc->m_array[oc->m_out_idx+lpc].node_uname,
oc->m_array[oc->m_out_idx+lpc].node_id,
oc->m_array[oc->m_out_idx+lpc].node_born_on);
}
crm_debug_2("-----------------------");
}
int
register_with_ccm(ll_cluster_t *hb_cluster)
{
return 0;
}
void
msg_ccm_join(const HA_Message *msg, void *foo)
{
crm_debug_2("###### Received ccm_join message...");
if (msg != NULL)
{
crm_debug_2("[type=%s]",
ha_msg_value(msg, F_TYPE));
crm_debug_2("[orig=%s]",
ha_msg_value(msg, F_ORIG));
crm_debug_2("[to=%s]",
ha_msg_value(msg, F_TO));
crm_debug_2("[status=%s]",
ha_msg_value(msg, F_STATUS));
crm_debug_2("[info=%s]",
ha_msg_value(msg, F_COMMENT));
crm_debug_2("[rsc_hold=%s]",
ha_msg_value(msg, F_RESOURCES));
crm_debug_2("[stable=%s]",
ha_msg_value(msg, F_ISSTABLE));
crm_debug_2("[rtype=%s]",
ha_msg_value(msg, F_RTYPE));
crm_debug_2("[ts=%s]",
ha_msg_value(msg, F_TIME));
crm_debug_2("[seq=%s]",
ha_msg_value(msg, F_SEQ));
crm_debug_2("[generation=%s]",
ha_msg_value(msg, F_HBGENERATION));
/* crm_debug_2("[=%s]", ha_msg_value(msg, F_)); */
}
return;
}
struct update_data_s
{
const char *state;
const char *caller;
crm_data_t *updates;
gboolean overwrite_join;
};
static void
ccm_node_update_complete(const HA_Message *msg, int call_id, int rc,
crm_data_t *output, void *user_data)
{
fsa_data_t *msg_data = NULL;
if(rc == cib_ok) {
crm_debug("Node update %d complete", call_id);
} else {
crm_err("Node update %d failed", call_id);
crm_log_message(LOG_DEBUG, msg);
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
}
}
void
do_update_cib_nodes(gboolean overwrite, const char *caller)
{
int call_id = 0;
int call_options = cib_scope_local|cib_quorum_override;
struct update_data_s update_data;
crm_data_t *fragment = NULL;
if(fsa_membership_copy == NULL) {
/* We got a replace notification before being connected to
* the CCM.
* So there is no need to update the local CIB with our values
* - since we have none.
*/
return;
}
fragment = create_xml_node(NULL, XML_CIB_TAG_STATUS);
update_data.caller = caller;
update_data.updates = fragment;
update_data.overwrite_join = overwrite;
if(overwrite == FALSE) {
call_options = call_options|cib_inhibit_bcast;
crm_debug_2("Inhibiting bcast for membership updates");
}
/* dead nodes */
update_data.state = XML_BOOLEAN_NO;
if(fsa_membership_copy->dead_members != NULL) {
g_hash_table_foreach(fsa_membership_copy->dead_members,
ghash_update_cib_node, &update_data);
}
/* live nodes */
update_data.state = XML_BOOLEAN_YES;
if(fsa_membership_copy->members != NULL) {
g_hash_table_foreach(fsa_membership_copy->members,
ghash_update_cib_node, &update_data);
}
fsa_cib_update(XML_CIB_TAG_STATUS, fragment, call_options, call_id);
add_cib_op_callback(call_id, FALSE, NULL, ccm_node_update_complete);
free_xml(fragment);
}
void
ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data)
{
crm_data_t *tmp1 = NULL;
const char *join = NULL;
const char *peer_online = NULL;
const char *node_uname = (const char*)key;
struct update_data_s* data = (struct update_data_s*)user_data;
crm_debug_2("Updating %s: %s (overwrite=%s)",
node_uname, data->state,
data->overwrite_join?"true":"false");
peer_online = g_hash_table_lookup(crmd_peer_state, node_uname);
if(data->overwrite_join) {
if(safe_str_neq(peer_online, ONLINESTATUS)) {
join = CRMD_JOINSTATE_DOWN;
} else {
const char *peer_member = g_hash_table_lookup(
confirmed_nodes, node_uname);
if(peer_member != NULL) {
join = CRMD_JOINSTATE_MEMBER;
} else {
join = CRMD_JOINSTATE_PENDING;
}
}
}
tmp1 = create_node_state(node_uname, NULL, data->state, peer_online,
join, NULL, FALSE, data->caller);
add_node_copy(data->updates, tmp1);
free_xml(tmp1);
}
diff --git a/crm/crmd/messages.c b/crm/crmd/messages.c
index b14b084179..c27b9f768c 100644
--- a/crm/crmd/messages.c
+++ b/crm/crmd/messages.c
@@ -1,1217 +1,1218 @@
/*
* 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 <time.h>
#include <crmd_fsa.h>
#include <hb_api.h>
#include <lrm/lrm_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_lrm.h>
GListPtr fsa_message_queue = NULL;
extern void crm_shutdown(int nsig);
enum crmd_fsa_input handle_request(ha_msg_input_t *stored_msg);
enum crmd_fsa_input handle_response(ha_msg_input_t *stored_msg);
enum crmd_fsa_input handle_shutdown_request(HA_Message *stored_msg);
ha_msg_input_t *copy_ha_msg_input(ha_msg_input_t *orig);
gboolean ipc_queue_helper(gpointer key, gpointer value, gpointer user_data);
#ifdef MSG_LOG
# define ROUTER_RESULT(x) crm_debug_3("Router result: %s", x); \
crm_log_message_adv(LOG_MSG, "router.log", relay_message);
#else
# define ROUTER_RESULT(x) crm_debug_3("Router result: %s", x)
#endif
/* debug only, can wrap all it likes */
int last_data_id = 0;
void
register_fsa_error_adv(
enum crmd_fsa_cause cause, enum crmd_fsa_input input,
fsa_data_t *cur_data, void *new_data, const char *raised_from)
{
/* save the current actions if any */
if(fsa_actions != A_NOTHING) {
register_fsa_input_adv(
cur_data?cur_data->fsa_cause:C_FSA_INTERNAL,
I_NULL, cur_data?cur_data->data:NULL,
fsa_actions, TRUE, __FUNCTION__);
}
/* reset the action list */
fsa_actions = A_NOTHING;
/* register the error */
register_fsa_input_adv(
cause, input, new_data, A_NOTHING, TRUE, raised_from);
}
static gboolean last_was_vote = FALSE;
int
register_fsa_input_adv(
enum crmd_fsa_cause cause, enum crmd_fsa_input input,
void *data, long long with_actions,
gboolean prepend, const char *raised_from)
{
unsigned old_len = g_list_length(fsa_message_queue);
fsa_data_t *fsa_data = NULL;
last_data_id++;
crm_debug_2("%s raised FSA input %d (%s) (cause=%s) %s data",
raised_from, last_data_id, fsa_input2string(input),
fsa_cause2string(cause), data?"with":"without");
if(input == I_WAIT_FOR_EVENT) {
do_fsa_stall = TRUE;
crm_debug("Stalling the FSA pending further input: cause=%s",
fsa_cause2string(cause));
if(old_len > 0) {
crm_warn("%s stalled the FSA with pending inputs",
raised_from);
fsa_dump_queue(LOG_DEBUG);
}
if(data == NULL) {
set_bit_inplace(fsa_actions, with_actions);
with_actions = A_NOTHING;
return 0;
}
crm_err("%s stalled the FSA with data - this may be broken",
raised_from);
}
if(old_len == 0) {
last_was_vote = FALSE;
}
if(input == I_NULL && with_actions == A_NOTHING /* && data == NULL */){
/* no point doing anything */
crm_err("Cannot add entry to queue: no input and no action");
return 0;
} else if(data == NULL) {
last_was_vote = FALSE;
#if 0
} else if(last_was_vote && cause == C_HA_MESSAGE && input == I_ROUTER) {
const char *op = cl_get_string(
((ha_msg_input_t*)data)->msg, F_CRM_TASK);
if(safe_str_eq(op, CRM_OP_VOTE)) {
/* It is always safe to treat N successive votes as
* a single one
*
* If all the discarded votes are more "loosing" than
* the first then the result is accurate
* (win or loose).
*
* If any of the discarded votes are less "loosing"
* than the first then we will cast our vote and the
* eventual winner will vote us down again (which
* even in the case that N=2, is no worse than if we
* had not disarded the vote).
*/
crm_debug_2("Vote compression: %d", old_len);
return 0;
}
#endif
} else if (cause == C_HA_MESSAGE && input == I_ROUTER) {
const char *op = cl_get_string(
((ha_msg_input_t*)data)->msg, F_CRM_TASK);
if(safe_str_eq(op, CRM_OP_VOTE)) {
last_was_vote = TRUE;
crm_debug_3("Added vote: %d", old_len);
}
} else {
last_was_vote = FALSE;
}
crm_malloc0(fsa_data, sizeof(fsa_data_t));
fsa_data->id = last_data_id;
fsa_data->fsa_input = input;
fsa_data->fsa_cause = cause;
fsa_data->origin = raised_from;
fsa_data->data = NULL;
fsa_data->data_type = fsa_dt_none;
fsa_data->actions = with_actions;
if(with_actions != A_NOTHING) {
crm_debug_3("Adding actions %.16llx to input", with_actions);
}
if(data != NULL) {
switch(cause) {
case C_FSA_INTERNAL:
case C_CRMD_STATUS_CALLBACK:
case C_IPC_MESSAGE:
case C_HA_MESSAGE:
crm_debug_3("Copying %s data from %s as a HA msg",
fsa_cause2string(cause),
raised_from);
fsa_data->data = copy_ha_msg_input(data);
fsa_data->data_type = fsa_dt_ha_msg;
break;
case C_LRM_OP_CALLBACK:
crm_debug_3("Copying %s data from %s as lrm_op_t",
fsa_cause2string(cause),
raised_from);
fsa_data->data = copy_lrm_op((lrm_op_t*)data);
fsa_data->data_type = fsa_dt_lrm;
break;
case C_CCM_CALLBACK:
crm_debug_3("Copying %s data from %s as CCM data",
fsa_cause2string(cause),
raised_from);
fsa_data->data = copy_ccm_data(data);
fsa_data->data_type = fsa_dt_ccm;
break;
case C_SUBSYSTEM_CONNECT:
case C_LRM_MONITOR_CALLBACK:
case C_TIMER_POPPED:
case C_SHUTDOWN:
case C_HEARTBEAT_FAILED:
case C_HA_DISCONNECT:
case C_ILLEGAL:
case C_UNKNOWN:
case C_STARTUP:
crm_err("Copying %s data (from %s)"
" not yet implemented",
fsa_cause2string(cause), raised_from);
exit(1);
break;
}
crm_debug_4("%s data copied",
fsa_cause2string(fsa_data->fsa_cause));
}
/* make sure to free it properly later */
if(prepend) {
crm_debug_2("Prepending input");
fsa_message_queue = g_list_prepend(fsa_message_queue, fsa_data);
} else {
fsa_message_queue = g_list_append(fsa_message_queue, fsa_data);
}
crm_debug_2("Queue len: %d", g_list_length(fsa_message_queue));
fsa_dump_queue(LOG_DEBUG_2);
if(old_len == g_list_length(fsa_message_queue)){
crm_err("Couldnt add message to the queue");
}
if(fsa_source) {
crm_debug_3("Triggering FSA: %s", __FUNCTION__);
G_main_set_trigger(fsa_source);
}
return last_data_id;
}
void
fsa_dump_queue(int log_level)
{
if(log_level < (int)crm_log_level) {
return;
}
slist_iter(
data, fsa_data_t, fsa_message_queue, lpc,
do_crm_log(log_level,
"queue[%d(%d)]: input %s raised by %s()\t(cause=%s)",
lpc, data->id, fsa_input2string(data->fsa_input),
data->origin, fsa_cause2string(data->fsa_cause));
);
}
ha_msg_input_t *
copy_ha_msg_input(ha_msg_input_t *orig)
{
ha_msg_input_t *input_copy = NULL;
crm_malloc0(input_copy, sizeof(ha_msg_input_t));
if(orig != NULL) {
crm_debug_4("Copy msg");
input_copy->msg = ha_msg_copy(orig->msg);
if(orig->xml != NULL) {
crm_debug_4("Copy xml");
input_copy->xml = copy_xml(orig->xml);
}
} else {
crm_debug_3("No message to copy");
}
return input_copy;
}
void
delete_fsa_input(fsa_data_t *fsa_data)
{
lrm_op_t *op = NULL;
crm_data_t *foo = NULL;
struct crmd_ccm_data_s *ccm_input = NULL;
if(fsa_data == NULL) {
return;
}
crm_debug_4("About to free %s data",
fsa_cause2string(fsa_data->fsa_cause));
if(fsa_data->data != NULL) {
switch(fsa_data->data_type) {
case fsa_dt_ha_msg:
delete_ha_msg_input(fsa_data->data);
break;
case fsa_dt_xml:
foo = fsa_data->data;
free_xml(foo);
break;
case fsa_dt_lrm:
op = (lrm_op_t*)fsa_data->data;
free_lrm_op(op);
break;
case fsa_dt_ccm:
ccm_input = (struct crmd_ccm_data_s *)
fsa_data->data;
delete_ccm_data(ccm_input);
break;
case fsa_dt_none:
if(fsa_data->data != NULL) {
crm_err("Dont know how to free %s data from %s",
fsa_cause2string(fsa_data->fsa_cause),
fsa_data->origin);
exit(1);
}
break;
}
crm_debug_4("%s data freed",
fsa_cause2string(fsa_data->fsa_cause));
}
crm_free(fsa_data);
}
/* returns the next message */
fsa_data_t *
get_message(void)
{
fsa_data_t* message = g_list_nth_data(fsa_message_queue, 0);
fsa_message_queue = g_list_remove(fsa_message_queue, message);
crm_debug_2("Processing input %d", message->id);
return message;
}
/* returns the current head of the FIFO queue */
gboolean
is_message(void)
{
return (g_list_length(fsa_message_queue) > 0);
}
void *
fsa_typed_data_adv(
fsa_data_t *fsa_data, enum fsa_data_type a_type, const char *caller)
{
void *ret_val = NULL;
if(fsa_data == NULL) {
do_crm_log(LOG_ERR, "%s: No FSA data available", caller);
} else if(fsa_data->data == NULL) {
do_crm_log(LOG_ERR, "%s: No message data available", caller);
} else if(fsa_data->data_type != a_type) {
do_crm_log(LOG_CRIT,
"%s: Message data was the wrong type! %d vs. requested=%d."
" Origin: %s", caller,
fsa_data->data_type, a_type, fsa_data->origin);
CRM_ASSERT(fsa_data->data_type == a_type);
} else {
ret_val = fsa_data->data;
}
return ret_val;
}
/* A_MSG_ROUTE */
enum crmd_fsa_input
do_msg_route(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg);
route_message(msg_data->fsa_cause, input);
return I_NULL;
}
void
route_message(enum crmd_fsa_cause cause, ha_msg_input_t *input)
{
enum crmd_fsa_input result = I_NULL;
CRM_CHECK(cause == C_IPC_MESSAGE || cause == C_HA_MESSAGE, return);
/* try passing the buck first */
crm_debug_4("Attempting to route message");
if(relay_message(input->msg, cause==C_IPC_MESSAGE)) {
crm_debug_4("Message routed...");
input->msg = NULL;
return;
}
crm_debug_4("Message wasn't routed... try handling locally");
/* calculate defer */
result = handle_message(input);
switch(result) {
case I_NULL:
crm_debug_4("Message processed");
break;
case I_CIB_OP:
break;
case I_ROUTER:
break;
default:
crm_debug_4("Defering local processing of message");
register_fsa_input_later(cause, result, input);
result = I_NULL;
break;
}
if(result != I_NULL) {
/* add to the front of the queue */
register_fsa_input(cause, result, input);
}
}
/*
* This method frees msg
*/
gboolean
send_request(HA_Message *msg, char **msg_reference)
{
gboolean was_sent = FALSE;
/* crm_log_xml_debug_3(request, "Final request..."); */
if(msg_reference != NULL) {
*msg_reference = crm_strdup(
cl_get_string(msg, XML_ATTR_REFERENCE));
}
was_sent = relay_message(msg, TRUE);
if(was_sent == FALSE) {
ha_msg_input_t *fsa_input = new_ha_msg_input(msg);
register_fsa_input(C_IPC_MESSAGE, I_ROUTER, fsa_input);
delete_ha_msg_input(fsa_input);
crm_msg_del(msg);
}
return was_sent;
}
/* unless more processing is required, relay_message is freed */
gboolean
relay_message(HA_Message *relay_message, gboolean originated_locally)
{
int is_for_dc = 0;
int is_for_dcib = 0;
int is_for_te = 0;
int is_for_crm = 0;
int is_for_cib = 0;
int is_local = 0;
gboolean processing_complete = FALSE;
const char *host_to = cl_get_string(relay_message, F_CRM_HOST_TO);
const char *sys_to = cl_get_string(relay_message, F_CRM_SYS_TO);
const char *sys_from= cl_get_string(relay_message, F_CRM_SYS_FROM);
const char *type = cl_get_string(relay_message, F_TYPE);
const char *msg_error = NULL;
crm_debug_3("Routing message %s",
cl_get_string(relay_message, XML_ATTR_REFERENCE));
if(relay_message == NULL) {
msg_error = "Cannot route empty message";
} else if(safe_str_eq(CRM_OP_HELLO,
cl_get_string(relay_message, F_CRM_TASK))){
/* quietly ignore */
processing_complete = TRUE;
} else if(safe_str_neq(type, T_CRM)) {
msg_error = "Bad message type";
} else if(sys_to == NULL) {
msg_error = "Bad message destination: no subsystem";
}
if(msg_error != NULL) {
processing_complete = TRUE;
crm_err("%s", msg_error);
crm_log_message(LOG_WARNING, relay_message);
}
if(processing_complete) {
crm_msg_del(relay_message);
return TRUE;
}
processing_complete = TRUE;
is_for_dc = (strcasecmp(CRM_SYSTEM_DC, sys_to) == 0);
is_for_dcib = (strcasecmp(CRM_SYSTEM_DCIB, sys_to) == 0);
is_for_te = (strcasecmp(CRM_SYSTEM_TENGINE, sys_to) == 0);
is_for_cib = (strcasecmp(CRM_SYSTEM_CIB, sys_to) == 0);
is_for_crm = (strcasecmp(CRM_SYSTEM_CRMD, sys_to) == 0);
is_local = 0;
if(host_to == NULL || strlen(host_to) == 0) {
if(is_for_dc || is_for_te) {
is_local = 0;
} else if(is_for_crm && originated_locally) {
is_local = 0;
} else {
is_local = 1;
}
} else if(strcasecmp(fsa_our_uname, host_to) == 0) {
is_local=1;
}
if(is_for_dc || is_for_dcib || is_for_te) {
if(AM_I_DC && is_for_te) {
ROUTER_RESULT("Message result: Local relay");
send_msg_via_ipc(relay_message, sys_to);
} else if(AM_I_DC) {
ROUTER_RESULT("Message result: DC/CRMd process");
processing_complete = FALSE; /* more to be done by caller */
} else if(originated_locally
&& safe_str_neq(sys_from, CRM_SYSTEM_PENGINE)
&& safe_str_neq(sys_from, CRM_SYSTEM_TENGINE)) {
/* Neither the TE or PE should be sending messages
* to DC's on other nodes
*
* By definition, if we are no longer the DC, then
* the PE or TE's data should be discarded
*/
ROUTER_RESULT("Message result: External relay to DC");
send_msg_via_ha(fsa_cluster_conn, relay_message);
} else {
/* discard */
ROUTER_RESULT("Message result: Discard, not DC");
crm_msg_del(relay_message);
}
} else if(is_local && (is_for_crm || is_for_cib)) {
ROUTER_RESULT("Message result: CRMd process");
processing_complete = FALSE; /* more to be done by caller */
} else if(is_local) {
ROUTER_RESULT("Message result: Local relay");
send_msg_via_ipc(relay_message, sys_to);
} else {
ROUTER_RESULT("Message result: External relay");
send_msg_via_ha(fsa_cluster_conn, relay_message);
}
return processing_complete;
}
gboolean
crmd_authorize_message(ha_msg_input_t *client_msg, crmd_client_t *curr_client)
{
/* check the best case first */
const char *sys_from = cl_get_string(client_msg->msg, F_CRM_SYS_FROM);
char *uuid = NULL;
char *client_name = NULL;
char *major_version = NULL;
char *minor_version = NULL;
const char *filtered_from;
gpointer table_key = NULL;
gboolean auth_result = FALSE;
struct crm_subsystem_s *the_subsystem = NULL;
gboolean can_reply = FALSE; /* no-one has registered with this id */
const char *op = cl_get_string(client_msg->msg, F_CRM_TASK);
if (safe_str_neq(CRM_OP_HELLO, op)) {
if(sys_from == NULL) {
crm_warn("Message [%s] was had no value for %s... discarding",
cl_get_string(client_msg->msg, XML_ATTR_REFERENCE),
F_CRM_SYS_FROM);
return FALSE;
}
filtered_from = sys_from;
/* The CIB can have two names on the DC */
if(strcasecmp(sys_from, CRM_SYSTEM_DCIB) == 0)
filtered_from = CRM_SYSTEM_CIB;
if (g_hash_table_lookup (ipc_clients, filtered_from) != NULL) {
can_reply = TRUE; /* reply can be routed */
}
crm_debug_2("Message reply can%s be routed from %s.",
can_reply?"":" not", sys_from);
if(can_reply == FALSE) {
crm_warn("Message [%s] not authorized",
cl_get_string(client_msg->msg, XML_ATTR_REFERENCE));
}
return can_reply;
}
crm_debug_3("received client join msg");
crm_log_message(LOG_MSG, client_msg->msg);
auth_result = process_hello_message(
client_msg->xml, &uuid, &client_name,
&major_version, &minor_version);
if (auth_result == TRUE) {
if(client_name == NULL || uuid == NULL) {
crm_err("Bad client details (client_name=%s, uuid=%s)",
crm_str(client_name), crm_str(uuid));
auth_result = FALSE;
}
}
if (auth_result == TRUE) {
/* check version */
int mav = atoi(major_version);
int miv = atoi(minor_version);
crm_debug_3("Checking client version number");
if (mav < 0 || miv < 0) {
crm_err("Client version (%d:%d) is not acceptable",
mav, miv);
auth_result = FALSE;
}
crm_free(major_version);
crm_free(minor_version);
}
if (strcasecmp(CRM_SYSTEM_PENGINE, client_name) == 0) {
the_subsystem = pe_subsystem;
} else if (strcasecmp(CRM_SYSTEM_TENGINE, client_name) == 0) {
the_subsystem = te_subsystem;
}
if (auth_result == TRUE && the_subsystem != NULL) {
/* if we already have one of those clients
* only applies to te, pe etc. not admin clients
*/
crm_debug_3("Checking if %s is required/already connected",
client_name);
table_key = (gpointer)crm_strdup(client_name);
if(is_set(fsa_input_register, the_subsystem->flag_connected)) {
auth_result = FALSE;
crm_free(table_key);
table_key = NULL;
crm_warn("Bit\t%.16llx set in %.16llx",
the_subsystem->flag_connected,
fsa_input_register);
crm_err("Client %s is already connected",
client_name);
} else if(FALSE == is_set(fsa_input_register,
the_subsystem->flag_required)) {
crm_warn("Bit\t%.16llx not set in %.16llx",
the_subsystem->flag_connected,
fsa_input_register);
crm_warn("Client %s joined but we dont need it",
client_name);
stop_subsystem(the_subsystem, TRUE);
} else {
the_subsystem->ipc = curr_client->client_channel;
set_bit_inplace(fsa_input_register,
the_subsystem->flag_connected);
}
} else {
table_key = (gpointer)generate_hash_key(client_name, uuid);
}
if (auth_result == TRUE) {
crm_debug_2("Accepted client %s", crm_str(table_key));
curr_client->table_key = table_key;
curr_client->sub_sys = crm_strdup(client_name);
curr_client->uuid = crm_strdup(uuid);
g_hash_table_insert (ipc_clients,
table_key, curr_client->client_channel);
send_hello_message(curr_client->client_channel,
"n/a", CRM_SYSTEM_CRMD,
"0", "1");
crm_debug_3("Updated client list with %s", crm_str(table_key));
crm_debug_3("Triggering FSA: %s", __FUNCTION__);
G_main_set_trigger(fsa_source);
if(the_subsystem != NULL) {
CRM_CHECK(the_subsystem->client == NULL,
process_client_disconnect(the_subsystem->client));
the_subsystem->client = curr_client;
}
} else {
+ crm_free(table_key);
crm_warn("Rejected client logon request");
curr_client->client_channel->ch_status = IPC_DISC_PENDING;
}
if(uuid != NULL) crm_free(uuid);
if(minor_version != NULL) crm_free(minor_version);
if(major_version != NULL) crm_free(major_version);
if(client_name != NULL) crm_free(client_name);
/* hello messages should never be processed further */
return FALSE;
}
enum crmd_fsa_input
handle_message(ha_msg_input_t *stored_msg)
{
enum crmd_fsa_input next_input = I_NULL;
const char *type = NULL;
if(stored_msg == NULL || stored_msg->msg == NULL) {
crm_err("No message to handle");
return I_NULL;
}
type = cl_get_string(stored_msg->msg, F_CRM_MSG_TYPE);
if(safe_str_eq(type, XML_ATTR_REQUEST)) {
next_input = handle_request(stored_msg);
} else if(safe_str_eq(type, XML_ATTR_RESPONSE)) {
next_input = handle_response(stored_msg);
} else {
crm_err("Unknown message type: %s", type);
}
/* crm_debug_2("%s: Next input is %s", __FUNCTION__, */
/* fsa_input2string(next_input)); */
return next_input;
}
#define schedule_pe() \
{ \
next_input = I_PE_CALC; \
if(fsa_pe_ref) { \
crm_debug("Cancelling %s...", fsa_pe_ref); \
crm_free(fsa_pe_ref); \
fsa_pe_ref = NULL; \
} \
}
enum crmd_fsa_input
handle_request(ha_msg_input_t *stored_msg)
{
HA_Message *msg = NULL;
enum crmd_fsa_input next_input = I_NULL;
const char *op = cl_get_string(stored_msg->msg, F_CRM_TASK);
const char *sys_to = cl_get_string(stored_msg->msg, F_CRM_SYS_TO);
const char *host_from = cl_get_string(stored_msg->msg, F_CRM_HOST_FROM);
crm_debug_2("Received %s "XML_ATTR_REQUEST" from %s in state %s",
op, host_from, fsa_state2string(fsa_state));
if(op == NULL) {
crm_err("Bad message");
crm_log_message(LOG_ERR, stored_msg->msg);
/*========== common actions ==========*/
} else if(strcasecmp(op, CRM_OP_NOOP) == 0) {
crm_debug_2("no-op from %s", crm_str(host_from));
} else if(strcasecmp(op, CRM_OP_NOVOTE) == 0) {
register_fsa_input_adv(C_HA_MESSAGE, I_NULL, stored_msg,
A_ELECTION_COUNT|A_ELECTION_CHECK, FALSE, __FUNCTION__);
} else if(strcasecmp(op, CRM_OP_VOTE) == 0) {
/* count the vote and decide what to do after that */
register_fsa_input_adv(C_HA_MESSAGE, I_NULL, stored_msg,
A_ELECTION_COUNT|A_ELECTION_CHECK, FALSE, __FUNCTION__);
/* Sometimes we _must_ go into S_ELECTION */
if(fsa_state == S_HALT) {
crm_debug("Forcing an election from S_HALT");
next_input = I_ELECTION;
#if 0
} else if(AM_I_DC) {
/* This is the old way of doing things but what is gained? */
next_input = I_ELECTION;
#endif
}
} else if(strcasecmp(op, CRM_OP_LOCAL_SHUTDOWN) == 0) {
crm_shutdown(SIGTERM);
/*next_input = I_SHUTDOWN; */
next_input = I_NULL;
} else if(strcasecmp(op, CRM_OP_PING) == 0) {
/* eventually do some stuff to figure out
* if we /are/ ok
*/
crm_data_t *ping = createPingAnswerFragment(sys_to, "ok");
crm_xml_add(ping, "crmd_state", fsa_state2string(fsa_state));
crm_info("Current ping state: %s", fsa_state2string(fsa_state));
msg = create_reply(stored_msg->msg, ping);
free_xml(ping);
if(relay_message(msg, TRUE) == FALSE) {
crm_msg_del(msg);
}
/* probably better to do this via signals on the
* local node
*/
} else if(strcasecmp(op, CRM_OP_DEBUG_UP) == 0) {
alter_debug(DEBUG_INC);
crm_info("Debug set to %d", get_crm_log_level());
} else if(strcasecmp(op, CRM_OP_DEBUG_DOWN) == 0) {
alter_debug(DEBUG_DEC);
crm_info("Debug set to %d", get_crm_log_level());
} else if(strcasecmp(op, CRM_OP_JOIN_OFFER) == 0) {
next_input = I_JOIN_OFFER;
crm_debug("Raising I_JOIN_OFFER: join-%s",
cl_get_string(stored_msg->msg, F_CRM_JOIN_ID));
} else if(strcasecmp(op, CRM_OP_JOIN_ACKNAK) == 0) {
next_input = I_JOIN_RESULT;
crm_debug("Raising I_JOIN_RESULT: join-%s",
cl_get_string(stored_msg->msg, F_CRM_JOIN_ID));
} else if(strcasecmp(op, CRM_OP_LRM_DELETE) == 0
|| strcasecmp(op, CRM_OP_LRM_REFRESH) == 0
|| strcasecmp(op, CRM_OP_REPROBE) == 0) {
cl_msg_modstring(stored_msg->msg, F_CRM_SYS_TO, CRM_SYSTEM_LRMD);
next_input = I_ROUTER;
/* this functionality should only be enabled
* if this is a development build
*/
} else if(CRM_DEV_BUILD && strcasecmp(op, CRM_OP_DIE) == 0/*constant condition*/) {
crm_warn("Test-only code: Killing the CRM without mercy");
crm_warn("Inhibiting respawns");
exit(100);
/*========== (NOT_DC)-Only Actions ==========*/
} else if(AM_I_DC == FALSE){
gboolean dc_match = safe_str_eq(host_from, fsa_our_dc);
if(dc_match || fsa_our_dc == NULL) {
if(strcasecmp(op, CRM_OP_HBEAT) == 0) {
crm_debug_3("Received DC heartbeat from %s",
host_from);
next_input = I_DC_HEARTBEAT;
} else if(fsa_our_dc == NULL) {
crm_warn("CRMd discarding request: %s"
" (DC: %s, from: %s)",
op, crm_str(fsa_our_dc), host_from);
crm_warn("Ignored Request");
crm_log_message(LOG_WARNING, stored_msg->msg);
} else if(strcasecmp(op, CRM_OP_SHUTDOWN) == 0) {
next_input = I_STOP;
} else {
crm_err("CRMd didnt expect request: %s", op);
crm_log_message(LOG_ERR, stored_msg->msg);
}
} else {
crm_warn("Discarding %s op from %s", op, host_from);
}
/*========== DC-Only Actions ==========*/
} else if(AM_I_DC) {
const char *message = ha_msg_value(stored_msg->msg, "message");
/* setting "fsa_pe_ref = NULL" makes sure we ignore any
* PE reply that might be pending or in the queue while
* we ask the CIB for a more up-to-date copy
*/
if(safe_str_eq(op, CRM_OP_TEABORT)) {
crm_debug("Transition cancelled: %s/%s", op, message);
clear_bit_inplace(fsa_input_register, R_IN_TRANSITION);
if(need_transition(fsa_state)) {
schedule_pe();
} else {
crm_debug("Filtering %s op in state %s",
op, fsa_state2string(fsa_state));
}
} else if(strcasecmp(op, CRM_OP_TECOMPLETE) == 0) {
crm_debug("Transition complete: %s/%s", op, message);
clear_bit_inplace(fsa_input_register, R_IN_TRANSITION);
if(fsa_state == S_TRANSITION_ENGINE) {
next_input = I_TE_SUCCESS;
} else {
crm_debug("Filtering %s op in state %s",
op, fsa_state2string(fsa_state));
}
} else if(strcasecmp(op, CRM_OP_JOIN_ANNOUNCE) == 0) {
next_input = I_NODE_JOIN;
} else if(strcasecmp(op, CRM_OP_JOIN_REQUEST) == 0) {
next_input = I_JOIN_REQUEST;
} else if(strcasecmp(op, CRM_OP_JOIN_CONFIRM) == 0) {
next_input = I_JOIN_RESULT;
} else if(strcasecmp(op, CRM_OP_SHUTDOWN) == 0) {
gboolean dc_match = safe_str_eq(host_from, fsa_our_dc);
if(dc_match) {
crm_err("We didnt ask to be shut down yet our"
" TE is telling us too."
" Better get out now!");
next_input = I_TERMINATE;
} else if(is_set(fsa_input_register, R_SHUTDOWN)) {
crm_info("Shutting ourselves down (DC)");
next_input = I_STOP;
} else if(fsa_state != S_STOPPING) {
crm_err("Another node is asking us to shutdown"
" but we think we're ok.");
next_input = I_ELECTION;
}
} else if(strcasecmp(op, CRM_OP_SHUTDOWN_REQ) == 0) {
/* a slave wants to shut down */
/* create cib fragment and add to message */
next_input = handle_shutdown_request(stored_msg->msg);
} else {
crm_err("Unexpected request (%s) sent to the DC", op);
crm_log_message(LOG_ERR, stored_msg->msg);
}
}
return next_input;
}
enum crmd_fsa_input
handle_response(ha_msg_input_t *stored_msg)
{
enum crmd_fsa_input next_input = I_NULL;
const char *op = cl_get_string(stored_msg->msg, F_CRM_TASK);
const char *sys_from = cl_get_string(stored_msg->msg, F_CRM_SYS_FROM);
const char *host_from = cl_get_string(stored_msg->msg, F_CRM_HOST_FROM);
const char *msg_ref = cl_get_string(stored_msg->msg, XML_ATTR_REFERENCE);
crm_debug_2("Received %s "XML_ATTR_RESPONSE" from %s in state %s",
op, host_from, fsa_state2string(fsa_state));
if(op == NULL) {
crm_err("Bad message");
crm_log_message(LOG_ERR, stored_msg->msg);
} else if(AM_I_DC && strcasecmp(op, CRM_OP_PECALC) == 0) {
crm_debug_2("Processing %s reply %s (fsa=%s)",
sys_from, msg_ref, crm_str(fsa_pe_ref));
if(msg_ref != NULL && safe_str_eq(msg_ref, fsa_pe_ref)) {
next_input = I_PE_SUCCESS;
crm_debug_2("Completed: %s...", fsa_pe_ref);
crm_free(fsa_pe_ref);
fsa_pe_ref = NULL;
} else {
crm_debug_2("Skipping superceeded reply from %s",
sys_from);
}
} else if(strcasecmp(op, CRM_OP_VOTE) == 0
|| strcasecmp(op, CRM_OP_HBEAT) == 0
|| strcasecmp(op, CRM_OP_SHUTDOWN_REQ) == 0
|| strcasecmp(op, CRM_OP_SHUTDOWN) == 0) {
crm_debug_2("Ignoring %s from %s in %s",
op, host_from, fsa_state2string(fsa_state));
next_input = I_NULL;
} else {
crm_err("Unexpected response (op=%s) sent to the %s",
op, AM_I_DC?"DC":"CRMd");
next_input = I_NULL;
}
return next_input;
}
enum crmd_fsa_input
handle_shutdown_request(HA_Message *stored_msg)
{
/* handle here to avoid potential version issues
* where the shutdown message/proceedure may have
* been changed in later versions.
*
* This way the DC is always in control of the shutdown
*/
time_t now = time(NULL);
crm_data_t *node_state = NULL;
const char *host_from = cl_get_string(stored_msg, F_CRM_HOST_FROM);
if(host_from == NULL) {
/* we're shutting down and the DC */
host_from = fsa_our_uname;
}
crm_info("Creating shutdown request for %s",host_from);
crm_log_message(LOG_MSG, stored_msg);
node_state = create_node_state(
host_from, NULL, NULL, NULL, NULL,
CRMD_STATE_INACTIVE, FALSE, __FUNCTION__);
crm_xml_add_int(node_state, XML_CIB_ATTR_SHUTDOWN, (int)now);
fsa_cib_anon_update(XML_CIB_TAG_STATUS,node_state, cib_quorum_override);
crm_log_xml_debug_2(node_state, "Shutdown update");
free_xml(node_state);
/* will be picked up by the TE as long as its running */
if(need_transition(fsa_state)
&& is_set(fsa_input_register, R_TE_CONNECTED) == FALSE) {
register_fsa_action(A_TE_CANCEL);
}
return I_NULL;
}
/* frees msg upon completion */
gboolean
send_msg_via_ha(ll_cluster_t *hb_fd, HA_Message *msg)
{
int log_level = LOG_DEBUG_3;
gboolean broadcast = FALSE;
gboolean all_is_good = TRUE;
const char *op = cl_get_string(msg, F_CRM_TASK);
const char *sys_to = cl_get_string(msg, F_CRM_SYS_TO);
const char *host_to = cl_get_string(msg, F_CRM_HOST_TO);
if (msg == NULL) {
crm_err("Attempt to send NULL Message via HA failed.");
all_is_good = FALSE;
} else {
crm_debug_4("Relaying message to (%s) via HA", host_to);
}
if (all_is_good) {
if (sys_to == NULL || strlen(sys_to) == 0) {
crm_err("You did not specify a destination sub-system"
" for this message.");
all_is_good = FALSE;
}
}
/* There are a number of messages may not need to be ordered.
* At a later point perhaps we should detect them and send them
* as unordered messages.
*/
if (all_is_good) {
if (host_to == NULL
|| strlen(host_to) == 0
|| safe_str_eq(sys_to, CRM_SYSTEM_DC)) {
broadcast = TRUE;
all_is_good = send_ha_message(hb_fd, msg, NULL, FALSE);
} else {
all_is_good = send_ha_message(hb_fd, msg, host_to, FALSE);
}
}
if(all_is_good == FALSE) {
log_level = LOG_WARNING;
}
if(log_level == LOG_WARNING
|| (safe_str_neq(op, CRM_OP_HBEAT))) {
do_crm_log(log_level,
"Sending %sHA message (ref=%s) to %s@%s %s.",
broadcast?"broadcast ":"directed ",
cl_get_string(msg, XML_ATTR_REFERENCE),
crm_str(sys_to), host_to==NULL?"<all>":host_to,
all_is_good?"succeeded":"failed");
}
crm_msg_del(msg);
return all_is_good;
}
/* msg is deleted by the time this returns */
gboolean
send_msg_via_ipc(HA_Message *msg, const char *sys)
{
gboolean send_ok = TRUE;
IPC_Channel *client_channel;
enum crmd_fsa_input next_input;
crm_debug_4("relaying msg to sub_sys=%s via IPC", sys);
client_channel = (IPC_Channel*)g_hash_table_lookup(ipc_clients, sys);
if(cl_get_string(msg, F_CRM_HOST_FROM) == NULL) {
ha_msg_add(msg, F_CRM_HOST_FROM, fsa_our_uname);
}
if (client_channel != NULL) {
crm_debug_3("Sending message via channel %s.", sys);
send_ok = send_ipc_message(client_channel, msg);
} else if(sys != NULL && strcasecmp(sys, CRM_SYSTEM_CIB) == 0) {
crm_err("Sub-system (%s) has been incorporated into the CRMd.",
sys);
crm_err("Change the way we handle this CIB message");
crm_log_message(LOG_ERR, msg);
send_ok = FALSE;
} else if(sys != NULL && strcasecmp(sys, CRM_SYSTEM_LRMD) == 0) {
fsa_data_t *fsa_data = NULL;
ha_msg_input_t *msg_copy = new_ha_msg_input(msg);
crm_malloc0(fsa_data, sizeof(fsa_data_t));
fsa_data->fsa_input = I_MESSAGE;
fsa_data->fsa_cause = C_IPC_MESSAGE;
fsa_data->data = msg_copy;
fsa_data->origin = __FUNCTION__;
fsa_data->data_type = fsa_dt_ha_msg;
#ifdef FSA_TRACE
crm_debug_2("Invoking action %s (%.16llx)",
fsa_action2string(A_LRM_INVOKE),
A_LRM_INVOKE);
#endif
next_input = do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE,
fsa_state, I_MESSAGE, fsa_data);
delete_ha_msg_input(msg_copy);
crm_free(fsa_data);
/* todo: feed this back in for anything != I_NULL */
#ifdef FSA_TRACE
crm_debug_2("Result of action %s was %s",
fsa_action2string(A_LRM_INVOKE),
fsa_input2string(next_input));
#endif
} else {
crm_err("Unknown Sub-system (%s)... discarding message.",
crm_str(sys));
send_ok = FALSE;
}
crm_msg_del(msg);
return send_ok;
}
void
msg_queue_helper(void)
{
IPC_Channel *ipc = NULL;
if(fsa_cluster_conn != NULL) {
ipc = fsa_cluster_conn->llc_ops->ipcchan(
fsa_cluster_conn);
}
if(ipc != NULL) {
ipc->ops->resume_io(ipc);
}
/* g_hash_table_foreach_remove(ipc_clients, ipc_queue_helper, NULL); */
}
gboolean
ipc_queue_helper(gpointer key, gpointer value, gpointer user_data)
{
crmd_client_t *ipc_client = value;
if(ipc_client->client_channel != NULL) {
ipc_client->client_channel->ops->is_message_pending(ipc_client->client_channel);
}
return FALSE;
}
diff --git a/crm/crmd/utils.c b/crm/crmd/utils.c
index 03bab915b3..daa3e0a6b7 100644
--- a/crm/crmd/utils.c
+++ b/crm/crmd/utils.c
@@ -1,1468 +1,1473 @@
/*
* 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 <crm/cib.h>
#include <crmd_fsa.h>
#include <clplumbing/Gmain_timeout.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <heartbeat.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <crmd_messages.h>
#include <crmd_utils.h>
void copy_ccm_node(oc_node_t a_node, oc_node_t *a_node_copy);
/* A_DC_TIMER_STOP, A_DC_TIMER_START,
* A_FINALIZE_TIMER_STOP, A_FINALIZE_TIMER_START
* A_INTEGRATE_TIMER_STOP, A_INTEGRATE_TIMER_START
*/
enum crmd_fsa_input
do_timer_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
gboolean timer_op_ok = TRUE;
enum crmd_fsa_input result = I_NULL;
if(action & A_DC_TIMER_STOP) {
timer_op_ok = crm_timer_stop(election_trigger);
} else if(action & A_FINALIZE_TIMER_STOP) {
timer_op_ok = crm_timer_stop(finalization_timer);
} else if(action & A_INTEGRATE_TIMER_STOP) {
timer_op_ok = crm_timer_stop(integration_timer);
/* } else if(action & A_ELECTION_TIMEOUT_STOP) { */
/* timer_op_ok = crm_timer_stop(election_timeout); */
}
/* dont start a timer that wasnt already running */
if(action & A_DC_TIMER_START && timer_op_ok) {
crm_timer_start(election_trigger);
if(AM_I_DC) {
/* there can be only one */
result = I_ELECTION;
}
} else if(action & A_FINALIZE_TIMER_START) {
crm_timer_start(finalization_timer);
} else if(action & A_INTEGRATE_TIMER_START) {
crm_timer_start(integration_timer);
/* } else if(action & A_ELECTION_TIMEOUT_START) { */
/* crm_timer_start(election_timeout); */
}
return I_NULL;
}
static const char *
get_timer_desc(fsa_timer_t *timer)
{
if(timer == election_trigger) {
return "Election Trigger";
} else if(timer == election_timeout) {
return "Election Timeout";
} else if(timer == shutdown_escalation_timer) {
return "Shutdown Escalation";
} else if(timer == integration_timer) {
return "Integration Timer";
} else if(timer == finalization_timer) {
return "Finalization Timer";
} else if(timer == wait_timer) {
return "Wait Timer";
} else if(timer == recheck_timer) {
return "PEngine Recheck Timer";
}
return "Unknown Timer";
}
gboolean
crm_timer_popped(gpointer data)
{
fsa_timer_t *timer = (fsa_timer_t *)data;
if(timer == wait_timer
|| timer == recheck_timer
|| timer == finalization_timer
|| timer == election_trigger) {
crm_info("%s (%s) just popped!",
get_timer_desc(timer),
fsa_input2string(timer->fsa_input));
} else {
crm_err("%s (%s) just popped!",
get_timer_desc(timer),
fsa_input2string(timer->fsa_input));
}
if(timer->repeat == FALSE) {
crm_timer_stop(timer); /* make it _not_ go off again */
}
if(timer->fsa_input == I_INTEGRATED) {
register_fsa_input_before(
C_TIMER_POPPED, timer->fsa_input, NULL);
} else if(timer->fsa_input == I_PE_CALC
&& fsa_state != S_IDLE) {
crm_debug("Discarding %s event in state: %s",
fsa_input2string(timer->fsa_input),
fsa_state2string(fsa_state));
} else if(timer->fsa_input == I_FINALIZED
&& fsa_state != S_FINALIZE_JOIN) {
crm_debug("Discarding %s event in state: %s",
fsa_input2string(timer->fsa_input),
fsa_state2string(fsa_state));
} else if(timer->fsa_input != I_NULL) {
register_fsa_input(C_TIMER_POPPED, timer->fsa_input, NULL);
}
crm_debug_3("Triggering FSA: %s", __FUNCTION__);
G_main_set_trigger(fsa_source);
return TRUE;
}
gboolean
crm_timer_start(fsa_timer_t *timer)
{
const char *timer_desc = get_timer_desc(timer);
if(timer->source_id == 0 && timer->period_ms > 0) {
timer->source_id = Gmain_timeout_add(
timer->period_ms, timer->callback, (void*)timer);
CRM_ASSERT(timer->source_id != 0);
crm_debug("Started %s (%s:%dms), src=%d",
timer_desc, fsa_input2string(timer->fsa_input),
timer->period_ms, timer->source_id);
} else if(timer->period_ms < 0) {
crm_err("Tried to start %s (%s:%dms) with a -ve period",
timer_desc, fsa_input2string(timer->fsa_input),
timer->period_ms);
} else {
crm_debug("%s (%s:%dms) already running: src=%d",
timer_desc, fsa_input2string(timer->fsa_input),
timer->period_ms, timer->source_id);
return FALSE;
}
return TRUE;
}
gboolean
crm_timer_stop(fsa_timer_t *timer)
{
const char *timer_desc = get_timer_desc(timer);
if(timer == NULL) {
crm_err("Attempted to stop NULL timer");
return FALSE;
} else if(timer->source_id != 0) {
crm_debug("Stopping %s (%s:%dms), src=%d",
timer_desc, fsa_input2string(timer->fsa_input),
timer->period_ms, timer->source_id);
Gmain_timeout_remove(timer->source_id);
timer->source_id = 0;
} else {
crm_debug_2("%s (%s:%dms) already stopped",
timer_desc, fsa_input2string(timer->fsa_input),
timer->period_ms);
return FALSE;
}
return TRUE;
}
long long
toggle_bit(long long action_list, long long action)
{
crm_debug_5("Toggling bit %.16llx", action);
action_list ^= action;
crm_debug_5("Result %.16llx", action_list & action);
return action_list;
}
long long
clear_bit(long long action_list, long long action)
{
unsigned int level = LOG_DEBUG_5;
do_crm_log(level, "Clearing bit\t%.16llx", action);
/* ensure its set */
action_list |= action;
/* then toggle */
action_list = action_list ^ action;
return action_list;
}
long long
set_bit(long long action_list, long long action)
{
unsigned int level = LOG_DEBUG_5;
do_crm_log(level, "Setting bit\t%.16llx", action);
action_list |= action;
return action_list;
}
gboolean
is_set(long long action_list, long long action)
{
crm_debug_5("Checking bit\t%.16llx in %.16llx", action, action_list);
return ((action_list & action) == action);
}
gboolean
is_set_any(long long action_list, long long action)
{
crm_debug_5("Checking bit\t%.16llx in %.16llx", action, action_list);
return ((action_list & action) != 0);
}
const char *
fsa_input2string(enum crmd_fsa_input input)
{
const char *inputAsText = NULL;
switch(input){
case I_NULL:
inputAsText = "I_NULL";
break;
case I_CCM_EVENT:
inputAsText = "I_CCM_EVENT";
break;
case I_CIB_OP:
inputAsText = "I_CIB_OP";
break;
case I_CIB_UPDATE:
inputAsText = "I_CIB_UPDATE";
break;
case I_DC_TIMEOUT:
inputAsText = "I_DC_TIMEOUT";
break;
case I_ELECTION:
inputAsText = "I_ELECTION";
break;
case I_PE_CALC:
inputAsText = "I_PE_CALC";
break;
case I_RELEASE_DC:
inputAsText = "I_RELEASE_DC";
break;
case I_ELECTION_DC:
inputAsText = "I_ELECTION_DC";
break;
case I_ERROR:
inputAsText = "I_ERROR";
break;
case I_FAIL:
inputAsText = "I_FAIL";
break;
case I_INTEGRATED:
inputAsText = "I_INTEGRATED";
break;
case I_FINALIZED:
inputAsText = "I_FINALIZED";
break;
case I_NODE_JOIN:
inputAsText = "I_NODE_JOIN";
break;
case I_JOIN_OFFER:
inputAsText = "I_JOIN_OFFER";
break;
case I_JOIN_REQUEST:
inputAsText = "I_JOIN_REQUEST";
break;
case I_JOIN_RESULT:
inputAsText = "I_JOIN_RESULT";
break;
case I_NOT_DC:
inputAsText = "I_NOT_DC";
break;
case I_RECOVERED:
inputAsText = "I_RECOVERED";
break;
case I_RELEASE_FAIL:
inputAsText = "I_RELEASE_FAIL";
break;
case I_RELEASE_SUCCESS:
inputAsText = "I_RELEASE_SUCCESS";
break;
case I_RESTART:
inputAsText = "I_RESTART";
break;
case I_PE_SUCCESS:
inputAsText = "I_PE_SUCCESS";
break;
case I_ROUTER:
inputAsText = "I_ROUTER";
break;
case I_SHUTDOWN:
inputAsText = "I_SHUTDOWN";
break;
case I_STARTUP:
inputAsText = "I_STARTUP";
break;
case I_TE_SUCCESS:
inputAsText = "I_TE_SUCCESS";
break;
case I_STOP:
inputAsText = "I_STOP";
break;
case I_DC_HEARTBEAT:
inputAsText = "I_DC_HEARTBEAT";
break;
case I_WAIT_FOR_EVENT:
inputAsText = "I_WAIT_FOR_EVENT";
break;
case I_LRM_EVENT:
inputAsText = "I_LRM_EVENT";
break;
case I_PENDING:
inputAsText = "I_PENDING";
break;
case I_HALT:
inputAsText = "I_HALT";
break;
case I_TERMINATE:
inputAsText = "I_TERMINATE";
break;
case I_ILLEGAL:
inputAsText = "I_ILLEGAL";
break;
}
if(inputAsText == NULL) {
crm_err("Input %d is unknown", input);
inputAsText = "<UNKNOWN_INPUT>";
}
return inputAsText;
}
const char *
fsa_state2string(enum crmd_fsa_state state)
{
const char *stateAsText = NULL;
switch(state){
case S_IDLE:
stateAsText = "S_IDLE";
break;
case S_ELECTION:
stateAsText = "S_ELECTION";
break;
case S_INTEGRATION:
stateAsText = "S_INTEGRATION";
break;
case S_FINALIZE_JOIN:
stateAsText = "S_FINALIZE_JOIN";
break;
case S_NOT_DC:
stateAsText = "S_NOT_DC";
break;
case S_POLICY_ENGINE:
stateAsText = "S_POLICY_ENGINE";
break;
case S_RECOVERY:
stateAsText = "S_RECOVERY";
break;
case S_RELEASE_DC:
stateAsText = "S_RELEASE_DC";
break;
case S_PENDING:
stateAsText = "S_PENDING";
break;
case S_STOPPING:
stateAsText = "S_STOPPING";
break;
case S_TERMINATE:
stateAsText = "S_TERMINATE";
break;
case S_TRANSITION_ENGINE:
stateAsText = "S_TRANSITION_ENGINE";
break;
case S_STARTING:
stateAsText = "S_STARTING";
break;
case S_HALT:
stateAsText = "S_HALT";
break;
case S_ILLEGAL:
stateAsText = "S_ILLEGAL";
break;
}
if(stateAsText == NULL) {
crm_err("State %d is unknown", state);
stateAsText = "<UNKNOWN_STATE>";
}
return stateAsText;
}
const char *
fsa_cause2string(enum crmd_fsa_cause cause)
{
const char *causeAsText = NULL;
switch(cause){
case C_UNKNOWN:
causeAsText = "C_UNKNOWN";
break;
case C_STARTUP:
causeAsText = "C_STARTUP";
break;
case C_IPC_MESSAGE:
causeAsText = "C_IPC_MESSAGE";
break;
case C_HA_MESSAGE:
causeAsText = "C_HA_MESSAGE";
break;
case C_CCM_CALLBACK:
causeAsText = "C_CCM_CALLBACK";
break;
case C_TIMER_POPPED:
causeAsText = "C_TIMER_POPPED";
break;
case C_SHUTDOWN:
causeAsText = "C_SHUTDOWN";
break;
case C_HEARTBEAT_FAILED:
causeAsText = "C_HEARTBEAT_FAILED";
break;
case C_SUBSYSTEM_CONNECT:
causeAsText = "C_SUBSYSTEM_CONNECT";
break;
case C_LRM_OP_CALLBACK:
causeAsText = "C_LRM_OP_CALLBACK";
break;
case C_LRM_MONITOR_CALLBACK:
causeAsText = "C_LRM_MONITOR_CALLBACK";
break;
case C_CRMD_STATUS_CALLBACK:
causeAsText = "C_CRMD_STATUS_CALLBACK";
break;
case C_HA_DISCONNECT:
causeAsText = "C_HA_DISCONNECT";
break;
case C_FSA_INTERNAL:
causeAsText = "C_FSA_INTERNAL";
break;
case C_ILLEGAL:
causeAsText = "C_ILLEGAL";
break;
}
if(causeAsText == NULL) {
crm_err("Cause %d is unknown", cause);
causeAsText = "<UNKNOWN_CAUSE>";
}
return causeAsText;
}
const char *
fsa_action2string(long long action)
{
const char *actionAsText = NULL;
switch(action){
case A_NOTHING:
actionAsText = "A_NOTHING";
break;
case A_ELECTION_START:
actionAsText = "A_ELECTION_START";
break;
case A_READCONFIG:
actionAsText = "A_READCONFIG";
break;
case O_RELEASE:
actionAsText = "O_RELEASE";
break;
case A_STARTUP:
actionAsText = "A_STARTUP";
break;
case A_STARTED:
actionAsText = "A_STARTED";
break;
case A_HA_CONNECT:
actionAsText = "A_HA_CONNECT";
break;
case A_HA_DISCONNECT:
actionAsText = "A_HA_DISCONNECT";
break;
case A_LRM_CONNECT:
actionAsText = "A_LRM_CONNECT";
break;
case A_LRM_EVENT:
actionAsText = "A_LRM_EVENT";
break;
case A_LRM_INVOKE:
actionAsText = "A_LRM_INVOKE";
break;
case A_LRM_DISCONNECT:
actionAsText = "A_LRM_DISCONNECT";
break;
case A_CL_JOIN_QUERY:
actionAsText = "A_CL_JOIN_QUERY";
break;
case A_DC_TIMER_STOP:
actionAsText = "A_DC_TIMER_STOP";
break;
case A_DC_TIMER_START:
actionAsText = "A_DC_TIMER_START";
break;
case A_INTEGRATE_TIMER_START:
actionAsText = "A_INTEGRATE_TIMER_START";
break;
case A_INTEGRATE_TIMER_STOP:
actionAsText = "A_INTEGRATE_TIMER_STOP";
break;
case A_FINALIZE_TIMER_START:
actionAsText = "A_FINALIZE_TIMER_START";
break;
case A_FINALIZE_TIMER_STOP:
actionAsText = "A_FINALIZE_TIMER_STOP";
break;
case A_ELECTION_COUNT:
actionAsText = "A_ELECTION_COUNT";
break;
case A_ELECTION_VOTE:
actionAsText = "A_ELECTION_VOTE";
break;
case A_ELECTION_CHECK:
actionAsText = "A_ELECTION_CHECK";
break;
case A_CL_JOIN_ANNOUNCE:
actionAsText = "A_CL_JOIN_ANNOUNCE";
break;
case A_CL_JOIN_REQUEST:
actionAsText = "A_CL_JOIN_REQUEST";
break;
case A_CL_JOIN_RESULT:
actionAsText = "A_CL_JOIN_RESULT";
break;
case A_DC_JOIN_OFFER_ALL:
actionAsText = "A_DC_JOIN_OFFER_ALL";
break;
case A_DC_JOIN_OFFER_ONE:
actionAsText = "A_DC_JOIN_OFFER_ONE";
break;
case A_DC_JOIN_PROCESS_REQ:
actionAsText = "A_DC_JOIN_PROCESS_REQ";
break;
case A_DC_JOIN_PROCESS_ACK:
actionAsText = "A_DC_JOIN_PROCESS_ACK";
break;
case A_DC_JOIN_FINALIZE:
actionAsText = "A_DC_JOIN_FINALIZE";
break;
case A_MSG_PROCESS:
actionAsText = "A_MSG_PROCESS";
break;
case A_MSG_ROUTE:
actionAsText = "A_MSG_ROUTE";
break;
case A_RECOVER:
actionAsText = "A_RECOVER";
break;
case A_DC_RELEASE:
actionAsText = "A_DC_RELEASE";
break;
case A_DC_RELEASED:
actionAsText = "A_DC_RELEASED";
break;
case A_DC_TAKEOVER:
actionAsText = "A_DC_TAKEOVER";
break;
case A_SHUTDOWN:
actionAsText = "A_SHUTDOWN";
break;
case A_SHUTDOWN_REQ:
actionAsText = "A_SHUTDOWN_REQ";
break;
case A_STOP:
actionAsText = "A_STOP ";
break;
case A_EXIT_0:
actionAsText = "A_EXIT_0";
break;
case A_EXIT_1:
actionAsText = "A_EXIT_1";
break;
case A_CCM_CONNECT:
actionAsText = "A_CCM_CONNECT";
break;
case A_CCM_DISCONNECT:
actionAsText = "A_CCM_DISCONNECT";
break;
case A_CCM_EVENT:
actionAsText = "A_CCM_EVENT";
break;
case A_CCM_UPDATE_CACHE:
actionAsText = "A_CCM_UPDATE_CACHE";
break;
case A_CIB_BUMPGEN:
actionAsText = "A_CIB_BUMPGEN";
break;
case A_CIB_INVOKE:
actionAsText = "A_CIB_INVOKE";
break;
case O_CIB_RESTART:
actionAsText = "O_CIB_RESTART";
break;
case A_CIB_START:
actionAsText = "A_CIB_START";
break;
case A_CIB_STOP:
actionAsText = "A_CIB_STOP";
break;
case A_TE_INVOKE:
actionAsText = "A_TE_INVOKE";
break;
case O_TE_RESTART:
actionAsText = "O_TE_RESTART";
break;
case A_TE_START:
actionAsText = "A_TE_START";
break;
case A_TE_STOP:
actionAsText = "A_TE_STOP";
break;
case A_TE_HALT:
actionAsText = "A_TE_HALT";
break;
case A_TE_CANCEL:
actionAsText = "A_TE_CANCEL";
break;
case A_PE_INVOKE:
actionAsText = "A_PE_INVOKE";
break;
case O_PE_RESTART:
actionAsText = "O_PE_RESTART";
break;
case A_PE_START:
actionAsText = "A_PE_START";
break;
case A_PE_STOP:
actionAsText = "A_PE_STOP";
break;
case A_NODE_BLOCK:
actionAsText = "A_NODE_BLOCK";
break;
case A_UPDATE_NODESTATUS:
actionAsText = "A_UPDATE_NODESTATUS";
break;
case A_LOG:
actionAsText = "A_LOG ";
break;
case A_ERROR:
actionAsText = "A_ERROR ";
break;
case A_WARN:
actionAsText = "A_WARN ";
break;
}
if(actionAsText == NULL) {
crm_err("Action %.16llx is unknown", action);
actionAsText = "<UNKNOWN_ACTION>";
}
return actionAsText;
}
void
fsa_dump_inputs(int log_level, const char *text, long long input_register)
{
if(input_register == A_NOTHING) {
return;
}
if(text == NULL) {
text = "Input register contents:";
}
if(is_set(input_register, R_THE_DC)) {
do_crm_log(log_level,
"%s %.16llx (R_THE_DC)", text, R_THE_DC);
}
if(is_set(input_register, R_STARTING)) {
do_crm_log(log_level, "%s %.16llx (R_STARTING)",
text, R_STARTING);
}
if(is_set(input_register, R_SHUTDOWN)) {
do_crm_log(log_level, "%s %.16llx (R_SHUTDOWN)",
text, R_SHUTDOWN);
}
if(is_set(input_register, R_STAYDOWN)) {
do_crm_log(log_level, "%s %.16llx (R_STAYDOWN)",
text, R_STAYDOWN);
}
if(is_set(input_register, R_JOIN_OK)) {
do_crm_log(log_level, "%s %.16llx (R_JOIN_OK)",
text, R_JOIN_OK);
}
if(is_set(input_register, R_READ_CONFIG)) {
do_crm_log(log_level, "%s %.16llx (R_READ_CONFIG)",
text, R_READ_CONFIG);
}
if(is_set(input_register, R_INVOKE_PE)) {
do_crm_log(log_level, "%s %.16llx (R_INVOKE_PE)",
text, R_INVOKE_PE);
}
if(is_set(input_register, R_CIB_CONNECTED)) {
do_crm_log(log_level, "%s %.16llx (R_CIB_CONNECTED)",
text, R_CIB_CONNECTED);
}
if(is_set(input_register, R_PE_CONNECTED)) {
do_crm_log(log_level, "%s %.16llx (R_PE_CONNECTED)",
text, R_PE_CONNECTED);
}
if(is_set(input_register, R_TE_CONNECTED)) {
do_crm_log(log_level, "%s %.16llx (R_TE_CONNECTED)",
text, R_TE_CONNECTED);
}
if(is_set(input_register, R_LRM_CONNECTED)) {
do_crm_log(log_level, "%s %.16llx (R_LRM_CONNECTED)",
text, R_LRM_CONNECTED);
}
if(is_set(input_register, R_CIB_REQUIRED)) {
do_crm_log(log_level, "%s %.16llx (R_CIB_REQUIRED)",
text, R_CIB_REQUIRED);
}
if(is_set(input_register, R_PE_REQUIRED)) {
do_crm_log(log_level, "%s %.16llx (R_PE_REQUIRED)",
text, R_PE_REQUIRED);
}
if(is_set(input_register, R_TE_REQUIRED)) {
do_crm_log(log_level, "%s %.16llx (R_TE_REQUIRED)",
text, R_TE_REQUIRED);
}
if(is_set(input_register, R_REQ_PEND)) {
do_crm_log(log_level, "%s %.16llx (R_REQ_PEND)",
text, R_REQ_PEND);
}
if(is_set(input_register, R_PE_PEND)) {
do_crm_log(log_level, "%s %.16llx (R_PE_PEND)",
text, R_PE_PEND);
}
if(is_set(input_register, R_TE_PEND)) {
do_crm_log(log_level, "%s %.16llx (R_TE_PEND)",
text, R_TE_PEND);
}
if(is_set(input_register, R_RESP_PEND)) {
do_crm_log(log_level, "%s %.16llx (R_RESP_PEND)",
text, R_RESP_PEND);
}
if(is_set(input_register, R_CIB_DONE)) {
do_crm_log(log_level, "%s %.16llx (R_CIB_DONE)",
text, R_CIB_DONE);
}
if(is_set(input_register, R_HAVE_CIB)) {
do_crm_log(log_level, "%s %.16llx (R_HAVE_CIB)",
text, R_HAVE_CIB);
}
if(is_set(input_register, R_CIB_ASKED)) {
do_crm_log(log_level, "%s %.16llx (R_CIB_ASKED)",
text, R_CIB_ASKED);
}
if(is_set(input_register, R_CCM_DATA)) {
do_crm_log(log_level, "%s %.16llx (R_CCM_DATA)",
text, R_CCM_DATA);
}
if(is_set(input_register, R_PEER_DATA)) {
do_crm_log(log_level, "%s %.16llx (R_PEER_DATA)",
text, R_PEER_DATA);
}
if(is_set(input_register, R_IN_RECOVERY)) {
do_crm_log(log_level, "%s %.16llx (R_IN_RECOVERY)",
text, R_IN_RECOVERY);
}
}
void
fsa_dump_actions(long long action, const char *text)
{
int log_level = LOG_DEBUG_3;
if(is_set(action, A_READCONFIG)) {
do_crm_log(log_level,
"Action %.16llx (A_READCONFIG) %s", A_READCONFIG, text);
}
if(is_set(action, A_STARTUP)) {
do_crm_log(log_level,
"Action %.16llx (A_STARTUP) %s", A_STARTUP, text);
}
if(is_set(action, A_STARTED)) {
do_crm_log(log_level,
"Action %.16llx (A_STARTED) %s", A_STARTED, text);
}
if(is_set(action, A_HA_CONNECT)) {
do_crm_log(log_level,
"Action %.16llx (A_CONNECT) %s", A_HA_CONNECT, text);
}
if(is_set(action, A_HA_DISCONNECT)) {
do_crm_log(log_level,
"Action %.16llx (A_DISCONNECT) %s",
A_HA_DISCONNECT, text);
}
if(is_set(action, A_LRM_CONNECT)) {
do_crm_log(log_level,
"Action %.16llx (A_LRM_CONNECT) %s",
A_LRM_CONNECT, text);
}
if(is_set(action, A_LRM_EVENT)) {
do_crm_log(log_level,
"Action %.16llx (A_LRM_EVENT) %s",
A_LRM_EVENT, text);
}
if(is_set(action, A_LRM_INVOKE)) {
do_crm_log(log_level,
"Action %.16llx (A_LRM_INVOKE) %s",
A_LRM_INVOKE, text);
}
if(is_set(action, A_LRM_DISCONNECT)) {
do_crm_log(log_level,
"Action %.16llx (A_LRM_DISCONNECT) %s",
A_LRM_DISCONNECT, text);
}
if(is_set(action, A_DC_TIMER_STOP)) {
do_crm_log(log_level,
"Action %.16llx (A_DC_TIMER_STOP) %s",
A_DC_TIMER_STOP, text);
}
if(is_set(action, A_DC_TIMER_START)) {
do_crm_log(log_level,
"Action %.16llx (A_DC_TIMER_START) %s",
A_DC_TIMER_START, text);
}
if(is_set(action, A_INTEGRATE_TIMER_START)) {
do_crm_log(log_level,
"Action %.16llx (A_INTEGRATE_TIMER_START) %s",
A_INTEGRATE_TIMER_START, text);
}
if(is_set(action, A_INTEGRATE_TIMER_STOP)) {
do_crm_log(log_level,
"Action %.16llx (A_INTEGRATE_TIMER_STOP) %s",
A_INTEGRATE_TIMER_STOP, text);
}
if(is_set(action, A_FINALIZE_TIMER_START)) {
do_crm_log(log_level,
"Action %.16llx (A_FINALIZE_TIMER_START) %s",
A_FINALIZE_TIMER_START, text);
}
if(is_set(action, A_FINALIZE_TIMER_STOP)) {
do_crm_log(log_level,
"Action %.16llx (A_FINALIZE_TIMER_STOP) %s",
A_FINALIZE_TIMER_STOP, text);
}
if(is_set(action, A_ELECTION_COUNT)) {
do_crm_log(log_level,
"Action %.16llx (A_ELECTION_COUNT) %s",
A_ELECTION_COUNT, text);
}
if(is_set(action, A_ELECTION_VOTE)) {
do_crm_log(log_level,
"Action %.16llx (A_ELECTION_VOTE) %s",
A_ELECTION_VOTE, text);
}
if(is_set(action, A_ELECTION_CHECK)) {
do_crm_log(log_level,
"Action %.16llx (A_ELECTION_CHECK) %s",
A_ELECTION_CHECK, text);
}
if(is_set(action, A_CL_JOIN_ANNOUNCE)) {
do_crm_log(log_level,
"Action %.16llx (A_CL_JOIN_ANNOUNCE) %s",
A_CL_JOIN_ANNOUNCE, text);
}
if(is_set(action, A_CL_JOIN_REQUEST)) {
do_crm_log(log_level,
"Action %.16llx (A_CL_JOIN_REQUEST) %s",
A_CL_JOIN_REQUEST, text);
}
if(is_set(action, A_CL_JOIN_RESULT)) {
do_crm_log(log_level,
"Action %.16llx (A_CL_JOIN_RESULT) %s",
A_CL_JOIN_RESULT, text);
}
if(is_set(action, A_DC_JOIN_OFFER_ALL)) {
do_crm_log(log_level,
"Action %.16llx (A_DC_JOIN_OFFER_ALL) %s",
A_DC_JOIN_OFFER_ALL, text);
}
if(is_set(action, A_DC_JOIN_OFFER_ONE)) {
do_crm_log(log_level,
"Action %.16llx (A_DC_JOIN_OFFER_ONE) %s",
A_DC_JOIN_OFFER_ONE, text);
}
if(is_set(action, A_DC_JOIN_PROCESS_REQ)) {
do_crm_log(log_level,
"Action %.16llx (A_DC_JOIN_PROCESS_REQ) %s",
A_DC_JOIN_PROCESS_REQ, text);
}
if(is_set(action, A_DC_JOIN_PROCESS_ACK)) {
do_crm_log(log_level,
"Action %.16llx (A_DC_JOIN_PROCESS_ACK) %s",
A_DC_JOIN_PROCESS_ACK, text);
}
if(is_set(action, A_DC_JOIN_FINALIZE)) {
do_crm_log(log_level,
"Action %.16llx (A_DC_JOIN_FINALIZE) %s",
A_DC_JOIN_FINALIZE, text);
}
if(is_set(action, A_MSG_PROCESS)) {
do_crm_log(log_level,
"Action %.16llx (A_MSG_PROCESS) %s",
A_MSG_PROCESS, text);
}
if(is_set(action, A_MSG_ROUTE)) {
do_crm_log(log_level,
"Action %.16llx (A_MSG_ROUTE) %s",
A_MSG_ROUTE, text);
}
if(is_set(action, A_RECOVER)) {
do_crm_log(log_level,
"Action %.16llx (A_RECOVER) %s",
A_RECOVER, text);
}
if(is_set(action, A_DC_RELEASE)) {
do_crm_log(log_level,
"Action %.16llx (A_DC_RELEASE) %s",
A_DC_RELEASE, text);
}
if(is_set(action, A_DC_RELEASED)) {
do_crm_log(log_level,
"Action %.16llx (A_DC_RELEASED) %s",
A_DC_RELEASED, text);
}
if(is_set(action, A_DC_TAKEOVER)) {
do_crm_log(log_level,
"Action %.16llx (A_DC_TAKEOVER) %s",
A_DC_TAKEOVER, text);
}
if(is_set(action, A_SHUTDOWN)) {
do_crm_log(log_level,
"Action %.16llx (A_SHUTDOWN) %s", A_SHUTDOWN, text);
}
if(is_set(action, A_SHUTDOWN_REQ)) {
do_crm_log(log_level,
"Action %.16llx (A_SHUTDOWN_REQ) %s",
A_SHUTDOWN_REQ, text);
}
if(is_set(action, A_STOP)) {
do_crm_log(log_level,
"Action %.16llx (A_STOP ) %s", A_STOP , text);
}
if(is_set(action, A_EXIT_0)) {
do_crm_log(log_level,
"Action %.16llx (A_EXIT_0) %s", A_EXIT_0, text);
}
if(is_set(action, A_EXIT_1)) {
do_crm_log(log_level,
"Action %.16llx (A_EXIT_1) %s", A_EXIT_1, text);
}
if(is_set(action, A_CCM_CONNECT)) {
do_crm_log(log_level,
"Action %.16llx (A_CCM_CONNECT) %s",
A_CCM_CONNECT, text);
}
if(is_set(action, A_CCM_DISCONNECT)) {
do_crm_log(log_level,
"Action %.16llx (A_CCM_DISCONNECT) %s",
A_CCM_DISCONNECT, text);
}
if(is_set(action, A_CCM_EVENT)) {
do_crm_log(log_level,
"Action %.16llx (A_CCM_EVENT) %s",
A_CCM_EVENT, text);
}
if(is_set(action, A_CCM_UPDATE_CACHE)) {
do_crm_log(log_level,
"Action %.16llx (A_CCM_UPDATE_CACHE) %s",
A_CCM_UPDATE_CACHE, text);
}
if(is_set(action, A_CIB_BUMPGEN)) {
do_crm_log(log_level,
"Action %.16llx (A_CIB_BUMPGEN) %s",
A_CIB_BUMPGEN, text);
}
if(is_set(action, A_CIB_INVOKE)) {
do_crm_log(log_level,
"Action %.16llx (A_CIB_INVOKE) %s",
A_CIB_INVOKE, text);
}
if(is_set(action, A_CIB_START)) {
do_crm_log(log_level,
"Action %.16llx (A_CIB_START) %s",
A_CIB_START, text);
}
if(is_set(action, A_CIB_STOP)) {
do_crm_log(log_level,
"Action %.16llx (A_CIB_STOP) %s", A_CIB_STOP, text);
}
if(is_set(action, A_TE_INVOKE)) {
do_crm_log(log_level,
"Action %.16llx (A_TE_INVOKE) %s", A_TE_INVOKE, text);
}
if(is_set(action, A_TE_START)) {
do_crm_log(log_level,
"Action %.16llx (A_TE_START) %s",
A_TE_START, text);
}
if(is_set(action, A_TE_STOP)) {
do_crm_log(log_level,
"Action %.16llx (A_TE_STOP) %s", A_TE_STOP, text);
}
if(is_set(action, A_TE_CANCEL)) {
do_crm_log(log_level,
"Action %.16llx (A_TE_CANCEL) %s",
A_TE_CANCEL, text);
}
if(is_set(action, A_PE_INVOKE)) {
do_crm_log(log_level,
"Action %.16llx (A_PE_INVOKE) %s",
A_PE_INVOKE, text);
}
if(is_set(action, A_PE_START)) {
do_crm_log(log_level,
"Action %.16llx (A_PE_START) %s", A_PE_START, text);
}
if(is_set(action, A_PE_STOP)) {
do_crm_log(log_level,
"Action %.16llx (A_PE_STOP) %s", A_PE_STOP, text);
}
if(is_set(action, A_NODE_BLOCK)) {
do_crm_log(log_level,
"Action %.16llx (A_NODE_BLOCK) %s",
A_NODE_BLOCK, text);
}
if(is_set(action, A_UPDATE_NODESTATUS)) {
do_crm_log(log_level,
"Action %.16llx (A_UPDATE_NODESTATUS) %s",
A_UPDATE_NODESTATUS, text);
}
if(is_set(action, A_LOG)) {
do_crm_log(log_level,
"Action %.16llx (A_LOG ) %s", A_LOG, text);
}
if(is_set(action, A_ERROR)) {
do_crm_log(log_level,
"Action %.16llx (A_ERROR ) %s", A_ERROR, text);
}
if(is_set(action, A_WARN)) {
do_crm_log(log_level,
"Action %.16llx (A_WARN ) %s", A_WARN, text);
}
}
void
create_node_entry(const char *uuid, const char *uname, const char *type)
{
/* make sure a node entry exists for the new node
*
* this will add anyone except the first ever node in the cluster
* since it will also be the DC which doesnt go through the
* join process (with itself). We can include a special case
* later if desired.
*/
crm_data_t *tmp1 = create_xml_node(NULL, XML_CIB_TAG_NODE);
crm_debug_3("Creating node entry for %s", uname);
set_uuid(fsa_cluster_conn, tmp1, XML_ATTR_UUID, uname);
crm_xml_add(tmp1, XML_ATTR_UNAME, uname);
crm_xml_add(tmp1, XML_ATTR_TYPE, type);
fsa_cib_anon_update(XML_CIB_TAG_NODES, tmp1,
cib_scope_local|cib_quorum_override);
free_xml(tmp1);
}
struct crmd_ccm_data_s *
copy_ccm_data(const struct crmd_ccm_data_s *ccm_input)
{
const oc_ev_membership_t *oc_in =
(const oc_ev_membership_t *)ccm_input->oc;
struct crmd_ccm_data_s *ccm_input_copy = NULL;
crm_malloc0(ccm_input_copy, sizeof(struct crmd_ccm_data_s));
ccm_input_copy->oc = copy_ccm_oc_data(oc_in);
ccm_input_copy->event = ccm_input->event;
return ccm_input_copy;
}
void
delete_ccm_data(struct crmd_ccm_data_s *ccm_input)
{
int lpc, offset = 0;
oc_node_t *a_node = NULL;
- oc_ev_membership_t *oc_in = ccm_input->oc;
- if(oc_in != NULL) {
- offset = oc_in->m_memb_idx;
+ oc_ev_membership_t *oc_in = NULL;
+ if(ccm_input == NULL) {
+ return;
+ }
+
+ oc_in = ccm_input->oc;
+ if(oc_in == NULL) {
+ goto bail;
}
+
+ offset = oc_in->m_memb_idx;
for(lpc = 0; lpc < oc_in->m_n_member; lpc++) {
a_node = &oc_in->m_array[lpc+offset];
crm_free(a_node->node_uname);
a_node->node_uname = NULL;
}
- if(oc_in != NULL) {
- offset = oc_in->m_in_idx;
- }
+ offset = oc_in->m_in_idx;
for(lpc = 0; lpc < oc_in->m_n_in; lpc++) {
a_node = &oc_in->m_array[lpc+offset];
crm_free(a_node->node_uname);
a_node->node_uname = NULL;
}
- if(oc_in != NULL) {
- offset = oc_in->m_out_idx;
- }
+ offset = oc_in->m_out_idx;
for(lpc = 0; lpc < oc_in->m_n_out; lpc++) {
a_node = &oc_in->m_array[lpc+offset];
crm_free(a_node->node_uname);
a_node->node_uname = NULL;
}
+
+ bail:
crm_free(ccm_input->oc);
crm_free(ccm_input);
}
oc_ev_membership_t *
copy_ccm_oc_data(const oc_ev_membership_t *oc_in)
{
unsigned lpc = 0;
int size = 0;
int offset = 0;
unsigned num_nodes = 0;
oc_ev_membership_t *oc_copy = NULL;
if(oc_in->m_n_member > 0
&& num_nodes < oc_in->m_n_member + oc_in->m_memb_idx) {
num_nodes = oc_in->m_n_member + oc_in->m_memb_idx;
crm_debug_3("Updated ccm nodes to %d - 1", num_nodes);
}
if(oc_in->m_n_in > 0
&& num_nodes < oc_in->m_n_in + oc_in->m_in_idx) {
num_nodes = oc_in->m_n_in + oc_in->m_in_idx;
crm_debug_3("Updated ccm nodes to %d - 2", num_nodes);
}
if(oc_in->m_n_out > 0
&& num_nodes < oc_in->m_n_out + oc_in->m_out_idx) {
num_nodes = oc_in->m_n_out + oc_in->m_out_idx;
crm_debug_3("Updated ccm nodes to %d - 3", num_nodes);
}
/* why 2*??
* ccm code does it like this so i guess its right...
*/
size = sizeof(oc_ev_membership_t)
+ sizeof(int)
+ 2*num_nodes*sizeof(oc_node_t);
crm_debug_3("Copying %d ccm nodes", num_nodes);
crm_malloc0(oc_copy, size);
oc_copy->m_instance = oc_in->m_instance;
oc_copy->m_n_member = oc_in->m_n_member;
oc_copy->m_memb_idx = oc_in->m_memb_idx;
oc_copy->m_n_out = oc_in->m_n_out;
oc_copy->m_out_idx = oc_in->m_out_idx;
oc_copy->m_n_in = oc_in->m_n_in;
oc_copy->m_in_idx = oc_in->m_in_idx;
crm_debug_3("instance=%d, nodes=%d (idx=%d), new=%d (idx=%d), lost=%d (idx=%d)",
oc_in->m_instance,
oc_in->m_n_member,
oc_in->m_memb_idx,
oc_in->m_n_in,
oc_in->m_in_idx,
oc_in->m_n_out,
oc_in->m_out_idx);
offset = oc_in->m_memb_idx;
for(lpc = 0; lpc < oc_in->m_n_member; lpc++) {
oc_node_t a_node = oc_in->m_array[lpc+offset];
oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]);
crm_debug_3("Copying ccm member node %d", lpc);
copy_ccm_node(a_node, a_node_copy);
}
offset = oc_in->m_in_idx;
for(lpc = 0; lpc < oc_in->m_n_in; lpc++) {
oc_node_t a_node = oc_in->m_array[lpc+offset];
oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]);
crm_debug_3("Copying ccm new node %d", lpc);
copy_ccm_node(a_node, a_node_copy);
}
offset = oc_in->m_out_idx;
for(lpc = 0; lpc < oc_in->m_n_out; lpc++) {
oc_node_t a_node = oc_in->m_array[lpc+offset];
oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]);
crm_debug_3("Copying ccm lost node %d", lpc);
copy_ccm_node(a_node, a_node_copy);
}
return oc_copy;
}
void
copy_ccm_node(oc_node_t a_node, oc_node_t *a_node_copy)
{
crm_debug_3("Copying ccm node: id=%d, born=%d, uname=%s",
a_node.node_id, a_node.node_born_on,
a_node.node_uname);
if(a_node_copy->node_uname != NULL) {
crm_debug_2("%p (%s) already copied", a_node_copy, a_node_copy->node_uname);
return;
}
a_node_copy->node_id = a_node.node_id;
a_node_copy->node_born_on = a_node.node_born_on;
a_node_copy->node_uname = NULL;
if(a_node.node_uname != NULL) {
a_node_copy->node_uname = crm_strdup(a_node.node_uname);
} else {
crm_err("Node Id %d had a NULL uname!", a_node.node_id);
}
crm_debug_3("Copied ccm node: id=%d, born=%d, uname=%s",
a_node_copy->node_id, a_node_copy->node_born_on,
a_node_copy->node_uname);
}
static gboolean
ghash_node_clfree(gpointer key, gpointer value, gpointer user_data)
{
/* value->node_uname is free'd as "key" */
if(key != NULL) {
crm_free(key);
}
if(value != NULL) {
crm_free(value);
}
return TRUE;
}
void
free_ccm_cache(oc_node_list_t *tmp)
{
/* Free the old copy */
if(tmp == NULL) {
return;
}
if(tmp->members != NULL) {
g_hash_table_foreach_remove(
tmp->members, ghash_node_clfree, NULL);
}
if(tmp->new_members != NULL) {
g_hash_table_foreach_remove(
tmp->new_members, ghash_node_clfree, NULL);
}
if(tmp->dead_members != NULL) {
g_hash_table_foreach_remove(
tmp->dead_members, ghash_node_clfree, NULL);
}
crm_free(tmp);
crm_debug_3("Free'd old copies");
}
crm_data_t*
create_node_state(
const char *uname, const char *ha_state, const char *ccm_state,
const char *crmd_state, const char *join_state, const char *exp_state,
gboolean clear_shutdown, const char *src)
{
crm_data_t *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE);
crm_debug_2("%s Creating node state entry for %s", src, uname);
set_uuid(fsa_cluster_conn, node_state, XML_ATTR_UUID, uname);
if(ID(node_state) == NULL) {
crm_debug("Node %s is not a cluster member", uname);
free_xml(node_state);
return NULL;
}
crm_xml_add(node_state, XML_ATTR_UNAME, uname);
crm_xml_add(node_state, XML_CIB_ATTR_HASTATE, ha_state);
crm_xml_add(node_state, XML_CIB_ATTR_INCCM, ccm_state);
crm_xml_add(node_state, XML_CIB_ATTR_CRMDSTATE, crmd_state);
crm_xml_add(node_state, XML_CIB_ATTR_JOINSTATE, join_state);
crm_xml_add(node_state, XML_CIB_ATTR_EXPSTATE, exp_state);
crm_xml_add(node_state, XML_ATTR_ORIGIN, src);
if(clear_shutdown) {
crm_xml_add(node_state, XML_CIB_ATTR_SHUTDOWN, "0");
#if CRM_DEPRECATED_SINCE_2_0_3
crm_xml_add(node_state, "clear_shutdown", "true");
#endif
/* crm_xml_add(node_state, */
/* XML_CIB_ATTR_REPLACE, XML_TAG_TRANSIENT_NODEATTRS); */
}
crm_log_xml_debug_3(node_state, "created");
return node_state;
}
gboolean
need_transition(enum crmd_fsa_state state)
{
if(state == S_POLICY_ENGINE
|| state == S_TRANSITION_ENGINE
|| state == S_IDLE) {
return TRUE;
}
return FALSE;
}
extern GHashTable *ipc_clients;
void
process_client_disconnect(crmd_client_t *curr_client)
{
struct crm_subsystem_s *the_subsystem = NULL;
CRM_CHECK(curr_client != NULL, return);
crm_debug_2("received HUP from %s", curr_client->table_key);
if (curr_client->sub_sys == NULL) {
crm_debug_2("Client hadn't registered with us yet");
} else if (strcasecmp(CRM_SYSTEM_PENGINE, curr_client->sub_sys) == 0) {
the_subsystem = pe_subsystem;
} else if (strcasecmp(CRM_SYSTEM_TENGINE, curr_client->sub_sys) == 0) {
the_subsystem = te_subsystem;
} else if (strcasecmp(CRM_SYSTEM_CIB, curr_client->sub_sys) == 0){
the_subsystem = cib_subsystem;
}
if(the_subsystem != NULL) {
the_subsystem->ipc = NULL;
the_subsystem->client = NULL;
crm_info("Received HUP from %s:[%d]",
the_subsystem->name, the_subsystem->pid);
} else {
/* else that was a transient client */
crm_debug("Received HUP from transient client");
}
if (curr_client->table_key != NULL) {
/*
* Key is destroyed below as:
* curr_client->table_key
* Value is cleaned up by:
* crmd_ipc_connection_destroy
* which will also call:
* G_main_del_IPC_Channel
*/
g_hash_table_remove(ipc_clients, curr_client->table_key);
}
}
void update_dc(HA_Message *msg, gboolean assert_same)
{
const char *dc_version = NULL;
const char *welcome_from = NULL;
if(msg != NULL) {
dc_version = cl_get_string(msg, F_CRM_VERSION);
welcome_from = cl_get_string(msg, F_CRM_HOST_FROM);
CRM_CHECK(dc_version != NULL, return);
CRM_CHECK(welcome_from != NULL, return);
if(AM_I_DC) {
CRM_CHECK(safe_str_eq(welcome_from, fsa_our_uname),
return);
}
if(assert_same) {
CRM_CHECK(fsa_our_dc != NULL, ;);
CRM_CHECK(safe_str_eq(fsa_our_dc, welcome_from), ;);
}
}
crm_free(fsa_our_dc);
crm_free(fsa_our_dc_version);
fsa_our_dc = NULL;
fsa_our_dc_version = NULL;
if(welcome_from != NULL) {
fsa_our_dc = crm_strdup(welcome_from);
}
if(dc_version != NULL) {
fsa_our_dc_version = crm_strdup(dc_version);
}
crm_info("Set DC to %s (%s)",
crm_str(fsa_our_dc), crm_str(fsa_our_dc_version));
}
diff --git a/crm/pengine/master.c b/crm/pengine/master.c
index 44b35f7727..cd935b23af 100644
--- a/crm/pengine/master.c
+++ b/crm/pengine/master.c
@@ -1,581 +1,577 @@
/* $Id: master.c,v 1.22 2006/06/07 12:46:58 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 <crm/msg_xml.h>
#include <allocate.h>
#include <lib/crm/pengine/utils.h>
#include <utils.h>
#define VARIANT_CLONE 1
#include <lib/crm/pengine/variant.h>
#define NO_MASTER_PREFS 0
extern gint sort_clone_instance(gconstpointer a, gconstpointer b);
extern void clone_create_notifications(
resource_t *rsc, action_t *action, action_t *action_complete,
pe_working_set_t *data_set);
static void
child_promoting_constraints(
clone_variant_data_t *clone_data, enum pe_ordering type,
resource_t *child, resource_t *last, pe_working_set_t *data_set)
{
/* if(clone_data->ordered */
/* || clone_data->self->restart_type == pe_restart_restart) { */
/* type = pe_order_implies_left; */
/* } */
if(child == NULL) {
if(clone_data->ordered && last != NULL) {
crm_debug_4("Ordered version (last node)");
/* last child promote before promoted started */
custom_action_order(
last, promote_key(last), NULL,
clone_data->self, promoted_key(clone_data->self), NULL,
type, data_set);
}
} else if(clone_data->ordered) {
crm_debug_4("Ordered version");
if(last == NULL) {
/* global promote before first child promote */
last = clone_data->self;
} /* else: child/child relative promote */
order_start_start(last, child, type);
custom_action_order(
last, promote_key(last), NULL,
child, promote_key(child), NULL,
type, data_set);
} else {
crm_debug_4("Un-ordered version");
/* child promote before global promoted */
custom_action_order(
child, promote_key(child), NULL,
clone_data->self, promoted_key(clone_data->self), NULL,
type, data_set);
/* global promote before child promote */
custom_action_order(
clone_data->self, promote_key(clone_data->self), NULL,
child, promote_key(child), NULL,
type, data_set);
}
}
static void
child_demoting_constraints(
clone_variant_data_t *clone_data, enum pe_ordering type,
resource_t *child, resource_t *last, pe_working_set_t *data_set)
{
/* if(clone_data->ordered */
/* || clone_data->self->restart_type == pe_restart_restart) { */
/* type = pe_order_implies_left; */
/* } */
if(child == NULL) {
if(clone_data->ordered && last != NULL) {
crm_debug_4("Ordered version (last node)");
/* global demote before first child demote */
custom_action_order(
clone_data->self, demote_key(clone_data->self), NULL,
last, demote_key(last), NULL,
pe_order_implies_left, data_set);
}
} else if(clone_data->ordered && last != NULL) {
crm_debug_4("Ordered version");
/* child/child relative demote */
custom_action_order(child, demote_key(child), NULL,
last, demote_key(last), NULL,
type, data_set);
} else if(clone_data->ordered) {
crm_debug_4("Ordered version (1st node)");
/* first child stop before global stopped */
custom_action_order(
child, demote_key(child), NULL,
clone_data->self, demoted_key(clone_data->self), NULL,
type, data_set);
} else {
crm_debug_4("Un-ordered version");
/* child demote before global demoted */
custom_action_order(
child, demote_key(child), NULL,
clone_data->self, demoted_key(clone_data->self), NULL,
type, data_set);
/* global demote before child demote */
custom_action_order(
clone_data->self, demote_key(clone_data->self), NULL,
child, demote_key(child), NULL,
type, data_set);
}
}
static void
master_update_pseudo_status(
resource_t *child, gboolean *demoting, gboolean *promoting)
{
CRM_ASSERT(demoting != NULL);
CRM_ASSERT(promoting != NULL);
slist_iter(
action, action_t, child->actions, lpc,
if(*promoting && *demoting) {
return;
} else if(action->optional) {
continue;
} else if(safe_str_eq(CRMD_ACTION_DEMOTE, action->task)) {
*demoting = TRUE;
} else if(safe_str_eq(CRMD_ACTION_PROMOTE, action->task)) {
*promoting = TRUE;
}
);
}
#define apply_master_location(list) \
slist_iter( \
cons, rsc_to_node_t, list, lpc2, \
cons_node = NULL; \
if(cons->role_filter == RSC_ROLE_MASTER) { \
crm_debug("Applying %s to %s", \
cons->id, child_rsc->id); \
cons_node = pe_find_node_id( \
cons->node_list_rh, chosen->details->id); \
} \
if(cons_node != NULL) { \
int new_priority = merge_weights( \
child_rsc->priority, cons_node->weight); \
crm_debug("\t%s: %d->%d", child_rsc->id, \
child_rsc->priority, new_priority); \
child_rsc->priority = new_priority; \
} \
);
#define apply_master_colocation(list) \
slist_iter( \
cons, rsc_colocation_t, list, lpc2, \
cons_node = cons->rsc_lh->allocated_to; \
if(cons->role_lh == RSC_ROLE_MASTER \
&& cons_node != NULL \
&& chosen->details == cons_node->details) { \
int new_priority = merge_weights( \
child_rsc->priority, cons->score); \
crm_debug("Applying %s to %s", \
cons->id, child_rsc->id); \
crm_debug("\t%s: %d->%d", child_rsc->id, \
child_rsc->priority, new_priority); \
child_rsc->priority = new_priority; \
} \
);
static node_t *
can_be_master(resource_t *rsc)
{
node_t *node = NULL;
node_t *local_node = NULL;
clone_variant_data_t *clone_data = NULL;
node = rsc->allocated_to;
if(rsc->priority < 0) {
crm_debug_2("%s cannot be master: preference",
rsc->id);
return NULL;
} else if(node == NULL) {
crm_debug_2("%s cannot be master: not allocated",
rsc->id);
return NULL;
} else if(can_run_resources(node) == FALSE) {
crm_debug_2("Node cant run any resources: %s",
node->details->uname);
return NULL;
}
get_clone_variant_data(clone_data, rsc->parent);
local_node = pe_find_node_id(
clone_data->self->allowed_nodes, node->details->id);
if(local_node == NULL) {
crm_err("%s cannot run on %s: node not allowed",
rsc->id, node->details->uname);
return NULL;
} else if(local_node->count < clone_data->master_node_max) {
return local_node;
} else {
crm_debug_2("%s cannot be master on %s: node full",
rsc->id, node->details->uname);
}
return NULL;
}
static gint sort_master_instance(gconstpointer a, gconstpointer b)
{
int rc;
const resource_t *resource1 = (const resource_t*)a;
const resource_t *resource2 = (const resource_t*)b;
CRM_ASSERT(resource1 != NULL);
CRM_ASSERT(resource2 != NULL);
rc = sort_rsc_priority(a, b);
if( rc != 0 ) {
return rc;
}
if(resource1->role > resource2->role) {
return -1;
} else if(resource1->role < resource2->role) {
return 1;
}
return sort_clone_instance(a, b);
}
node_t *
master_color(resource_t *rsc, pe_working_set_t *data_set)
{
int len = 0;
int promoted = 0;
node_t *chosen = NULL;
node_t *cons_node = NULL;
char *attr_name = NULL;
const char *attr_value = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
clone_color(rsc, data_set);
/* count now tracks the number of masters allocated */
slist_iter(node, node_t, clone_data->self->allowed_nodes, lpc,
node->count = 0;
);
/*
* assign priority
*/
slist_iter(
child_rsc, resource_t, clone_data->child_list, lpc,
crm_debug_2("Assigning priority for %s", child_rsc->id);
chosen = child_rsc->allocated_to;
if(chosen == NULL) {
continue;
} else if(child_rsc->role == RSC_ROLE_STARTED) {
child_rsc->role = RSC_ROLE_SLAVE;
}
switch(child_rsc->next_role) {
case RSC_ROLE_STARTED:
if(NO_MASTER_PREFS) {
child_rsc->priority =
clone_data->clone_max - lpc;
break;
}
child_rsc->priority = -1;
CRM_CHECK(chosen != NULL, break);
len = 8 + strlen(child_rsc->id);
crm_malloc0(attr_name, len);
sprintf(attr_name, "master-%s", child_rsc->id);
crm_debug_2("looking for %s on %s", attr_name,
chosen->details->uname);
attr_value = g_hash_table_lookup(
chosen->details->attrs, attr_name);
if(attr_value == NULL) {
crm_free(attr_name);
len = 8 + strlen(child_rsc->long_name);
crm_malloc0(attr_name, len);
sprintf(attr_name, "master-%s", child_rsc->long_name);
crm_debug_2("looking for %s on %s", attr_name,
chosen->details->uname);
attr_value = g_hash_table_lookup(
chosen->details->attrs, attr_name);
}
if(attr_value != NULL) {
crm_debug("%s=%s for %s", attr_name,
crm_str(attr_value),
chosen->details->uname);
child_rsc->priority = char2score(
attr_value);
}
crm_free(attr_name);
break;
case RSC_ROLE_SLAVE:
case RSC_ROLE_STOPPED:
child_rsc->priority = -INFINITY;
break;
case RSC_ROLE_MASTER:
/* the only reason we should be here is if
* we're re-creating actions after a stonith
*/
promoted++;
break;
default:
CRM_CHECK(FALSE/* unhandled */,
crm_err("Unknown resource role: %d for %s",
child_rsc->next_role, child_rsc->id));
}
apply_master_location(child_rsc->rsc_location);
apply_master_location(rsc->rsc_location);
apply_master_colocation(rsc->rsc_cons);
apply_master_colocation(child_rsc->rsc_cons);
);
/* sort based on the new "promote" priority */
clone_data->child_list = g_list_sort(
clone_data->child_list, sort_master_instance);
/* mark the first N as masters */
slist_iter(
child_rsc, resource_t, clone_data->child_list, lpc,
chosen = NULL;
crm_debug_2("Processing %s", child_rsc->id);
if(promoted < clone_data->master_max) {
chosen = can_be_master(child_rsc);
}
if(chosen == NULL) {
if(child_rsc->next_role == RSC_ROLE_STARTED) {
child_rsc->next_role = RSC_ROLE_SLAVE;
}
continue;
}
chosen->count++;
crm_info("Promoting %s", child_rsc->id);
child_rsc->next_role = RSC_ROLE_MASTER;
promoted++;
add_hash_param(child_rsc->parameters, crm_meta_name("role"),
role2text(child_rsc->next_role));
);
crm_info("Promoted %d instances of a possible %d to master", promoted, clone_data->master_max);
return NULL;
}
void master_create_actions(resource_t *rsc, pe_working_set_t *data_set)
{
action_t *action = NULL;
action_t *action_complete = NULL;
gboolean any_promoting = FALSE;
gboolean any_demoting = FALSE;
resource_t *last_promote_rsc = NULL;
resource_t *last_demote_rsc = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
crm_debug("Creating actions for %s", rsc->id);
/* create actions as normal */
clone_create_actions(rsc, data_set);
slist_iter(
child_rsc, resource_t, clone_data->child_list, lpc,
gboolean child_promoting = FALSE;
gboolean child_demoting = FALSE;
crm_debug_2("Creating actions for %s", child_rsc->id);
child_rsc->cmds->create_actions(child_rsc, data_set);
master_update_pseudo_status(
child_rsc, &child_demoting, &child_promoting);
any_demoting = any_demoting || child_demoting;
any_promoting = any_promoting || child_promoting;
);
/* promote */
action = promote_action(clone_data->self, NULL, !any_promoting);
action_complete = custom_action(
clone_data->self, promoted_key(rsc),
CRMD_ACTION_PROMOTED, NULL, !any_promoting, TRUE, data_set);
action->pseudo = TRUE;
action->runnable = TRUE;
action_complete->pseudo = TRUE;
action_complete->runnable = TRUE;
action_complete->priority = INFINITY;
child_promoting_constraints(clone_data, pe_order_optional,
NULL, last_promote_rsc, data_set);
clone_create_notifications(rsc, action, action_complete, data_set);
/* demote */
action = demote_action(clone_data->self, NULL, !any_demoting);
action_complete = custom_action(
clone_data->self, demoted_key(rsc),
CRMD_ACTION_DEMOTED, NULL, !any_demoting, TRUE, data_set);
action_complete->priority = INFINITY;
action->pseudo = TRUE;
action->runnable = TRUE;
action_complete->pseudo = TRUE;
action_complete->runnable = TRUE;
child_demoting_constraints(clone_data, pe_order_optional,
NULL, last_demote_rsc, data_set);
clone_create_notifications(rsc, action, action_complete, data_set);
}
void
master_internal_constraints(resource_t *rsc, pe_working_set_t *data_set)
{
resource_t *last_rsc = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
clone_internal_constraints(rsc, data_set);
/* global demoted before start */
custom_action_order(
clone_data->self, demoted_key(clone_data->self), NULL,
clone_data->self, start_key(clone_data->self), NULL,
pe_order_optional, data_set);
/* global started before promote */
custom_action_order(
clone_data->self, started_key(clone_data->self), NULL,
clone_data->self, promote_key(clone_data->self), NULL,
pe_order_optional, data_set);
/* global demoted before stop */
custom_action_order(
clone_data->self, demoted_key(clone_data->self), NULL,
clone_data->self, stop_key(clone_data->self), NULL,
pe_order_optional, data_set);
/* global demote before demoted */
custom_action_order(
clone_data->self, demote_key(clone_data->self), NULL,
clone_data->self, demoted_key(clone_data->self), NULL,
pe_order_optional, data_set);
/* global demoted before promote */
custom_action_order(
clone_data->self, demoted_key(clone_data->self), NULL,
clone_data->self, promote_key(clone_data->self), NULL,
pe_order_internal_restart, data_set);
slist_iter(
child_rsc, resource_t, clone_data->child_list, lpc,
/* child demote before promote */
custom_action_order(
child_rsc, demote_key(child_rsc), NULL,
child_rsc, promote_key(child_rsc), NULL,
pe_order_internal_restart, data_set);
child_promoting_constraints(clone_data, pe_order_optional,
child_rsc, last_rsc, data_set);
child_demoting_constraints(clone_data, pe_order_optional,
child_rsc, last_rsc, data_set);
last_rsc = child_rsc;
);
}
void master_rsc_colocation_rh(
resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
{
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc_rh);
if(rsc_rh->provisional) {
return;
- } else if(rsc_rh == NULL) {
- pe_err("rsc_rh was NULL for %s", constraint->id);
- return;
-
} else if(constraint->role_rh == RSC_ROLE_UNKNOWN) {
crm_debug_3("Handling %s as a clone colocation", constraint->id);
clone_rsc_colocation_rh(rsc_lh, rsc_rh, constraint);
return;
}
CRM_CHECK(rsc_lh != NULL, return);
CRM_CHECK(rsc_lh->variant == pe_native, return);
crm_debug_3("Processing constraint %s: %d", constraint->id, constraint->score);
if(constraint->score < INFINITY) {
slist_iter(
child_rsc, resource_t, clone_data->child_list, lpc,
child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint);
);
} else {
GListPtr lhs = NULL, rhs = NULL;
lhs = rsc_lh->allowed_nodes;
slist_iter(
child_rsc, resource_t, clone_data->child_list, lpc,
if(child_rsc->allocated_to != NULL
&& child_rsc->next_role == constraint->role_rh) {
rhs = g_list_append(rhs, child_rsc->allocated_to);
}
);
rsc_lh->allowed_nodes = node_list_and(lhs, rhs, FALSE);
pe_free_shallow_adv(rhs, FALSE);
pe_free_shallow(lhs);
}
return;
}
diff --git a/crm/pengine/native.c b/crm/pengine/native.c
index 381925495f..0455fa8be3 100644
--- a/crm/pengine/native.c
+++ b/crm/pengine/native.c
@@ -1,1610 +1,1612 @@
/* $Id: native.c,v 1.161 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 <pengine.h>
#include <crm/pengine/rules.h>
#include <lib/crm/pengine/utils.h>
#include <crm/msg_xml.h>
#include <allocate.h>
#include <utils.h>
#define DELETE_THEN_REFRESH 1
#define VARIANT_NATIVE 1
#include <lib/crm/pengine/variant.h>
resource_t *ultimate_parent(resource_t *rsc);
void node_list_update(GListPtr list1, GListPtr list2, int factor);
void native_rsc_colocation_rh_must(resource_t *rsc_lh, gboolean update_lh,
resource_t *rsc_rh, gboolean update_rh);
void native_rsc_colocation_rh_mustnot(resource_t *rsc_lh, gboolean update_lh,
resource_t *rsc_rh, gboolean update_rh);
void create_notifications(resource_t *rsc, pe_working_set_t *data_set);
void Recurring(resource_t *rsc, action_t *start, node_t *node,
pe_working_set_t *data_set);
void pe_pre_notify(
resource_t *rsc, node_t *node, action_t *op,
notify_data_t *n_data, pe_working_set_t *data_set);
void pe_post_notify(
resource_t *rsc, node_t *node, action_t *op,
notify_data_t *n_data, pe_working_set_t *data_set);
gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set);
void NoRoleChange(resource_t *rsc, node_t *current, node_t *next, pe_working_set_t *data_set);
gboolean StopRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
gboolean StartRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
extern gboolean DemoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
gboolean PromoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
gboolean RoleError(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
gboolean NullOp(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
enum rsc_role_e rsc_state_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX] = {
/* Current State */
/* Next State: Unknown Stopped Started Slave Master */
/* Unknown */ { RSC_ROLE_UNKNOWN, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, },
/* Stopped */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_SLAVE, },
/* Started */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, },
/* Slave */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, },
/* Master */ { RSC_ROLE_STOPPED, RSC_ROLE_SLAVE, RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, },
};
gboolean (*rsc_action_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX])(resource_t*,node_t*,pe_working_set_t*) = {
/* Current State */
/* Next State: Unknown Stopped Started Slave Master */
/* Unknown */ { RoleError, StopRsc, RoleError, RoleError, RoleError, },
/* Stopped */ { RoleError, NullOp, StartRsc, StartRsc, RoleError, },
/* Started */ { RoleError, StopRsc, NullOp, NullOp, PromoteRsc, },
/* Slave */ { RoleError, StopRsc, RoleError, NullOp, PromoteRsc, },
/* Master */ { RoleError, RoleError, RoleError, DemoteRsc, NullOp, },
};
static gboolean
native_choose_node(resource_t *rsc)
{
/*
1. Sort by weight
2. color.chosen_node = the node (of those with the highest wieght)
with the fewest resources
3. remove color.chosen_node from all other colors
*/
GListPtr nodes = NULL;
node_t *chosen = NULL;
if(rsc->provisional == FALSE) {
return rsc->allocated_to?TRUE:FALSE;
}
crm_debug_3("Choosing node for %s from %d candidates",
rsc->id, g_list_length(rsc->allowed_nodes));
if(rsc->allowed_nodes) {
rsc->allowed_nodes = g_list_sort(
rsc->allowed_nodes, sort_node_weight);
nodes = rsc->allowed_nodes;
chosen = g_list_nth_data(nodes, 0);
}
return native_assign_node(rsc, nodes, chosen);
}
void native_set_cmds(resource_t *rsc)
{
}
int native_num_allowed_nodes(resource_t *rsc)
{
int num_nodes = 0;
if(rsc->next_role == RSC_ROLE_STOPPED) {
return 0;
}
crm_debug_4("Default case");
slist_iter(
this_node, node_t, rsc->allowed_nodes, lpc,
crm_debug_3("Rsc %s Checking %s: %d",
rsc->id, this_node->details->uname,
this_node->weight);
if(this_node->details->shutdown
|| this_node->details->online == FALSE) {
this_node->weight = -INFINITY;
}
if(this_node->weight < 0) {
continue;
/* } else if(this_node->details->unclean) { */
/* continue; */
}
num_nodes++;
);
crm_debug_2("Resource %s can run on %d nodes", rsc->id, num_nodes);
return num_nodes;
}
resource_t *
ultimate_parent(resource_t *rsc)
{
resource_t *parent = rsc;
while(parent->parent) {
parent = parent->parent;
}
return parent;
}
node_t *
native_color(resource_t *rsc, pe_working_set_t *data_set)
{
if(rsc->parent && rsc->parent->is_allocating == FALSE) {
/* never allocate children on their own */
crm_debug("Escalating allocation of %s to its parent: %s",
rsc->id, rsc->parent->id);
rsc->parent->cmds->color(rsc->parent, data_set);
}
print_resource(LOG_DEBUG_2, "Allocating: ", rsc, FALSE);
if(rsc->provisional == FALSE) {
return rsc->allocated_to;
}
if(rsc->is_allocating) {
crm_debug("Dependancy loop detected involving %s", rsc->id);
return NULL;
}
rsc->is_allocating = TRUE;
rsc->rsc_cons = g_list_sort(rsc->rsc_cons, sort_cons_strength);
slist_iter(
constraint, rsc_colocation_t, rsc->rsc_cons, lpc,
crm_debug_3("%s: Pre-Processing %s", rsc->id, constraint->id);
if(rsc->provisional && constraint->rsc_rh->provisional) {
crm_info("Combine scores from %s and %s",
rsc->id, constraint->rsc_rh->id);
node_list_update(constraint->rsc_rh->allowed_nodes,
rsc->allowed_nodes,
constraint->score/INFINITY);
}
constraint->rsc_rh->cmds->color(
constraint->rsc_rh, data_set);
rsc->cmds->rsc_colocation_lh(
rsc, constraint->rsc_rh, constraint);
);
print_resource(LOG_DEBUG, "Allocating: ", rsc, FALSE);
if(rsc->next_role == RSC_ROLE_STOPPED) {
crm_debug_2("Making sure %s doesn't get allocated", rsc->id);
/* make sure it doesnt come up again */
resource_location(
rsc, NULL, -INFINITY, "target_role", data_set);
}
if(rsc->provisional && native_choose_node(rsc) ) {
crm_debug_3("Allocated resource %s to %s",
rsc->id, rsc->allocated_to->details->uname);
} else if(rsc->allocated_to == NULL) {
if(rsc->orphan == FALSE) {
pe_warn("Resource %s cannot run anywhere", rsc->id);
} else {
crm_info("Stopping orphan resource %s", rsc->id);
}
} else {
crm_debug("Pre-Allocated resource %s to %s",
rsc->id, rsc->allocated_to->details->uname);
}
rsc->is_allocating = FALSE;
print_resource(LOG_DEBUG_3, "Allocated ", rsc, TRUE);
return rsc->allocated_to;
}
void
Recurring(resource_t *rsc, action_t *start, node_t *node,
pe_working_set_t *data_set)
{
char *key = NULL;
const char *name = NULL;
const char *value = NULL;
const char *interval = NULL;
const char *node_uname = NULL;
int interval_ms = 0;
action_t *mon = NULL;
gboolean is_optional = TRUE;
GListPtr possible_matches = NULL;
crm_debug_2("Creating recurring actions for %s", rsc->id);
if(node != NULL) {
node_uname = node->details->uname;
}
xml_child_iter_filter(
rsc->ops_xml, operation, "op",
is_optional = TRUE;
name = crm_element_value(operation, "name");
interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
interval_ms = crm_get_msec(interval);
if(interval_ms <= 0) {
continue;
}
value = crm_element_value(operation, "disabled");
if(crm_is_true(value)) {
continue;
}
key = generate_op_key(rsc->id, name, interval_ms);
if(start != NULL) {
crm_debug_3("Marking %s %s due to %s",
key, start->optional?"optional":"manditory",
start->uuid);
is_optional = start->optional;
} else {
crm_debug_2("Marking %s optional", key);
is_optional = TRUE;
}
/* start a monitor for an already active resource */
possible_matches = find_actions_exact(rsc->actions, key, node);
if(possible_matches == NULL) {
is_optional = FALSE;
crm_debug_3("Marking %s manditory: not active", key);
}
value = crm_element_value(operation, "role");
if((rsc->next_role == RSC_ROLE_MASTER && value == NULL)
|| (value != NULL && text2role(value) != rsc->next_role)) {
int log_level = LOG_DEBUG_2;
const char *foo = "Ignoring";
if(is_optional) {
char *local_key = crm_strdup(key);
log_level = LOG_INFO;
foo = "Cancelling";
/* its running : cancel it */
mon = custom_action(
rsc, local_key, CRMD_ACTION_CANCEL, node,
FALSE, TRUE, data_set);
mon->task = CRMD_ACTION_CANCEL;
add_hash_param(mon->meta, XML_LRM_ATTR_INTERVAL, interval);
add_hash_param(mon->meta, XML_LRM_ATTR_TASK, name);
custom_action_order(
rsc, NULL, mon,
rsc, promote_key(rsc), NULL,
pe_order_optional, data_set);
mon = NULL;
}
do_crm_log(log_level, "%s action %s (%s vs. %s)",
foo , key, value?value:role2text(RSC_ROLE_SLAVE),
role2text(rsc->next_role));
crm_free(key);
key = NULL;
continue;
}
mon = custom_action(rsc, key, name, node,
is_optional, TRUE, data_set);
if(is_optional) {
crm_debug("%s\t %s (optional)",
crm_str(node_uname), mon->uuid);
}
if(start == NULL || start->runnable == FALSE) {
crm_debug("%s\t %s (cancelled : start un-runnable)",
crm_str(node_uname), mon->uuid);
mon->runnable = FALSE;
} else if(node == NULL
|| node->details->online == FALSE
|| node->details->unclean) {
crm_debug("%s\t %s (cancelled : no node available)",
crm_str(node_uname), mon->uuid);
mon->runnable = FALSE;
} else if(mon->optional == FALSE) {
crm_notice("%s\t %s", crm_str(node_uname),mon->uuid);
}
custom_action_order(rsc, start_key(rsc), NULL,
NULL, crm_strdup(key), mon,
pe_order_internal_restart, data_set);
if(rsc->next_role == RSC_ROLE_MASTER) {
char *running_master = crm_itoa(EXECRA_RUNNING_MASTER);
add_hash_param(mon->meta, XML_ATTR_TE_TARGET_RC, running_master);
custom_action_order(
rsc, promote_key(rsc), NULL,
rsc, NULL, mon,
pe_order_optional, data_set);
crm_free(running_master);
}
);
}
void native_create_actions(resource_t *rsc, pe_working_set_t *data_set)
{
action_t *start = NULL;
node_t *chosen = NULL;
enum rsc_role_e role = RSC_ROLE_UNKNOWN;
enum rsc_role_e next_role = RSC_ROLE_UNKNOWN;
crm_debug_2("Creating actions for %s", rsc->id);
chosen = rsc->allocated_to;
if(chosen != NULL) {
CRM_CHECK(rsc->next_role != RSC_ROLE_UNKNOWN, rsc->next_role = RSC_ROLE_STARTED);
}
unpack_instance_attributes(
rsc->xml, XML_TAG_ATTR_SETS,
chosen?chosen->details->attrs:NULL,
rsc->parameters, NULL, data_set->now);
crm_debug_2("%s: %s->%s", rsc->id,
role2text(rsc->role), role2text(rsc->next_role));
if(g_list_length(rsc->running_on) > 1) {
if(rsc->recovery_type == recovery_stop_start) {
pe_proc_err("Attempting recovery of resource %s", rsc->id);
StopRsc(rsc, NULL, data_set);
rsc->role = RSC_ROLE_STOPPED;
}
} else if(rsc->running_on != NULL) {
node_t *current = rsc->running_on->data;
NoRoleChange(rsc, current, chosen, data_set);
} else if(rsc->role == RSC_ROLE_STOPPED && rsc->next_role == RSC_ROLE_STOPPED) {
char *key = start_key(rsc);
GListPtr possible_matches = find_actions(rsc->actions, key, NULL);
slist_iter(
action, action_t, possible_matches, lpc,
action->optional = TRUE;
/* action->pseudo = TRUE; */
);
crm_debug_2("Stopping a stopped resource");
crm_free(key);
return;
}
role = rsc->role;
while(role != rsc->next_role) {
next_role = rsc_state_matrix[role][rsc->next_role];
crm_debug_2("Executing: %s->%s (%s)",
role2text(role), role2text(next_role), rsc->id);
if(rsc_action_matrix[role][next_role](
rsc, chosen, data_set) == FALSE) {
break;
}
role = next_role;
}
if(rsc->next_role != RSC_ROLE_STOPPED && rsc->is_managed) {
start = start_action(rsc, chosen, TRUE);
Recurring(rsc, start, chosen, data_set);
}
}
void native_internal_constraints(resource_t *rsc, pe_working_set_t *data_set)
{
order_restart(rsc);
custom_action_order(rsc, demote_key(rsc), NULL,
rsc, stop_key(rsc), NULL,
pe_order_implies_left, data_set);
custom_action_order(rsc, start_key(rsc), NULL,
rsc, promote_key(rsc), NULL,
pe_order_optional, data_set);
custom_action_order(
rsc, stop_key(rsc), NULL, rsc, delete_key(rsc), NULL,
pe_order_optional, data_set);
custom_action_order(
rsc, delete_key(rsc), NULL, rsc, start_key(rsc), NULL,
pe_order_implies_left, data_set);
if(rsc->notify) {
char *key1 = NULL;
char *key2 = NULL;
key1 = generate_op_key(rsc->id, "confirmed-post_notify_start", 0);
key2 = generate_op_key(rsc->id, "pre_notify_promote", 0);
custom_action_order(
rsc, key1, NULL, rsc, key2, NULL,
pe_order_optional, data_set);
key1 = generate_op_key(rsc->id, "confirmed-post_notify_demote", 0);
key2 = generate_op_key(rsc->id, "pre_notify_stop", 0);
custom_action_order(
rsc, key1, NULL, rsc, key2, NULL,
pe_order_optional, data_set);
}
}
void native_rsc_colocation_lh(
resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
{
if(rsc_lh == NULL) {
pe_err("rsc_lh was NULL for %s", constraint->id);
return;
} else if(constraint->rsc_rh == NULL) {
pe_err("rsc_rh was NULL for %s", constraint->id);
return;
}
crm_debug_2("Processing colocation constraint between %s and %s",
rsc_lh->id, rsc_rh->id);
rsc_rh->cmds->rsc_colocation_rh(rsc_lh, rsc_rh, constraint);
}
static gboolean
filter_colocation_constraint(
resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
{
if(constraint->score == 0){
return FALSE;
}
if(constraint->role_lh != RSC_ROLE_UNKNOWN
&& constraint->role_lh != rsc_lh->next_role) {
crm_debug_4("RH: Skipping constraint: \"%s\" state filter",
role2text(constraint->role_rh));
return FALSE;
}
if(constraint->role_rh != RSC_ROLE_UNKNOWN
&& constraint->role_rh != rsc_rh->next_role) {
crm_debug_4("RH: Skipping constraint: \"%s\" state filter",
role2text(constraint->role_rh));
return FALSE;
}
return TRUE;
}
static void
colocation_match(
resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
{
const char *tmp = NULL;
const char *value = NULL;
gboolean do_check = FALSE;
const char *attribute = "#id";
if(constraint->node_attribute != NULL) {
attribute = constraint->node_attribute;
}
if(rsc_rh->allocated_to) {
value = g_hash_table_lookup(
rsc_rh->allocated_to->details->attrs, attribute);
do_check = TRUE;
}
slist_iter(
node, node_t, rsc_lh->allowed_nodes, lpc,
tmp = g_hash_table_lookup(node->details->attrs, attribute);
if(do_check && safe_str_eq(tmp, value)) {
crm_debug_2("%s: %s.%s += %d", constraint->id, rsc_lh->id,
node->details->uname, constraint->score);
node->weight = merge_weights(
constraint->score, node->weight);
} else if(do_check == FALSE || constraint->score >= INFINITY) {
crm_debug_2("%s: %s.%s = -INFINITY (%s)", constraint->id, rsc_lh->id,
node->details->uname, do_check?"failed":"unallocated");
node->weight = -INFINITY;
}
);
}
void native_rsc_colocation_rh(
resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
{
crm_debug_2("%sColocating %s with %s (%s, weight=%d)",
constraint->score >= 0?"":"Anti-",
rsc_lh->id, rsc_rh->id, constraint->id, constraint->score);
if(filter_colocation_constraint(rsc_lh, rsc_rh, constraint) == FALSE) {
return;
}
if(rsc_rh->provisional) {
return;
} else if(rsc_lh->provisional == FALSE) {
/* error check */
struct node_shared_s *details_lh;
struct node_shared_s *details_rh;
if((constraint->score > -INFINITY) && (constraint->score < INFINITY)) {
return;
}
details_rh = rsc_rh->allocated_to?rsc_rh->allocated_to->details:NULL;
details_lh = rsc_lh->allocated_to?rsc_lh->allocated_to->details:NULL;
if(constraint->score == INFINITY && details_lh != details_rh) {
crm_err("%s and %s are both allocated"
" but to different nodes: %s vs. %s",
rsc_lh->id, rsc_rh->id,
details_lh?details_lh->uname:"n/a",
details_rh?details_rh->uname:"n/a");
} else if(constraint->score == -INFINITY && details_lh == details_rh) {
crm_err("%s and %s are both allocated"
" but to the SAME node: %s",
rsc_lh->id, rsc_rh->id,
details_rh?details_rh->uname:"n/a");
}
return;
} else {
colocation_match(rsc_lh, rsc_rh, constraint);
}
}
void
node_list_update(GListPtr list1, GListPtr list2, int factor)
{
node_t *other_node = NULL;
slist_iter(
node, node_t, list1, lpc,
if(node == NULL) {
continue;
}
other_node = (node_t*)pe_find_node_id(
list2, node->details->id);
if(other_node != NULL) {
crm_debug_2("%s: %d + %d",
node->details->uname,
node->weight, other_node->weight);
node->weight = merge_weights(
factor*other_node->weight, node->weight);
}
);
}
void native_rsc_order_lh(resource_t *lh_rsc, order_constraint_t *order)
{
GListPtr lh_actions = NULL;
action_t *lh_action = order->lh_action;
crm_debug_3("Processing LH of ordering constraint %d", order->id);
if(lh_action != NULL) {
lh_actions = g_list_append(NULL, lh_action);
} else if(lh_action == NULL && lh_rsc != NULL) {
lh_actions = find_actions(
lh_rsc->actions, order->lh_action_task, NULL);
if(lh_actions == NULL) {
crm_debug_4("No LH-Side (%s/%s) found for constraint",
lh_rsc->id, order->lh_action_task);
if(lh_rsc->next_role == RSC_ROLE_STOPPED) {
resource_t *rh_rsc = order->rh_rsc;
if(order->rh_action
&& (order->type & pe_order_internal_restart)) {
crm_debug_3("No LH(%s/%s) found for RH(%s)...",
lh_rsc->id, order->lh_action_task,
order->rh_action->uuid);
order->rh_action->runnable = FALSE;
return;
} else if(rh_rsc != NULL) {
crm_debug_3("No LH(%s/%s) found for RH(%s/%s)...",
lh_rsc->id, order->lh_action_task,
rh_rsc->id, order->rh_action_task);
rh_rsc->cmds->rsc_order_rh(NULL, rh_rsc, order);
return;
}
}
return;
}
} else {
pe_warn("No LH-Side (%s) specified for constraint",
order->lh_action_task);
if(order->rh_rsc != NULL) {
crm_debug_4("RH-Side was: (%s/%s)",
order->rh_rsc->id,
order->rh_action_task);
} else if(order->rh_action != NULL
&& order->rh_action->rsc != NULL) {
crm_debug_4("RH-Side was: (%s/%s)",
order->rh_action->rsc->id,
order->rh_action_task);
} else if(order->rh_action != NULL) {
crm_debug_4("RH-Side was: %s",
order->rh_action_task);
} else {
crm_debug_4("RH-Side was NULL");
}
return;
}
slist_iter(
lh_action_iter, action_t, lh_actions, lpc,
resource_t *rh_rsc = order->rh_rsc;
if(rh_rsc == NULL && order->rh_action) {
rh_rsc = order->rh_action->rsc;
}
if(rh_rsc) {
rh_rsc->cmds->rsc_order_rh(
lh_action_iter, rh_rsc, order);
} else if(order->rh_action) {
order_actions(lh_action_iter, order->rh_action, order->type);
}
);
pe_free_shallow_adv(lh_actions, FALSE);
}
void native_rsc_order_rh(
action_t *lh_action, resource_t *rsc, order_constraint_t *order)
{
GListPtr rh_actions = NULL;
action_t *rh_action = NULL;
CRM_CHECK(rsc != NULL, return);
CRM_CHECK(order != NULL, return);
CRM_CHECK(lh_action != NULL, return);
rh_action = order->rh_action;
crm_debug_3("Processing RH of ordering constraint %d", order->id);
if(rh_action != NULL) {
rh_actions = g_list_append(NULL, rh_action);
} else if(rh_action == NULL && rsc != NULL) {
rh_actions = find_actions(
rsc->actions, order->rh_action_task, NULL);
if(rh_actions == NULL) {
crm_debug_4("No RH-Side (%s/%s) found for constraint..."
" ignoring", rsc->id, order->rh_action_task);
crm_debug_4("LH-Side was: %s", lh_action->uuid);
return;
}
} else if(rh_action == NULL) {
crm_debug_4("No RH-Side (%s) specified for constraint..."
" ignoring", order->rh_action_task);
crm_debug_4("LH-Side was: %s", lh_action->uuid);
return;
}
slist_iter(
rh_action_iter, action_t, rh_actions, lpc,
if(lh_action) {
order_actions(lh_action, rh_action_iter, order->type);
} else if(order->type & pe_order_internal_restart) {
rh_action_iter->runnable = FALSE;
}
);
pe_free_shallow_adv(rh_actions, FALSE);
}
void native_rsc_location(resource_t *rsc, rsc_to_node_t *constraint)
{
GListPtr or_list;
crm_debug_2("Applying %s (%s) to %s", constraint->id,
role2text(constraint->role_filter), rsc->id);
/* take "lifetime" into account */
if(constraint == NULL) {
pe_err("Constraint is NULL");
return;
} else if(rsc == NULL) {
pe_err("LHS of rsc_to_node (%s) is NULL", constraint->id);
return;
} else if(constraint->role_filter > 0
&& constraint->role_filter != rsc->next_role) {
crm_debug("Constraint (%s) is not active (role : %s)",
constraint->id, role2text(constraint->role_filter));
return;
} else if(is_active(constraint) == FALSE) {
crm_debug_2("Constraint (%s) is not active", constraint->id);
return;
}
if(constraint->node_list_rh == NULL) {
crm_debug_2("RHS of constraint %s is NULL", constraint->id);
return;
}
or_list = node_list_or(
rsc->allowed_nodes, constraint->node_list_rh, FALSE);
pe_free_shallow(rsc->allowed_nodes);
rsc->allowed_nodes = or_list;
slist_iter(node, node_t, or_list, lpc,
crm_debug_3("%s + %s : %d", rsc->id, node->details->uname, node->weight);
);
}
void native_expand(resource_t *rsc, pe_working_set_t *data_set)
{
slist_iter(
action, action_t, rsc->actions, lpc,
crm_debug_4("processing action %d for rsc=%s",
action->id, rsc->id);
graph_element_from_action(action, data_set);
);
}
void
native_agent_constraints(resource_t *rsc)
{
}
void
create_notifications(resource_t *rsc, pe_working_set_t *data_set)
{
if(rsc->notify == FALSE) {
return;
}
/* slist_iter( */
/* action, action_t, rsc->actions, lpc, */
/* ); */
}
static void
register_activity(resource_t *rsc, enum action_tasks task, node_t *node, notify_data_t *n_data)
{
notify_entry_t *entry = NULL;
crm_malloc0(entry, sizeof(notify_entry_t));
entry->rsc = rsc;
entry->node = node;
switch(task) {
case start_rsc:
n_data->start = g_list_append(n_data->start, entry);
break;
case stop_rsc:
n_data->stop = g_list_append(n_data->stop, entry);
break;
case action_promote:
n_data->promote = g_list_append(n_data->promote, entry);
break;
case action_demote:
n_data->demote = g_list_append(n_data->demote, entry);
break;
default:
crm_err("Unsupported notify action: %s", task2text(task));
+ crm_free(entry);
break;
}
}
static void
register_state(resource_t *rsc, node_t *on_node, notify_data_t *n_data)
{
notify_entry_t *entry = NULL;
crm_malloc0(entry, sizeof(notify_entry_t));
entry->rsc = rsc;
entry->node = on_node;
crm_debug_2("%s state: %s", rsc->id, role2text(rsc->next_role));
switch(rsc->next_role) {
case RSC_ROLE_STOPPED:
/* n_data->inactive = g_list_append(n_data->inactive, entry); */
crm_free(entry);
break;
case RSC_ROLE_STARTED:
n_data->active = g_list_append(n_data->active, entry);
break;
case RSC_ROLE_SLAVE:
n_data->slave = g_list_append(n_data->slave, entry);
break;
case RSC_ROLE_MASTER:
n_data->master = g_list_append(n_data->master, entry);
break;
default:
crm_err("Unsupported notify role");
+ crm_free(entry);
break;
}
}
void
native_create_notify_element(resource_t *rsc, action_t *op,
notify_data_t *n_data, pe_working_set_t *data_set)
{
node_t *next_node = NULL;
gboolean registered = FALSE;
char *op_key = NULL;
GListPtr possible_matches = NULL;
enum action_tasks task = text2task(op->task);
if(op->pre_notify == NULL || op->post_notify == NULL) {
/* no notifications required */
crm_debug_4("No notificaitons required for %s", op->task);
return;
}
next_node = rsc->allocated_to;
op_key = generate_op_key(rsc->id, op->task, 0);
possible_matches = find_actions(rsc->actions, op_key, NULL);
crm_debug_2("Creating notificaitons for: %s (%s->%s)",
op->uuid, role2text(rsc->role), role2text(rsc->next_role));
if(rsc->role == rsc->next_role) {
register_state(rsc, next_node, n_data);
}
slist_iter(
local_op, action_t, possible_matches, lpc,
local_op->notify_keys = n_data->keys;
if(local_op->optional == FALSE) {
registered = TRUE;
register_activity(rsc, task, local_op->node, n_data);
}
);
/* stop / demote */
if(rsc->role != RSC_ROLE_STOPPED) {
if(task == stop_rsc || task == action_demote) {
slist_iter(
current_node, node_t, rsc->running_on, lpc,
pe_pre_notify(rsc, current_node, op, n_data, data_set);
if(task == action_demote || registered == FALSE) {
pe_post_notify(rsc, current_node, op, n_data, data_set);
}
);
}
}
/* start / promote */
if(rsc->next_role != RSC_ROLE_STOPPED) {
CRM_CHECK(next_node != NULL,;);
if(next_node == NULL) {
pe_proc_err("next role: %s", role2text(rsc->next_role));
} else if(task == start_rsc || task == action_promote) {
if(task != start_rsc || registered == FALSE) {
pe_pre_notify(rsc, next_node, op, n_data, data_set);
}
pe_post_notify(rsc, next_node, op, n_data, data_set);
}
}
crm_free(op_key);
pe_free_shallow_adv(possible_matches, FALSE);
}
static void dup_attr(gpointer key, gpointer value, gpointer user_data)
{
char *meta_key = crm_concat(CRM_META, key, '_');
g_hash_table_replace(user_data, meta_key, crm_strdup(value));
}
static action_t *
pe_notify(resource_t *rsc, node_t *node, action_t *op, action_t *confirm,
notify_data_t *n_data, pe_working_set_t *data_set)
{
char *key = NULL;
action_t *trigger = NULL;
const char *value = NULL;
const char *task = NULL;
if(op == NULL || confirm == NULL) {
crm_debug_2("Op=%p confirm=%p", op, confirm);
return NULL;
}
CRM_CHECK(node != NULL, return NULL);
if(node->details->online == FALSE) {
crm_info("Skipping notification for %s", rsc->id);
return NULL;
}
value = g_hash_table_lookup(op->meta, "notify_type");
task = g_hash_table_lookup(op->meta, "notify_operation");
crm_debug_2("Creating actions for %s: %s (%s-%s)",
op->uuid, rsc->id, value, task);
key = generate_notify_key(rsc->id, value, task);
trigger = custom_action(rsc, key, op->task, node,
op->optional, TRUE, data_set);
g_hash_table_foreach(op->meta, dup_attr, trigger->extra);
trigger->notify_keys = n_data->keys;
/* pseudo_notify before notify */
crm_debug_3("Ordering %s before %s (%d->%d)",
op->uuid, trigger->uuid, trigger->id, op->id);
order_actions(op, trigger, pe_order_implies_left);
value = g_hash_table_lookup(op->meta, "notify_confirm");
if(crm_is_true(value)) {
/* notify before pseudo_notified */
crm_debug_3("Ordering %s before %s (%d->%d)",
trigger->uuid, confirm->uuid,
confirm->id, trigger->id);
order_actions(trigger, confirm, pe_order_implies_left);
}
return trigger;
}
void
pe_pre_notify(resource_t *rsc, node_t *node, action_t *op,
notify_data_t *n_data, pe_working_set_t *data_set)
{
crm_debug_2("%s: %s", rsc->id, op->uuid);
pe_notify(rsc, node, op->pre_notify, op->pre_notified,
n_data, data_set);
}
void
pe_post_notify(resource_t *rsc, node_t *node, action_t *op,
notify_data_t *n_data, pe_working_set_t *data_set)
{
action_t *notify = NULL;
CRM_CHECK(op != NULL, return);
CRM_CHECK(rsc != NULL, return);
crm_debug_2("%s: %s", rsc->id, op->uuid);
notify = pe_notify(rsc, node, op->post_notify, op->post_notified,
n_data, data_set);
if(notify != NULL) {
/* crm_err("Upgrading priority for %s to INFINITY", notify->uuid); */
notify->priority = INFINITY;
}
notify = op->post_notified;
if(notify != NULL) {
slist_iter(
mon, action_t, rsc->actions, lpc,
const char *interval = g_hash_table_lookup(mon->meta, "interval");
if(interval == NULL || safe_str_eq(interval, "0")) {
crm_debug_3("Skipping %s: interval", mon->uuid);
continue;
} else if(safe_str_eq(mon->task, "cancel")) {
crm_debug_3("Skipping %s: cancel", mon->uuid);
continue;
}
order_actions(notify, mon, pe_order_optional);
);
}
}
void
NoRoleChange(resource_t *rsc, node_t *current, node_t *next,
pe_working_set_t *data_set)
{
action_t *start = NULL;
action_t *stop = NULL;
GListPtr possible_matches = NULL;
crm_debug("Executing: %s (role=%s)",rsc->id, role2text(rsc->next_role));
if(current == NULL || next == NULL) {
return;
}
/* use StartRsc/StopRsc */
if(safe_str_neq(current->details->id, next->details->id)) {
crm_notice("Move resource %s\t(%s -> %s)", rsc->id,
current->details->uname, next->details->uname);
stop = stop_action(rsc, current, FALSE);
start = start_action(rsc, next, FALSE);
possible_matches = find_recurring_actions(rsc->actions, next);
slist_iter(match, action_t, possible_matches, lpc,
if(match->optional == FALSE) {
crm_err("Found bad recurring action: %s",
match->uuid);
match->optional = TRUE;
}
);
if(data_set->remove_after_stop) {
DeleteRsc(rsc, current, data_set);
}
} else {
if(rsc->failed) {
crm_notice("Recover resource %s\t(%s)",
rsc->id, next->details->uname);
stop = stop_action(rsc, current, FALSE);
start = start_action(rsc, next, FALSE);
/* /\* make the restart required *\/ */
/* order_stop_start(rsc, rsc, pe_order_implies_left); */
} else if(rsc->start_pending) {
start = start_action(rsc, next, TRUE);
if(start->runnable) {
/* wait for StartRsc() to be called */
rsc->role = RSC_ROLE_STOPPED;
} else {
/* wait for StopRsc() to be called */
rsc->next_role = RSC_ROLE_STOPPED;
}
} else {
stop = stop_action(rsc, current, TRUE);
start = start_action(rsc, next, TRUE);
stop->optional = start->optional;
if(start->runnable == FALSE) {
rsc->next_role = RSC_ROLE_STOPPED;
} else if(start->optional) {
crm_notice("Leave resource %s\t(%s)",
rsc->id, next->details->uname);
} else {
crm_notice("Restart resource %s\t(%s)",
rsc->id, next->details->uname);
}
}
}
}
gboolean
StopRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
{
action_t *stop = NULL;
crm_debug_2("Executing: %s", rsc->id);
slist_iter(
current, node_t, rsc->running_on, lpc,
crm_notice(" %s\tStop %s", current->details->uname, rsc->id);
stop = stop_action(rsc, current, FALSE);
if(data_set->remove_after_stop) {
DeleteRsc(rsc, current, data_set);
}
);
return TRUE;
}
gboolean
StartRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
{
action_t *start = NULL;
crm_debug_2("Executing: %s", rsc->id);
start = start_action(rsc, next, TRUE);
if(start->runnable) {
crm_notice(" %s\tStart %s", next->details->uname, rsc->id);
start->optional = FALSE;
}
return TRUE;
}
gboolean
PromoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
{
char *key = NULL;
gboolean runnable = TRUE;
GListPtr action_list = NULL;
crm_debug_2("Executing: %s", rsc->id);
CRM_CHECK(rsc->next_role == RSC_ROLE_MASTER, return FALSE);
key = start_key(rsc);
action_list = find_actions_exact(rsc->actions, key, next);
crm_free(key);
slist_iter(start, action_t, action_list, lpc,
if(start->runnable == FALSE) {
runnable = FALSE;
}
);
if(runnable) {
promote_action(rsc, next, FALSE);
crm_notice("%s\tPromote %s", next->details->uname, rsc->id);
return TRUE;
}
crm_debug("%s\tPromote %s (canceled)", next->details->uname, rsc->id);
key = promote_key(rsc);
action_list = find_actions_exact(rsc->actions, key, next);
crm_free(key);
slist_iter(promote, action_t, action_list, lpc,
promote->runnable = FALSE;
);
return TRUE;
}
gboolean
DemoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
{
crm_debug_2("Executing: %s", rsc->id);
/* CRM_CHECK(rsc->next_role == RSC_ROLE_SLAVE, return FALSE); */
slist_iter(
current, node_t, rsc->running_on, lpc,
crm_notice("%s\tDeomote %s", current->details->uname, rsc->id);
demote_action(rsc, current, FALSE);
);
return TRUE;
}
gboolean
RoleError(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
{
crm_debug("Executing: %s", rsc->id);
CRM_CHECK(FALSE, return FALSE);
return FALSE;
}
gboolean
NullOp(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
{
crm_debug("Executing: %s", rsc->id);
return FALSE;
}
gboolean
DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set)
{
action_t *delete = NULL;
action_t *refresh = NULL;
if(rsc->failed) {
crm_debug_2("Resource %s not deleted from %s: failed",
rsc->id, node->details->uname);
return FALSE;
} else if(node == NULL) {
crm_debug_2("Resource %s not deleted: NULL node", rsc->id);
return FALSE;
} else if(node->details->unclean || node->details->online == FALSE) {
crm_debug_2("Resource %s not deleted from %s: unrunnable",
rsc->id, node->details->uname);
return FALSE;
}
crm_notice("Removing %s from %s",
rsc->id, node->details->uname);
delete = delete_action(rsc, node);
#if DELETE_THEN_REFRESH
refresh = custom_action(
NULL, crm_strdup(CRM_OP_LRM_REFRESH), CRM_OP_LRM_REFRESH,
node, FALSE, TRUE, data_set);
add_hash_param(refresh->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE);
order_actions(delete, refresh, pe_order_optional);
#endif
return TRUE;
}
gboolean
native_create_probe(resource_t *rsc, node_t *node, action_t *complete,
gboolean force, pe_working_set_t *data_set)
{
char *key = NULL;
char *target_rc = NULL;
action_t *probe = NULL;
node_t *running = NULL;
CRM_CHECK(node != NULL, return FALSE);
if(rsc->orphan) {
crm_debug_2("Skipping orphan: %s", rsc->id);
return FALSE;
}
running = pe_find_node_id(rsc->known_on, node->details->id);
if(force == FALSE && running != NULL) {
/* we already know the status of the resource on this node */
crm_debug_3("Skipping active: %s", rsc->id);
return FALSE;
}
key = generate_op_key(rsc->id, CRMD_ACTION_STATUS, 0);
probe = custom_action(rsc, key, CRMD_ACTION_STATUS, node,
FALSE, TRUE, data_set);
probe->priority = INFINITY;
running = pe_find_node_id(rsc->running_on, node->details->id);
if(running == NULL) {
target_rc = crm_itoa(EXECRA_NOT_RUNNING);
add_hash_param(probe->meta, XML_ATTR_TE_TARGET_RC, target_rc);
crm_free(target_rc);
}
crm_debug_2("%s: Created probe for %s", node->details->uname, rsc->id);
custom_action_order(rsc, NULL, probe, rsc, NULL, complete,
pe_order_implies_left, data_set);
return TRUE;
}
static void
native_start_constraints(
resource_t *rsc, action_t *stonith_op, gboolean is_stonith,
pe_working_set_t *data_set)
{
gboolean is_unprotected = FALSE;
gboolean run_unprotected = TRUE;
if(is_stonith) {
char *key = start_key(rsc);
crm_debug_2("Ordering %s action before stonith events", key);
custom_action_order(
rsc, key, NULL,
NULL, crm_strdup(CRM_OP_FENCE), stonith_op,
pe_order_optional, data_set);
} else {
slist_iter(action, action_t, rsc->actions, lpc2,
if(action->needs != rsc_req_stonith) {
crm_debug_3("%s doesnt need to wait for stonith events", action->uuid);
continue;
}
crm_debug_2("Ordering %s after stonith events", action->uuid);
if(stonith_op != NULL) {
custom_action_order(
NULL, crm_strdup(CRM_OP_FENCE), stonith_op,
rsc, NULL, action,
pe_order_implies_left, data_set);
} else if(run_unprotected == FALSE) {
/* mark the start unrunnable */
action->runnable = FALSE;
} else {
is_unprotected = TRUE;
}
);
}
if(is_unprotected) {
pe_err("SHARED RESOURCE %s IS NOT PROTECTED:"
" Stonith disabled", rsc->id);
}
}
static void
native_stop_constraints(
resource_t *rsc, action_t *stonith_op, gboolean is_stonith,
pe_working_set_t *data_set)
{
char *key = NULL;
GListPtr action_list = NULL;
node_t *node = stonith_op->node;
key = stop_key(rsc);
action_list = find_actions(rsc->actions, key, node);
crm_free(key);
/* add the stonith OP as a stop pre-req and the mark the stop
* as a pseudo op - since its now redundant
*/
slist_iter(
action, action_t, action_list, lpc2,
if(node->details->online == FALSE || rsc->failed) {
resource_t *parent = NULL;
crm_warn("Stop of failed resource %s is"
" implicit after %s is fenced",
action->uuid, node->details->uname);
/* the stop would never complete and is
* now implied by the stonith operation
*/
action->pseudo = TRUE;
action->runnable = TRUE;
if(is_stonith) {
/* do nothing */
} else {
custom_action_order(
NULL, crm_strdup(CRM_OP_FENCE),stonith_op,
rsc, start_key(rsc), NULL,
pe_order_implies_left, data_set);
}
/* find the top-most resource */
parent = rsc->parent;
while(parent != NULL && parent->parent != NULL) {
parent = parent->parent;
}
if(parent) {
crm_info("Re-creating actions for %s",
parent->id);
parent->cmds->create_actions(parent, data_set);
/* make sure we dont mess anything up in create_actions */
CRM_CHECK(action->pseudo, action->pseudo = TRUE);
CRM_CHECK(action->runnable, action->runnable = TRUE);
}
} else if(is_stonith == FALSE) {
crm_info("Moving healthy resource %s"
" off %s before fencing",
rsc->id, node->details->uname);
/* stop healthy resources before the
* stonith op
*/
custom_action_order(
rsc, stop_key(rsc), NULL,
NULL,crm_strdup(CRM_OP_FENCE),stonith_op,
pe_order_implies_left, data_set);
}
);
key = demote_key(rsc);
action_list = find_actions(rsc->actions, key, node);
crm_free(key);
slist_iter(
action, action_t, action_list, lpc2,
if(node->details->online == FALSE || rsc->failed) {
crm_info("Demote of failed resource %s is"
" implict after %s is fenced",
rsc->id, node->details->uname);
/* the stop would never complete and is
* now implied by the stonith operation
*/
action->pseudo = TRUE;
action->runnable = TRUE;
if(is_stonith == FALSE) {
custom_action_order(
NULL, crm_strdup(CRM_OP_FENCE), stonith_op,
rsc, demote_key(rsc), NULL,
pe_order_implies_left, data_set);
}
}
);
}
void
native_stonith_ordering(
resource_t *rsc, action_t *stonith_op, pe_working_set_t *data_set)
{
gboolean is_stonith = FALSE;
const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
if(rsc->is_managed == FALSE) {
crm_debug_3("Skipping fencing constraints for unmanaged resource: %s", rsc->id);
return;
}
if(stonith_op != NULL && safe_str_eq(class, "stonith")) {
is_stonith = TRUE;
}
/* Start constraints */
native_start_constraints(rsc, stonith_op, is_stonith, data_set);
/* Stop constraints */
native_stop_constraints(rsc, stonith_op, is_stonith, data_set);
}
void
native_migrate_reload(resource_t *rsc, pe_working_set_t *data_set)
{
char *key = NULL;
GListPtr action_list = NULL;
const char *value = NULL;
action_t *stop = NULL;
action_t *start = NULL;
action_t *other = NULL;
action_t *action = NULL;
if(rsc->variant != pe_native) {
return;
}
if(rsc->is_managed == FALSE
|| rsc->failed
|| rsc->start_pending
|| rsc->next_role != RSC_ROLE_STARTED
|| g_list_length(rsc->running_on) != 1) {
crm_debug_3("%s: resource", rsc->id);
return;
}
key = start_key(rsc);
action_list = find_actions(rsc->actions, key, NULL);
crm_free(key);
if(action_list == NULL) {
crm_debug_3("%s: no start action", rsc->id);
return;
}
start = action_list->data;
value = g_hash_table_lookup(rsc->meta, "allow_migrate");
if(crm_is_true(value)) {
rsc->can_migrate = TRUE;
}
if(rsc->can_migrate == FALSE
&& start->allow_reload_conversion == FALSE) {
crm_debug_3("%s: no need to continue", rsc->id);
return;
}
key = stop_key(rsc);
action_list = find_actions(rsc->actions, key, NULL);
crm_free(key);
if(action_list == NULL) {
crm_debug_3("%s: no stop action", rsc->id);
return;
}
stop = action_list->data;
action = start;
if(action->pseudo
|| action->optional
|| action->node == NULL
|| action->runnable == FALSE) {
crm_debug_3("Skipping: %s", action->task);
return;
}
action = stop;
if(action->pseudo
|| action->optional
|| action->node == NULL
|| action->runnable == FALSE) {
crm_debug_3("Skipping: %s", action->task);
return;
}
slist_iter(
other_w, action_wrapper_t, start->actions_before, lpc,
other = other_w->action;
if(other->optional == FALSE
&& other->rsc != NULL
&& other->rsc != start->rsc) {
crm_debug_2("Skipping: start depends");
return;
}
);
slist_iter(
other_w, action_wrapper_t, stop->actions_after, lpc,
other = other_w->action;
if(other->optional == FALSE
&& other->rsc != NULL
&& other->rsc != stop->rsc) {
crm_debug_2("Skipping: stop depends");
return;
}
);
if(rsc->can_migrate && stop->node->details != start->node->details) {
crm_info("Migrating %s from %s to %s", rsc->id,
stop->node->details->uname,
start->node->details->uname);
crm_free(stop->uuid);
stop->task = CRMD_ACTION_MIGRATE;
stop->uuid = generate_op_key(rsc->id, stop->task, 0);
add_hash_param(stop->meta, "migrate_source",
stop->node->details->uname);
add_hash_param(stop->meta, "migrate_target",
start->node->details->uname);
crm_free(start->uuid);
start->task = CRMD_ACTION_MIGRATED;
start->uuid = generate_op_key(rsc->id, start->task, 0);
add_hash_param(start->meta, "migrate_source_uuid",
stop->node->details->id);
add_hash_param(start->meta, "migrate_source",
stop->node->details->uname);
add_hash_param(start->meta, "migrate_target",
start->node->details->uname);
} else if(start->allow_reload_conversion
&& stop->node->details == start->node->details) {
crm_info("Rewriting restart of %s on %s as a reload",
rsc->id, start->node->details->uname);
crm_free(start->uuid);
start->task = "reload";
start->uuid = generate_op_key(rsc->id, start->task, 0);
stop->pseudo = TRUE; /* easier than trying to delete it from the graph */
} else {
crm_debug_3("%s nothing to do", rsc->id);
}
}
diff --git a/crm/pengine/utils.c b/crm/pengine/utils.c
index cf196116e6..6ef8cf085e 100644
--- a/crm/pengine/utils.c
+++ b/crm/pengine/utils.c
@@ -1,537 +1,537 @@
/* $Id: utils.c,v 1.147 2006/07/05 14:20:02 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 <crm/msg_xml.h>
#include <allocate.h>
#include <utils.h>
#include <lib/crm/pengine/utils.h>
gint sort_cons_strength(gconstpointer a, gconstpointer b)
{
const rsc_colocation_t *rsc_constraint1 = (const rsc_colocation_t*)a;
const rsc_colocation_t *rsc_constraint2 = (const rsc_colocation_t*)b;
if(a == NULL) { return 1; }
if(b == NULL) { return -1; }
if(rsc_constraint1->score > rsc_constraint2->score) {
return 1;
}
if(rsc_constraint1->score < rsc_constraint2->score) {
return -1;
}
return 0;
}
void
print_rsc_to_node(const char *pre_text, rsc_to_node_t *cons, gboolean details)
{
if(cons == NULL) {
crm_debug_4("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug_4("%s%s%s Constraint %s (%p) - %d nodes:",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
"rsc_to_node",
cons->id, cons,
g_list_length(cons->node_list_rh));
if(details == FALSE) {
crm_debug_4("\t%s (node placement rule)",
safe_val3(NULL, cons, rsc_lh, id));
slist_iter(
node, node_t, cons->node_list_rh, lpc,
print_node("\t\t-->", node, FALSE)
);
}
}
void
print_rsc_colocation(const char *pre_text, rsc_colocation_t *cons, gboolean details)
{
if(cons == NULL) {
crm_debug_4("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug_4("%s%s%s Constraint %s (%p):",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
XML_CONS_TAG_RSC_DEPEND, cons->id, cons);
if(details == FALSE) {
crm_debug_4("\t%s --> %s, %d",
safe_val3(NULL, cons, rsc_lh, id),
safe_val3(NULL, cons, rsc_rh, id),
cons->score);
}
}
void
pe_free_ordering(GListPtr constraints)
{
GListPtr iterator = constraints;
while(iterator != NULL) {
order_constraint_t *order = iterator->data;
iterator = iterator->next;
crm_free(order->lh_action_task);
crm_free(order->rh_action_task);
crm_free(order);
}
if(constraints != NULL) {
g_list_free(constraints);
}
}
void
pe_free_rsc_to_node(GListPtr constraints)
{
GListPtr iterator = constraints;
while(iterator != NULL) {
rsc_to_node_t *cons = iterator->data;
iterator = iterator->next;
pe_free_shallow(cons->node_list_rh);
crm_free(cons);
}
if(constraints != NULL) {
g_list_free(constraints);
}
}
rsc_to_node_t *
rsc2node_new(const char *id, resource_t *rsc,
int node_weight, node_t *foo_node, pe_working_set_t *data_set)
{
rsc_to_node_t *new_con = NULL;
if(rsc == NULL || id == NULL) {
pe_err("Invalid constraint %s for rsc=%p", crm_str(id), rsc);
return NULL;
- }
+ } else if(foo_node == NULL) {
+ CRM_CHECK(node_weight == 0, return NULL);
+ }
+
crm_malloc0(new_con, sizeof(rsc_to_node_t));
if(new_con != NULL) {
new_con->id = id;
new_con->rsc_lh = rsc;
new_con->node_list_rh = NULL;
new_con->role_filter = RSC_ROLE_UNKNOWN;
if(foo_node != NULL) {
node_t *copy = node_copy(foo_node);
copy->weight = node_weight;
new_con->node_list_rh = g_list_append(NULL, copy);
- } else {
- CRM_CHECK(node_weight == 0, return NULL);
}
data_set->placement_constraints = g_list_append(
data_set->placement_constraints, new_con);
- rsc->rsc_location = g_list_append(
- rsc->rsc_location, new_con);
+ rsc->rsc_location = g_list_append(rsc->rsc_location, new_con);
}
return new_con;
}
const char *
ordering_type2text(enum pe_ordering type)
{
const char *result = "<unknown>";
if(type & pe_order_implies_left) {
/* was: mandatory */
result = "right_implies_left";
} else if(type & pe_order_internal_restart) {
/* upgrades to: right_implies_left */
result = "internal_restart";
} else if(type & pe_order_implies_right) {
/* was: recover */
result = "left_implies_right";
} else if(type & pe_order_optional) {
/* pure ordering, nothing implied */
result = "optional";
} else if(type & pe_order_postnotify) {
result = "post_notify";
} else {
crm_err("Unknown ordering type: %.3x", type);
}
return result;
}
gboolean
can_run_resources(const node_t *node)
{
if(node == NULL) {
return FALSE;
}
if(node->details->online == FALSE
|| node->details->shutdown
|| node->details->unclean
|| node->details->standby) {
crm_debug_2("%s: online=%d, unclean=%d, standby=%d",
node->details->uname, node->details->online,
node->details->unclean, node->details->standby);
return FALSE;
}
return TRUE;
}
/* return -1 if 'a' is more preferred
* return 1 if 'b' is more preferred
*/
gint sort_node_weight(gconstpointer a, gconstpointer b)
{
const node_t *node1 = (const node_t*)a;
const node_t *node2 = (const node_t*)b;
int node1_weight = 0;
int node2_weight = 0;
if(a == NULL) { return 1; }
if(b == NULL) { return -1; }
node1_weight = node1->weight;
node2_weight = node2->weight;
if(can_run_resources(node1) == FALSE) {
node1_weight = -INFINITY;
}
if(can_run_resources(node2) == FALSE) {
node2_weight = -INFINITY;
}
if(node1_weight > node2_weight) {
crm_debug_3("%s (%d) > %s (%d) : weight",
node1->details->uname, node1_weight,
node2->details->uname, node2_weight);
return -1;
}
if(node1_weight < node2_weight) {
crm_debug_3("%s (%d) < %s (%d) : weight",
node1->details->uname, node1_weight,
node2->details->uname, node2_weight);
return 1;
}
crm_debug_3("%s (%d) == %s (%d) : weight",
node1->details->uname, node1_weight,
node2->details->uname, node2_weight);
/* now try to balance resources across the cluster */
if(node1->details->num_resources
< node2->details->num_resources) {
crm_debug_3("%s (%d) < %s (%d) : resources",
node1->details->uname, node1->details->num_resources,
node2->details->uname, node2->details->num_resources);
return -1;
} else if(node1->details->num_resources
> node2->details->num_resources) {
crm_debug_3("%s (%d) > %s (%d) : resources",
node1->details->uname, node1->details->num_resources,
node2->details->uname, node2->details->num_resources);
return 1;
}
crm_debug_4("%s = %s", node1->details->uname, node2->details->uname);
return 0;
}
gboolean
native_assign_node(resource_t *rsc, GListPtr nodes, node_t *chosen)
{
int multiple = 0;
CRM_ASSERT(rsc->variant == pe_native);
rsc->provisional = FALSE;
if(chosen == NULL) {
crm_debug("Could not allocate a node for %s", rsc->id);
rsc->next_role = RSC_ROLE_STOPPED;
return FALSE;
} else if(can_run_resources(chosen) == FALSE) {
crm_debug("All nodes for resource %s are unavailable"
", unclean or shutting down", rsc->id);
rsc->next_role = RSC_ROLE_STOPPED;
return FALSE;
} else if(chosen->weight < 0) {
crm_debug("Even highest ranked node for %s, had weight %d",
rsc->id, chosen->weight);
rsc->next_role = RSC_ROLE_STOPPED;
return FALSE;
}
if(rsc->next_role == RSC_ROLE_UNKNOWN) {
rsc->next_role = RSC_ROLE_STARTED;
}
slist_iter(candidate, node_t, nodes, lpc,
crm_debug("Color %s, Node[%d] %s: %d", rsc->id, lpc,
candidate->details->uname, candidate->weight);
if(chosen->weight > 0
&& candidate->details->unclean == FALSE
&& candidate->weight == chosen->weight) {
multiple++;
}
);
if(multiple > 1) {
int log_level = LOG_INFO;
char *score = score2char(chosen->weight);
if(chosen->weight >= INFINITY) {
log_level = LOG_WARNING;
}
do_crm_log(log_level, "%d nodes with equal score (%s) for"
" running the listed resources (chose %s):",
multiple, score, chosen->details->uname);
crm_free(score);
}
/* todo: update the old node for each resource to reflect its
* new resource count
*/
if(rsc->allocated_to) {
node_t *old = rsc->allocated_to;
old->details->allocated_rsc = g_list_remove(
old->details->allocated_rsc, rsc);
old->details->num_resources--;
old->count--;
}
crm_debug("Assigning %s to %s", chosen->details->uname, rsc->id);
crm_free(rsc->allocated_to);
rsc->allocated_to = node_copy(chosen);
chosen->details->allocated_rsc = g_list_append(chosen->details->allocated_rsc, rsc);
chosen->details->num_resources++;
chosen->count++;
return TRUE;
}
void
convert_non_atomic_task(resource_t *rsc, order_constraint_t *order)
{
int interval = 0;
char *rid = NULL;
char *raw_task = NULL;
int task = no_action;
char *old_uuid = order->lh_action_task;
crm_debug("Processing %s", old_uuid);
if(order->lh_action_task == NULL
|| strstr(order->lh_action_task, "notify") != NULL) {
/* no conversion */
return;
}
CRM_ASSERT(parse_op_key(old_uuid, &rid, &raw_task, &interval));
task = text2task(raw_task);
switch(task) {
case stop_rsc:
case start_rsc:
case action_notify:
case action_promote:
case action_demote:
break;
case stopped_rsc:
case started_rsc:
case action_notified:
case action_promoted:
case action_demoted:
task--;
break;
case monitor_rsc:
case shutdown_crm:
case stonith_node:
task = no_action;
break;
default:
crm_err("Unknown action: %s", raw_task);
task = no_action;
break;
}
if(task != no_action) {
if(rsc->notify) {
order->lh_action_task = generate_notify_key(
rsc->id, "confirmed-post",
task2text(task));
} else {
order->lh_action_task = generate_op_key(
rsc->id, task2text(task+1), 0);
}
crm_debug("Converted %s -> %s",
old_uuid, order->lh_action_task);
crm_free(old_uuid);
}
crm_free(raw_task);
crm_free(rid);
}
void
order_actions(
action_t *lh_action, action_t *rh_action, enum pe_ordering order)
{
action_wrapper_t *wrapper = NULL;
GListPtr list = NULL;
crm_debug_2("Ordering Action %s before %s",
lh_action->uuid, rh_action->uuid);
log_action(LOG_DEBUG_4, "LH (order_actions)", lh_action, FALSE);
log_action(LOG_DEBUG_4, "RH (order_actions)", rh_action, FALSE);
crm_malloc0(wrapper, sizeof(action_wrapper_t));
if(wrapper != NULL) {
wrapper->action = rh_action;
wrapper->type = order;
list = lh_action->actions_after;
list = g_list_append(list, wrapper);
lh_action->actions_after = list;
wrapper = NULL;
}
order |= pe_order_implies_right;
order ^= pe_order_implies_right;
if(order) {
crm_malloc0(wrapper, sizeof(action_wrapper_t));
if(wrapper != NULL) {
wrapper->action = lh_action;
wrapper->type = order;
list = rh_action->actions_before;
list = g_list_append(list, wrapper);
rh_action->actions_before = list;
}
}
}
void
log_action(unsigned int log_level, const char *pre_text, action_t *action, gboolean details)
{
const char *node_uname = NULL;
const char *node_uuid = NULL;
if(action == NULL) {
do_crm_log(log_level, "%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
if(action->pseudo) {
node_uname = NULL;
node_uuid = NULL;
} else if(action->node != NULL) {
node_uname = action->node->details->uname;
node_uuid = action->node->details->id;
} else {
node_uname = "<none>";
node_uuid = NULL;
}
switch(text2task(action->task)) {
case stonith_node:
case shutdown_crm:
do_crm_log(log_level,
"%s%s%sAction %d: %s%s%s%s%s%s",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
action->pseudo?"Pseduo ":action->optional?"Optional ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ",
action->id, action->uuid,
node_uname?"\ton ":"",
node_uname?node_uname:"",
node_uuid?"\t\t(":"",
node_uuid?node_uuid:"",
node_uuid?")":"");
break;
default:
do_crm_log(log_level,
"%s%s%sAction %d: %s %s%s%s%s%s%s",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
action->optional?"Optional ":action->pseudo?"Pseduo ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ",
action->id, action->uuid,
safe_val3("<none>", action, rsc, id),
node_uname?"\ton ":"",
node_uname?node_uname:"",
node_uuid?"\t\t(":"",
node_uuid?node_uuid:"",
node_uuid?")":"");
break;
}
if(details) {
do_crm_log(log_level+1, "\t\t====== Preceeding Actions");
slist_iter(
other, action_wrapper_t, action->actions_before, lpc,
log_action(log_level+1, "\t\t", other->action, FALSE);
);
do_crm_log(log_level+1, "\t\t====== Subsequent Actions");
slist_iter(
other, action_wrapper_t, action->actions_after, lpc,
log_action(log_level+1, "\t\t", other->action, FALSE);
);
do_crm_log(log_level+1, "\t\t====== End");
} else {
do_crm_log(log_level, "\t\t(seen=%d, before=%d, after=%d)",
action->seen_count,
g_list_length(action->actions_before),
g_list_length(action->actions_after));
}
}
diff --git a/crm/tengine/callbacks.c b/crm/tengine/callbacks.c
index 50fc8e8091..d78cfaa275 100644
--- a/crm/tengine/callbacks.c
+++ b/crm/tengine/callbacks.c
@@ -1,575 +1,579 @@
/* $Id: callbacks.c,v 1.89 2006/08/14 09:14:45 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/stat.h>
#include <hb_api.h>
#include <crm/crm.h>
#include <crm/common/xml.h>
#include <crm/msg_xml.h>
#include <crm/cib.h>
#include <heartbeat.h>
#include <tengine.h>
#include <te_callbacks.h>
#include <clplumbing/Gmain_timeout.h>
void te_update_confirm(const char *event, HA_Message *msg);
void te_update_diff(const char *event, HA_Message *msg);
crm_data_t *need_abort(crm_data_t *update);
void cib_fencing_updated(const HA_Message *msg, int call_id, int rc,
crm_data_t *output, void *user_data);
extern char *te_uuid;
gboolean shuttingdown = FALSE;
crm_graph_t *transition_graph;
GTRIGSource *transition_trigger = NULL;
crm_action_timer_t *transition_timer = NULL;
static gboolean
start_global_timer(crm_action_timer_t *timer, int timeout)
{
CRM_ASSERT(timer != NULL);
CRM_CHECK(timer > 0, return FALSE);
CRM_CHECK(timer->source_id == 0, return FALSE);
if(timeout <= 0) {
crm_err("Tried to start timer with period: %d", timeout);
} else if(timer->source_id == 0) {
crm_debug_2("Starting abort timer: %dms", timeout);
timer->timeout = timeout;
timer->source_id = Gmain_timeout_add(
timeout, global_timer_callback, (void*)timer);
CRM_ASSERT(timer->source_id != 0);
return TRUE;
} else {
crm_err("Timer is already active with period: %d", timer->timeout);
}
return FALSE;
}
void
te_update_diff(const char *event, HA_Message *msg)
{
int rc = -1;
const char *op = NULL;
crm_data_t *diff = NULL;
crm_data_t *aborted = NULL;
const char *set_name = NULL;
int diff_add_updates = 0;
int diff_add_epoch = 0;
int diff_add_admin_epoch = 0;
int diff_del_updates = 0;
int diff_del_epoch = 0;
int diff_del_admin_epoch = 0;
if(msg == NULL) {
crm_err("NULL update");
return;
}
ha_msg_value_int(msg, F_CIB_RC, &rc);
op = cl_get_string(msg, F_CIB_OPERATION);
if(rc < cib_ok) {
crm_debug_2("Ignoring failed %s operation: %s",
op, cib_error2string(rc));
return;
}
diff = get_message_xml(msg, F_CIB_UPDATE_RESULT);
cib_diff_version_details(
diff,
&diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
&diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
crm_info("Processing diff (%s): %d.%d.%d -> %d.%d.%d", op,
diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
diff_add_admin_epoch,diff_add_epoch,diff_add_updates);
log_cib_diff(LOG_DEBUG_2, diff, op);
set_name = "diff-added";
if(diff != NULL) {
crm_data_t *section = NULL;
crm_data_t *change_set = find_xml_node(diff, set_name, FALSE);
change_set = find_xml_node(change_set, XML_TAG_CIB, FALSE);
if(change_set != NULL) {
crm_debug_2("Checking status changes");
section=get_object_root(XML_CIB_TAG_STATUS,change_set);
}
if(section != NULL) {
extract_event(section);
}
crm_debug_2("Checking change set: %s", set_name);
aborted = need_abort(change_set);
}
set_name = "diff-removed";
if(diff != NULL && aborted == NULL) {
crm_data_t *attrs = NULL;
crm_data_t *status = NULL;
crm_data_t *change_set = find_xml_node(diff, set_name, FALSE);
change_set = find_xml_node(change_set, XML_TAG_CIB, FALSE);
crm_debug_2("Checking change set: %s", set_name);
aborted = need_abort(change_set);
if(aborted == NULL && change_set != NULL) {
status = get_object_root(XML_CIB_TAG_STATUS, change_set);
xml_child_iter_filter(
status, node_state, XML_CIB_TAG_STATE,
attrs = find_xml_node(
node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE);
if(attrs != NULL) {
crm_info("Aborting on "XML_TAG_TRANSIENT_NODEATTRS" deletions");
abort_transition(INFINITY, tg_restart,
XML_TAG_TRANSIENT_NODEATTRS, attrs);
}
);
}
}
if(aborted != NULL) {
abort_transition(
INFINITY, tg_restart, "Non-status change", NULL);
}
free_xml(diff);
return;
}
gboolean
process_te_message(HA_Message *msg, crm_data_t *xml_data, IPC_Channel *sender)
{
crm_data_t *xml_obj = NULL;
const char *from = cl_get_string(msg, F_ORIG);
const char *sys_to = cl_get_string(msg, F_CRM_SYS_TO);
const char *sys_from = cl_get_string(msg, F_CRM_SYS_FROM);
const char *ref = cl_get_string(msg, XML_ATTR_REFERENCE);
const char *op = cl_get_string(msg, F_CRM_TASK);
const char *type = cl_get_string(msg, F_CRM_MSG_TYPE);
crm_debug_2("Processing %s (%s) message", op, ref);
crm_log_message(LOG_DEBUG_3, msg);
if(op == NULL){
/* error */
} else if(strcasecmp(op, CRM_OP_HELLO) == 0) {
/* ignore */
} else if(sys_to == NULL || strcasecmp(sys_to, CRM_SYSTEM_TENGINE) != 0) {
crm_debug_2("Bad sys-to %s", crm_str(sys_to));
return FALSE;
} else if(safe_str_eq(op, CRM_OP_INVOKE_LRM)
&& safe_str_eq(sys_from, CRM_SYSTEM_LRMD)
/* && safe_str_eq(type, XML_ATTR_RESPONSE) */
){
#if CRM_DEPRECATED_SINCE_2_0_4
if(safe_str_eq(crm_element_name(xml_data), XML_TAG_CIB)) {
xml_obj = xml_data;
} else {
xml_obj = find_xml_node(xml_data, XML_TAG_CIB, TRUE);
}
#else
xml_obj = xml_data;
CRM_CHECK(xml_obj != NULL,
crm_log_message_adv(LOG_ERR, "Invalid (N)ACK", msg);
return FALSE);
#endif
CRM_CHECK(xml_obj != NULL,
crm_log_message_adv(LOG_ERR, "Invalid (N)ACK", msg);
return FALSE);
xml_obj = get_object_root(XML_CIB_TAG_STATUS, xml_obj);
CRM_CHECK(xml_obj != NULL,
crm_log_message_adv(LOG_ERR, "Invalid (N)ACK", msg);
return FALSE);
crm_log_message_adv(LOG_DEBUG_2, "Processing (N)ACK", msg);
crm_debug("Processing (N)ACK from %s", from);
extract_event(xml_obj);
} else if(safe_str_eq(type, XML_ATTR_RESPONSE)) {
crm_err("Message was a response not a request. Discarding");
return TRUE;
} else if(strcasecmp(op, CRM_OP_TRANSITION) == 0) {
const char *graph_file = cl_get_string(msg, F_CRM_TGRAPH);
const char *graph_input = cl_get_string(msg, F_CRM_TGRAPH_INPUT);
CRM_CHECK(graph_file != NULL || xml_data != NULL,
crm_err("No graph provided");
crm_log_message(LOG_WARNING, msg);
return TRUE);
if(transition_graph->complete == FALSE) {
crm_info("Another transition is already active");
abort_transition(
INFINITY, tg_restart, "Transition Active", NULL);
} else {
destroy_graph(transition_graph);
crm_debug("Processing graph derived from %s", graph_input);
if(graph_file == NULL) {
transition_graph = unpack_graph(xml_data);
} else {
FILE *graph_fd = fopen(graph_file, "r");
crm_data_t *graph_data = file2xml(graph_fd, FALSE);
CRM_CHECK(graph_fd != NULL,
crm_err("Could not open graph filename: %s", graph_file);
return TRUE);
transition_graph = unpack_graph(graph_data);
fclose(graph_fd);
free_xml(graph_data);
unlink(graph_file);
}
start_global_timer(transition_timer,
transition_graph->transition_timeout);
trigger_graph();
print_graph(LOG_DEBUG_2, transition_graph);
}
} else if(strcasecmp(op, CRM_OP_TE_HALT) == 0) {
abort_transition(INFINITY, tg_stop, "Peer Halt", NULL);
} else if(strcasecmp(op, CRM_OP_TEABORT) == 0) {
abort_transition(INFINITY, tg_restart, "Peer Cancelled", NULL);
} else {
crm_err("Unknown command: %s::%s from %s", type, op, sys_from);
}
crm_debug_3("finished processing message");
return TRUE;
}
void
tengine_stonith_callback(stonith_ops_t * op)
{
const char *allow_fail = NULL;
int stonith_id = -1;
int transition_id = -1;
char *uuid = NULL;
crm_action_t *stonith_action = NULL;
if(op == NULL) {
crm_err("Called with a NULL op!");
return;
}
crm_info("call=%d, optype=%d, node_name=%s, result=%d, node_list=%s, action=%s",
op->call_id, op->optype, op->node_name, op->op_result,
(char *)op->node_list, op->private_data);
/* this will mark the event complete if a match is found */
CRM_CHECK(op->private_data != NULL, return);
/* filter out old STONITH actions */
CRM_CHECK(decode_transition_key(
op->private_data, &uuid, &transition_id, &stonith_id),
crm_err("Invalid event detected");
+ goto bail;
);
if(transition_graph->complete
|| stonith_id < 0
|| safe_str_neq(uuid, te_uuid)
|| transition_graph->id != transition_id) {
crm_info("Ignoring STONITH action initiated outside"
" of the current transition");
}
stonith_action = get_action(stonith_id, TRUE);
if(stonith_action == NULL) {
crm_err("Stonith action not matched");
- return;
+ goto bail;
}
switch(op->op_result) {
case STONITH_SUCCEEDED:
send_stonith_update(op);
break;
case STONITH_CANNOT:
case STONITH_TIMEOUT:
case STONITH_GENERIC:
stonith_action->failed = TRUE;
allow_fail = g_hash_table_lookup(
stonith_action->params,
crm_meta_name(XML_ATTR_TE_ALLOWFAIL));
if(FALSE == crm_is_true(allow_fail)) {
crm_err("Stonith of %s failed (%d)..."
" aborting transition.",
op->node_name, op->op_result);
abort_transition(INFINITY, tg_restart,
"Stonith failed", NULL);
}
break;
default:
crm_err("Unsupported action result: %d", op->op_result);
abort_transition(INFINITY, tg_restart,
"Unsupport Stonith result", NULL);
}
update_graph(transition_graph, stonith_action);
trigger_graph();
+
+ bail:
+ crm_free(uuid);
return;
}
void
tengine_stonith_connection_destroy(gpointer user_data)
{
#if 0
crm_err("Fencing daemon has left us: Shutting down...NOW");
/* shutdown properly later */
CRM_CHECK(FALSE/* fencing daemon died */);
#else
crm_err("Fencing daemon has left us");
#endif
return;
}
gboolean
tengine_stonith_dispatch(IPC_Channel *sender, void *user_data)
{
int lpc = 0;
while(stonithd_op_result_ready()) {
if (sender->ch_status == IPC_DISCONNECT) {
/* The message which was pending for us is that
* the IPC status is now IPC_DISCONNECT */
break;
}
if(ST_FAIL == stonithd_receive_ops_result(FALSE)) {
crm_err("stonithd_receive_ops_result() failed");
} else {
lpc++;
}
}
crm_debug_2("Processed %d messages", lpc);
if (sender->ch_status == IPC_DISCONNECT) {
return FALSE;
}
return TRUE;
}
void
cib_fencing_updated(const HA_Message *msg, int call_id, int rc,
crm_data_t *output, void *user_data)
{
trigger_graph();
if(rc < cib_ok) {
crm_err("CIB update failed: %s", cib_error2string(rc));
crm_log_xml_warn(msg, "[Failed Update]");
}
}
void
cib_action_updated(const HA_Message *msg, int call_id, int rc,
crm_data_t *output, void *user_data)
{
trigger_graph();
if(rc < cib_ok) {
crm_err("Update %d FAILED: %s", call_id, cib_error2string(rc));
}
}
gboolean
action_timer_callback(gpointer data)
{
crm_action_timer_t *timer = NULL;
if(data == NULL) {
crm_err("Timer popped with no data");
return FALSE;
}
timer = (crm_action_timer_t*)data;
stop_te_timer(timer);
crm_warn("Timer popped (abort_level=%d, complete=%s)",
transition_graph->abort_priority,
transition_graph->complete?"true":"false");
CRM_CHECK(timer->action != NULL, return FALSE);
if(transition_graph->complete) {
crm_err("Ignoring timeout while not in transition");
} else if(timer->reason == timeout_action_warn) {
print_action(
LOG_WARNING,"Action missed its timeout", timer->action);
} else {
/* fail the action */
cib_action_update(timer->action, LRM_OP_TIMEOUT);
}
return FALSE;
}
static int
unconfirmed_actions(gboolean send_updates)
{
int unconfirmed = 0;
const char *task = NULL;
crm_debug_2("Unconfirmed actions...");
slist_iter(
synapse, synapse_t, transition_graph->synapses, lpc,
/* lookup event */
slist_iter(
action, crm_action_t, synapse->actions, lpc2,
if(action->executed == FALSE) {
continue;
} else if(action->confirmed) {
continue;
}
unconfirmed++;
task = crm_element_value(action->xml,XML_LRM_ATTR_TASK);
if(action->type != action_type_rsc) {
continue;
} else if(send_updates == FALSE) {
continue;
} else if(safe_str_eq(task, "cancel")) {
/* we dont need to update the CIB with these */
continue;
} else if(safe_str_eq(task, "stop")) {
/* *never* update the CIB with these */
continue;
}
crm_err("Action %d unconfirmed from peer", action->id);
cib_action_update(action, LRM_OP_PENDING);
);
);
if(unconfirmed > 0) {
crm_info("Waiting on %d unconfirmed actions", unconfirmed);
}
return unconfirmed;
}
gboolean
global_timer_callback(gpointer data)
{
crm_action_timer_t *timer = NULL;
if(data == NULL) {
crm_err("Timer popped with no data");
return FALSE;
}
timer = (crm_action_timer_t*)data;
stop_te_timer(timer);
crm_warn("Timer popped (abort_level=%d, complete=%s)",
transition_graph->abort_priority,
transition_graph->complete?"true":"false");
CRM_CHECK(timer->action == NULL, return FALSE);
if(transition_graph->complete) {
crm_err("Ignoring timeout while not in transition");
} else if(timer->reason == timeout_abort) {
int unconfirmed = unconfirmed_actions(FALSE);
crm_warn("Transition abort timeout reached..."
" marking transition complete.");
transition_graph->complete = TRUE;
abort_transition(INFINITY, tg_restart, "Global Timeout", NULL);
if(unconfirmed != 0) {
crm_warn("Writing %d unconfirmed actions to the CIB",
unconfirmed);
unconfirmed_actions(TRUE);
}
}
return FALSE;
}
gboolean
te_graph_trigger(gpointer user_data)
{
int timeout = 0;
enum transition_status graph_rc = -1;
if(transition_graph->complete) {
notify_crmd(transition_graph);
return TRUE;
}
graph_rc = run_graph(transition_graph);
timeout = transition_graph->transition_timeout;
print_graph(LOG_DEBUG_3, transition_graph);
if(graph_rc == transition_active) {
crm_debug_3("Transition not yet complete");
stop_te_timer(transition_timer);
start_global_timer(transition_timer, timeout);
return TRUE;
} else if(graph_rc == transition_pending) {
timeout = transition_timer->timeout;
crm_debug_3("Transition not yet complete - no actions fired");
return TRUE;
}
if(graph_rc != transition_complete) {
crm_err("Transition failed: %s", transition_status(graph_rc));
print_graph(LOG_WARNING, transition_graph);
}
transition_graph->complete = TRUE;
notify_crmd(transition_graph);
return TRUE;
}
diff --git a/crm/tengine/events.c b/crm/tengine/events.c
index 298083268b..8e6cdf332a 100644
--- a/crm/tengine/events.c
+++ b/crm/tengine/events.c
@@ -1,509 +1,510 @@
/* $Id: events.c,v 1.23 2006/08/14 09:14:45 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 <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/msg.h>
#include <crm/common/xml.h>
#include <tengine.h>
#include <heartbeat.h>
#include <clplumbing/Gmain_timeout.h>
#include <lrm/lrm_api.h>
crm_data_t *need_abort(crm_data_t *update);
void process_graph_event(crm_data_t *event, const char *event_node);
int match_graph_event(int action_id, crm_data_t *event, const char *event_node,
int op_status, int op_rc);
crm_data_t *
need_abort(crm_data_t *update)
{
crm_data_t *section_xml = NULL;
const char *section = NULL;
if(update == NULL) {
return NULL;
}
section = XML_CIB_TAG_NODES;
section_xml = get_object_root(section, update);
xml_child_iter(section_xml, child,
return section_xml;
);
section = XML_CIB_TAG_RESOURCES;
section_xml = get_object_root(section, update);
xml_child_iter(section_xml, child,
return section_xml;
);
section = XML_CIB_TAG_CONSTRAINTS;
section_xml = get_object_root(section, update);
xml_child_iter(section_xml, child,
return section_xml;
);
section = XML_CIB_TAG_CRMCONFIG;
section_xml = get_object_root(section, update);
xml_child_iter(section_xml, child,
return section_xml;
);
return NULL;
}
static gboolean
fail_incompletable_actions(crm_graph_t *graph, const char *down_node)
{
const char *target = NULL;
crm_data_t *last_action = NULL;
slist_iter(
synapse, synapse_t, graph->synapses, lpc,
if (synapse->confirmed) {
continue;
}
slist_iter(
action, crm_action_t, synapse->actions, lpc,
if(action->type == action_type_pseudo || action->confirmed) {
continue;
}
target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
if(safe_str_eq(target, down_node)) {
action->failed = TRUE;
last_action = action->xml;
update_graph(graph, action);
crm_notice("Action %d (%s) is scheduled for %s (offline)",
action->id, ID(action->xml), down_node);
}
);
);
if(last_action != NULL) {
crm_warn("Node %s shutdown resulted in un-runnable actions", down_node);
abort_transition(INFINITY, tg_restart, "Node failure", last_action);
return TRUE;
}
return FALSE;
}
gboolean
extract_event(crm_data_t *msg)
{
int shutdown = 0;
const char *event_node = NULL;
/*
[cib fragment]
...
<status>
<node_state id="node1" state=CRMD_STATE_ACTIVE exp_state="active">
<lrm>
<lrm_resources>
<rsc_state id="" rsc_id="rsc4" node_id="node1" rsc_state="stopped"/>
*/
crm_debug_4("Extracting event from %s", crm_element_name(msg));
xml_child_iter_filter(
msg, node_state, XML_CIB_TAG_STATE,
crm_data_t *attrs = NULL;
crm_data_t *resources = NULL;
const char *ccm_state = crm_element_value(
node_state, XML_CIB_ATTR_INCCM);
const char *crmd_state = crm_element_value(
node_state, XML_CIB_ATTR_CRMDSTATE);
/* Transient node attribute changes... */
event_node = crm_element_value(node_state, XML_ATTR_ID);
crm_debug_2("Processing state update from %s", event_node);
crm_log_xml_debug_3(node_state, "Processing");
attrs = find_xml_node(
node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE);
if(attrs != NULL) {
crm_info("Aborting on "XML_TAG_TRANSIENT_NODEATTRS" changes for %s", event_node);
abort_transition(INFINITY, tg_restart,
XML_TAG_TRANSIENT_NODEATTRS, attrs);
}
resources = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE);
resources = find_xml_node(
resources, XML_LRM_TAG_RESOURCES, FALSE);
/* LRM resource update... */
xml_child_iter(
resources, rsc,
xml_child_iter(
rsc, rsc_op,
crm_log_xml_debug_3(rsc_op, "Processing resource update");
process_graph_event(rsc_op, event_node);
);
);
/*
* node state update... possibly from a shutdown we requested
*/
if(safe_str_eq(ccm_state, XML_BOOLEAN_FALSE)
|| safe_str_eq(crmd_state, CRMD_JOINSTATE_DOWN)) {
crm_action_t *shutdown = NULL;
shutdown = match_down_event(0, event_node, NULL);
if(shutdown != NULL) {
update_graph(transition_graph, shutdown);
trigger_graph();
} else {
crm_info("Stonith/shutdown of %s not matched", event_node);
abort_transition(INFINITY, tg_restart, "Node failure", node_state);
}
fail_incompletable_actions(transition_graph, event_node);
}
shutdown = 0;
ha_msg_value_int(node_state, XML_CIB_ATTR_SHUTDOWN, &shutdown);
if(shutdown != 0) {
crm_info("Aborting on "XML_CIB_ATTR_SHUTDOWN" attribute for %s", event_node);
abort_transition(INFINITY, tg_restart, "Shutdown request", node_state);
}
);
return TRUE;
}
static void
update_failcount(crm_data_t *event, const char *event_node, int rc)
{
int interval = 0;
char *task = NULL;
char *rsc_id = NULL;
char *attr_name = NULL;
const char *id = ID(event);
const char *on_uuid = event_node;
if(rc == 99) {
/* this is an internal code for "we're busy, try again" */
return;
}
CRM_CHECK(on_uuid != NULL, return);
CRM_CHECK(parse_op_key(id, &rsc_id, &task, &interval),
crm_err("Couldn't parse: %s", ID(event));
- return);
- CRM_CHECK(task != NULL, crm_free(rsc_id); return);
- CRM_CHECK(rsc_id != NULL, crm_free(task); return);
+ goto bail);
+ CRM_CHECK(task != NULL, goto bail);
+ CRM_CHECK(rsc_id != NULL, goto bail);
if(interval > 0) {
attr_name = crm_concat("fail-count", rsc_id, '-');
crm_warn("Updating failcount for %s on %s after failed %s: rc=%d",
rsc_id, on_uuid, task, rc);
update_attr(te_cib_conn, cib_none, XML_CIB_TAG_STATUS,
on_uuid, NULL,NULL, attr_name,
XML_NVPAIR_ATTR_VALUE"++");
crm_free(attr_name);
}
+ bail:
crm_free(rsc_id);
crm_free(task);
}
static int
status_from_rc(crm_action_t *action, int orig_status, int rc)
{
int status = orig_status;
const char *target_rc_s = g_hash_table_lookup(
action->params, crm_meta_name(XML_ATTR_TE_TARGET_RC));
if(target_rc_s != NULL) {
int target_rc = 0;
crm_debug_2("Target rc: %s vs. %d", target_rc_s, rc);
target_rc = crm_parse_int(target_rc_s, NULL);
if(target_rc == rc) {
crm_debug_2("Target rc: == %d", rc);
if(status != LRM_OP_DONE) {
crm_debug_2("Re-mapping op status to"
" LRM_OP_DONE for rc=%d", rc);
status = LRM_OP_DONE;
}
} else {
crm_debug_2("Target rc: != %d", rc);
if(status != LRM_OP_ERROR) {
crm_info("Re-mapping op status to"
" LRM_OP_ERROR for rc=%d", rc);
status = LRM_OP_ERROR;
}
}
}
/* 99 is the code we use for direct nack's */
if(rc != 99 && status != LRM_OP_DONE) {
const char *task, *uname;
task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
uname = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
crm_warn("Action %s on %s failed (target: %s vs. rc: %d): %s",
task, uname, target_rc_s, rc, op_status2text(status));
}
return status;
}
/*
* returns the ID of the action if a match is found
* returns -1 if a match was not found
* returns -2 if a match was found but the action failed (and was
* not allowed to)
*/
int
match_graph_event(int action_id, crm_data_t *event, const char *event_node,
int op_status, int op_rc)
{
const char *allow_fail = NULL;
const char *this_event = ID(event);
crm_action_t *action = NULL;
action = get_action(action_id, FALSE);
if(action == NULL) {
return -1;
}
op_status = status_from_rc(action, op_status, op_rc);
if(op_status != LRM_OP_DONE) {
update_failcount(event, event_node, op_rc);
}
/* Process OP status */
switch(op_status) {
case LRM_OP_PENDING:
crm_debug("Ignoring pending operation");
return action->id;
break;
case LRM_OP_DONE:
break;
case LRM_OP_ERROR:
case LRM_OP_TIMEOUT:
case LRM_OP_NOTSUPPORTED:
action->failed = TRUE;
break;
case LRM_OP_CANCELLED:
/* do nothing?? */
crm_err("Dont know what to do for cancelled ops yet");
break;
default:
action->failed = TRUE;
crm_err("Unsupported action result: %d", op_status);
}
/* stop this event's timer if it had one */
stop_te_timer(action->timer);
action->confirmed = TRUE;
update_graph(transition_graph, action);
trigger_graph();
if(action->failed) {
allow_fail = g_hash_table_lookup(
action->params, crm_meta_name(XML_ATTR_TE_ALLOWFAIL));
if(crm_is_true(allow_fail)) {
action->failed = FALSE;
}
}
if(action->failed) {
abort_transition(action->synapse->priority+1,
tg_restart, "Event failed", event);
}
te_log_action(LOG_INFO, "Action %s (%d) confirmed on %s",
this_event, action->id, event_node);
return action->id;
}
crm_action_t *
get_action(int id, gboolean confirmed)
{
slist_iter(
synapse, synapse_t, transition_graph->synapses, lpc,
slist_iter(
action, crm_action_t, synapse->actions, lpc2,
if(action->id == id) {
if(confirmed) {
stop_te_timer(action->timer);
action->confirmed = TRUE;
}
return action;
}
)
);
return NULL;
}
crm_action_t *
match_down_event(int id, const char *target, const char *filter)
{
const char *this_action = NULL;
const char *this_node = NULL;
crm_action_t *match = NULL;
slist_iter(
synapse, synapse_t, transition_graph->synapses, lpc,
/* lookup event */
slist_iter(
action, crm_action_t, synapse->actions, lpc2,
if(id > 0 && action->id == id) {
match = action;
break;
}
this_action = crm_element_value(
action->xml, XML_LRM_ATTR_TASK);
if(action->type != action_type_crm) {
continue;
} else if(safe_str_eq(this_action, CRM_OP_LRM_REFRESH)){
continue;
} else if(filter != NULL
&& safe_str_neq(this_action, filter)) {
continue;
}
this_node = crm_element_value(
action->xml, XML_LRM_ATTR_TARGET_UUID);
if(this_node == NULL) {
crm_log_xml_err(action->xml, "No node uuid");
}
if(safe_str_neq(this_node, target)) {
crm_debug("Action %d : Node mismatch: %s",
action->id, this_node);
continue;
}
match = action;
break;
);
if(match != NULL) {
/* stop this event's timer if it had one */
break;
}
);
if(match != NULL) {
/* stop this event's timer if it had one */
crm_debug("Match found for action %d: %s on %s", id,
crm_element_value(match->xml, XML_LRM_ATTR_TASK_KEY),
target);
stop_te_timer(match->timer);
match->confirmed = TRUE;
} else if(id > 0) {
crm_err("No match for action %d", id);
} else {
crm_warn("No match for shutdown action on %s", target);
}
return match;
}
void
process_graph_event(crm_data_t *event, const char *event_node)
{
int rc = -1;
int status = -1;
int action = -1;
int transition_num = -1;
char *update_te_uuid = NULL;
gboolean passed = FALSE;
const char *id = NULL;
const char *magic = NULL;
CRM_ASSERT(event != NULL);
id = ID(event);
magic = crm_element_value(event, XML_ATTR_TRANSITION_MAGIC);
if(magic == NULL) {
/* non-change */
return;
}
CRM_CHECK(decode_transition_magic(
magic, &update_te_uuid, &transition_num, &action,
&status, &rc),
crm_err("Invalid event %s detected", id);
abort_transition(INFINITY, tg_restart,"Bad event", event);
);
if(transition_num == -1) {
crm_err("Action %s initiated outside of a transition", id);
abort_transition(INFINITY, tg_restart,"Unexpected event",event);
} else if(action < 0 || safe_str_neq(update_te_uuid, te_uuid)) {
crm_info("Action %s initiated by a different transitioner", id);
abort_transition(INFINITY, tg_restart,"Foreign event", event);
} else if(transition_graph->id != transition_num) {
crm_info("Detected action %s from a different transition:"
" %d vs. %d", id, transition_num, transition_graph->id);
abort_transition(INFINITY, tg_restart,"Old event", event);
} else if(transition_graph->complete) {
crm_info("Action %s arrived after a completed transition", id);
abort_transition(INFINITY, tg_restart, "Inactive graph", event);
} else if(match_graph_event(
action, event, event_node, status, rc) < 0) {
crm_err("Unknown graph action %s", id);
abort_transition(INFINITY, tg_restart, "Unknown event", event);
} else {
passed = TRUE;
crm_debug("Processed update to %s: %s", id, magic);
}
if(passed == FALSE && rc != EXECRA_OK) {
update_failcount(event, event_node, rc);
}
crm_free(update_te_uuid);
return;
}
diff --git a/lib/crm/common/iso8601.c b/lib/crm/common/iso8601.c
index 88f641ca59..301eb604a4 100644
--- a/lib/crm/common/iso8601.c
+++ b/lib/crm/common/iso8601.c
@@ -1,1278 +1,1283 @@
/* $Id: iso8601.c,v 1.15 2006/05/29 11:53:53 andrew Exp $ */
/*
* Copyright (C) 2005 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
*/
/*
* Primary reference:
* http://en.wikipedia.org/wiki/ISO_8601 (as at 2005-08-01)
*
* Secondary references:
* http://hydracen.com/dx/iso8601.htm
* http://www.personal.ecu.edu/mccartyr/ISOwdALG.txt
* http://www.personal.ecu.edu/mccartyr/isowdcal.html
* http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
*
*/
#include <portability.h>
#include <crm/crm.h>
#include <time.h>
#include <ctype.h>
#include <crm/common/iso8601.h>
gboolean gregorian_to_ordinal(ha_time_t *a_date);
gboolean ordinal_to_gregorian(ha_time_t *a_date);
gboolean ordinal_to_weekdays(ha_time_t *a_date);
void normalize_time(ha_time_t *a_time);
/*
* Andrew's code was originally written for OSes whose "struct tm" contains:
* long tm_gmtoff; :: Seconds east of UTC
* const char *tm_zone; :: Timezone abbreviation
* Some OSes lack these, instead having:
* time_t (or long) timezone;
:: "difference between UTC and local standard time"
* char *tzname[2] = { "...", "..." };
* I (David Lee) confess to not understanding the details. So my attempted
* generalisations for where their use is necessary may be flawed.
*
* 1. Does "difference between ..." subtract the same or opposite way?
* 2. Should it use "altzone" instead of "timezone"?
* 3. Should it use tzname[0] or tzname[1]? Interaction with timezone/altzone?
*/
#if defined(HAVE_TM_GMTOFF)
#define GMTOFF(tm) ((tm)->tm_gmtoff)
#else
/* Note: extern variable; macro argument not actually used. */
#define GMTOFF(tm) (timezone)
#endif
char *
date_to_string(ha_time_t *date_time, int flags)
{
char *date_s = NULL;
char *time_s = NULL;
char *offset_s = NULL;
char *result_s = NULL;
ha_time_t *dt = NULL;
if(flags & ha_log_local) {
crm_debug_6("Local version");
dt = date_time;
} else {
dt = date_time->normalized;
}
CRM_CHECK(dt != NULL, return NULL);
if(flags & ha_log_date) {
crm_malloc0(date_s, 32);
if(date_s == NULL) {
return NULL;
} else if(flags & ha_date_weeks) {
snprintf(date_s, 31, "%d-W%.2d-%d",
dt->weekyears, dt->weeks, dt->weekdays);
} else if(flags & ha_date_ordinal) {
snprintf(date_s, 31, "%d-%.3d",dt->years, dt->yeardays);
} else {
snprintf(date_s, 31, "%.4d-%.2d-%.2d",
dt->years, dt->months, dt->days);
}
}
if(flags & ha_log_time) {
int offset = 0;
crm_malloc0(time_s, 32);
if(time_s == NULL) {
return NULL;
}
snprintf(time_s, 31, "%.2d:%.2d:%.2d",
dt->hours, dt->minutes, dt->seconds);
if(dt->offset != NULL) {
offset =(dt->offset->hours * 100) + dt->offset->minutes;
}
crm_malloc0(offset_s, 32);
if((flags & ha_log_local) == 0 || offset == 0) {
snprintf(offset_s, 31, "Z");
} else {
int hr = dt->offset->hours;
int mins = dt->offset->minutes;
if(hr < 0) {
hr = 0 - hr;
}
if(mins < 0) {
mins = 0 - mins;
}
snprintf(offset_s, 31, " %s%.2d:%.2d",
offset>0?"+":"-", hr, mins);
}
}
crm_malloc0(result_s, 100);
snprintf(result_s, 100, "%s%s%s%s",
date_s?date_s:"", (date_s!=NULL&&time_s!=NULL)?" ":"",
time_s?time_s:"", offset_s?offset_s:"");
crm_free(date_s);
crm_free(time_s);
crm_free(offset_s);
return result_s;
}
void
log_date(int log_level, const char *prefix, ha_time_t *date_time, int flags)
{
char *date_s = date_to_string(date_time, flags);
do_crm_log(log_level, "%s%s%s",
prefix?prefix:"", prefix?": ":"",
date_s?date_s:"__invalid_date__");
crm_free(date_s);
}
void
log_time_period(int log_level, ha_time_period_t *dtp, int flags)
{
log_date(log_level, "Period start:", dtp->start, flags);
log_date(log_level, "Period end:", dtp->end, flags);
}
ha_time_t*
parse_time_offset(char **offset_str)
{
ha_time_t *new_time = NULL;
crm_malloc0(new_time, sizeof(ha_time_t));
crm_malloc0(new_time->has, sizeof(ha_has_time_t));
if((*offset_str)[0] == 'Z') {
} else if((*offset_str)[0] == '+'
|| (*offset_str)[0] == '-'
|| isdigit((int) (*offset_str)[0])) {
gboolean negate = FALSE;
if((*offset_str)[0] == '-') {
negate = TRUE;
(*offset_str)++;
}
parse_time(offset_str, new_time, FALSE);
if(negate) {
new_time->hours = 0 - new_time->hours;
new_time->minutes = 0 - new_time->minutes;
new_time->seconds = 0 - new_time->seconds;
}
} else {
#if defined(HAVE_TM_GMTOFF)
time_t now = time(NULL);
struct tm *now_tm = localtime(&now);
#endif
int h_offset = GMTOFF(now_tm) / (3600);
int m_offset = (GMTOFF(now_tm) - (3600 * h_offset)) / (60);
if(h_offset < 0 && m_offset < 0) {
m_offset = 0 - m_offset;
}
new_time->hours = h_offset;
new_time->minutes = m_offset;
new_time->has->hours = TRUE;
new_time->has->minutes = TRUE;
}
return new_time;
}
ha_time_t*
parse_time(char **time_str, ha_time_t *a_time, gboolean with_offset)
{
ha_time_t *new_time = a_time;
tzset();
if(a_time == NULL) {
new_time = new_ha_date(FALSE);
}
CRM_CHECK(new_time != NULL, return NULL);
CRM_CHECK(new_time->has != NULL, free_ha_date(new_time); return NULL);
crm_debug_4("Get hours...");
if(parse_int(time_str, 2, 24, &new_time->hours)) {
new_time->has->hours = TRUE;
}
crm_debug_4("Get minutes...");
if(parse_int(time_str, 2, 60, &new_time->minutes)) {
new_time->has->minutes = TRUE;
}
crm_debug_4("Get seconds...");
if(parse_int(time_str, 2, 60, &new_time->seconds)){
new_time->has->seconds = TRUE;
}
if(with_offset) {
crm_debug_4("Get offset...");
while(isspace((int) (*time_str)[0])) {
(*time_str)++;
}
new_time->offset = parse_time_offset(time_str);
normalize_time(new_time);
}
return new_time;
}
void
normalize_time(ha_time_t *a_time)
{
CRM_CHECK(a_time != NULL, return);
CRM_CHECK(a_time->has != NULL, return);
if(a_time->normalized == NULL) {
crm_malloc0(a_time->normalized, sizeof(ha_time_t));
}
if(a_time->normalized->has == NULL) {
crm_malloc0(a_time->normalized->has, sizeof(ha_has_time_t));
}
ha_set_time(a_time->normalized, a_time, FALSE);
if(a_time->offset != NULL) {
if(a_time->offset->has->hours) {
sub_hours(a_time->normalized, a_time->offset->hours);
}
if(a_time->offset->has->minutes) {
sub_minutes(a_time->normalized,a_time->offset->minutes);
}
if(a_time->offset->has->seconds) {
sub_seconds(a_time->normalized,a_time->offset->seconds);
}
}
CRM_CHECK(is_date_sane(a_time), return);
}
ha_time_t *
parse_date(char **date_str)
{
gboolean is_done = FALSE;
gboolean converted = FALSE;
ha_time_t *new_time = NULL;
CRM_CHECK(date_str != NULL, return NULL);
CRM_CHECK(strlen(*date_str) > 0, return NULL);
crm_malloc0(new_time, sizeof(ha_time_t));
crm_malloc0(new_time->has, sizeof(ha_has_time_t));
while(is_done == FALSE) {
char ch = (*date_str)[0];
crm_debug_5("Switching on ch=%c (len=%d)",
ch, (int)strlen(*date_str));
if(ch == 0) {
/* all done */
is_done = TRUE;
break;
} else if(ch == '/') {
/* all done - interval marker */
is_done = TRUE;
break;
} else if(ch == 'W') {
CRM_CHECK(new_time->has->weeks == FALSE, ;);
(*date_str)++;
if(parse_int(date_str, 2, 53, &new_time->weeks)){
new_time->has->weeks = TRUE;
new_time->weekyears = new_time->years;
new_time->has->weekyears = new_time->has->years;
}
if((*date_str)[0] == '-') {
(*date_str)++;
if(parse_int(date_str, 1, 7, &new_time->weekdays)) {
new_time->has->weekdays = TRUE;
}
}
if(new_time->weekdays == 0
|| new_time->has->weekdays == FALSE) {
new_time->weekdays = 1;
new_time->has->weekdays = TRUE;
}
} else if(ch == '-') {
(*date_str)++;
if(check_for_ordinal(*date_str)) {
if(parse_int(date_str, 3, 366, &new_time->yeardays)) {
new_time->has->yeardays = TRUE;
}
}
} else if(ch == 'O') {
/* ordinal date */
(*date_str)++;
if(parse_int(date_str, 3, 366, &new_time->yeardays)){
new_time->has->yeardays = TRUE;
}
} else if(ch == 'T' || ch == ' ') {
if(new_time->has->yeardays) {
converted = convert_from_ordinal(new_time);
} else if(new_time->has->weekdays) {
converted = convert_from_weekdays(new_time);
} else {
converted = convert_from_gregorian(new_time);
}
(*date_str)++;
parse_time(date_str, new_time, TRUE);
is_done = TRUE;
} else if(isdigit((int) ch)) {
if(new_time->has->years == FALSE
&& parse_int(date_str, 4, 9999, &new_time->years)) {
new_time->has->years = TRUE;
} else if(check_for_ordinal(*date_str) && parse_int(
date_str, 3,
is_leap_year(new_time->years)?366:365,
&new_time->yeardays)) {
new_time->has->yeardays = TRUE;
} else if(new_time->has->months == FALSE
&& parse_int(date_str, 2, 12, &new_time->months)) {
new_time->has->months = TRUE;
} else if(new_time->has->days == FALSE) {
if(parse_int(date_str, 2,
days_per_month(new_time->months, new_time->years),
&new_time->days)) {
new_time->has->days = TRUE;
}
}
} else {
crm_err("Unexpected characters at: %s", *date_str);
is_done = TRUE;
break;
}
}
if(converted) {
} else if(new_time->has->yeardays) {
convert_from_ordinal(new_time);
} else if(new_time->has->weekdays) {
convert_from_weekdays(new_time);
} else {
convert_from_gregorian(new_time);
}
normalize_time(new_time);
log_date(LOG_DEBUG_3, "Unpacked", new_time, ha_log_date|ha_log_time);
CRM_CHECK(is_date_sane(new_time), return NULL);
return new_time;
}
ha_time_t*
parse_time_duration(char **interval_str)
{
gboolean is_time = FALSE;
ha_time_t *diff = NULL;
crm_malloc0(diff, sizeof(ha_time_t));
crm_malloc0(diff->has, sizeof(ha_has_time_t));
- CRM_CHECK(interval_str != NULL, return NULL);
- CRM_CHECK(strlen(*interval_str) > 0, return NULL);
+ CRM_CHECK(interval_str != NULL, goto bail);
+ CRM_CHECK(strlen(*interval_str) > 0, goto bail);
- CRM_CHECK((*interval_str)[0] == 'P', return NULL);
+ CRM_CHECK((*interval_str)[0] == 'P', goto bail);
(*interval_str)++;
while(isspace((int) (*interval_str)[0]) == FALSE) {
int an_int = 0;
char ch = 0;
if((*interval_str)[0] == 'T') {
is_time = TRUE;
(*interval_str)++;
}
if(parse_int(interval_str, 10, 0, &an_int) == FALSE) {
break;
}
ch = (*interval_str)[0];
(*interval_str)++;
crm_debug_4("%c=%d", ch, an_int);
switch(ch) {
case 0:
return diff;
break;
case 'Y':
diff->years = an_int;
diff->has->years = TRUE;
break;
case 'M':
if(is_time) {
diff->minutes = an_int;
diff->has->minutes = TRUE;
} else {
diff->months = an_int;
diff->has->months = TRUE;
}
break;
case 'W':
diff->weeks = an_int;
diff->has->weeks = TRUE;
break;
case 'D':
diff->days = an_int;
diff->has->days = TRUE;
break;
case 'H':
diff->hours = an_int;
diff->has->hours = TRUE;
break;
case 'S':
diff->seconds = an_int;
diff->has->seconds = TRUE;
break;
default:
break;
}
}
return diff;
+
+ bail:
+ crm_free(diff);
+ crm_free(diff->has);
+ return NULL;
}
ha_time_period_t*
parse_time_period(char **period_str)
{
gboolean invalid = FALSE;
const char *original = *period_str;
ha_time_period_t *period = NULL;
CRM_CHECK(period_str != NULL, return NULL);
CRM_CHECK(strlen(*period_str) > 0, return NULL);
tzset();
crm_malloc0(period, sizeof(ha_time_period_t));
if((*period_str)[0] == 'P') {
period->diff = parse_time_duration(period_str);
} else {
period->start = parse_date(period_str);
}
if((*period_str)[0] != 0) {
CRM_CHECK((*period_str)[0] == '/', invalid = TRUE; goto bail);
(*period_str)++;
if((*period_str)[0] == 'P') {
period->diff = parse_time_duration(period_str);
} else {
period->end = parse_date(period_str);
}
} else if(period->diff != NULL) {
/* just aduration starting from now */
time_t now = time(NULL);
crm_malloc0(period->start, sizeof(ha_time_t));
crm_malloc0(period->start->has, sizeof(ha_has_time_t));
crm_malloc0(period->start->offset, sizeof(ha_time_t));
crm_malloc0(period->start->offset->has, sizeof(ha_has_time_t));
ha_set_timet_time(period->start, &now);
normalize_time(period->start);
} else {
invalid = TRUE;
CRM_CHECK((*period_str)[0] == '/', goto bail);
goto bail;
}
/* sanity checks */
if(period->start == NULL && period->end == NULL) {
crm_err("Invalid time period: %s", original);
invalid = TRUE;
} else if(period->start == NULL && period->diff == NULL) {
crm_err("Invalid time period: %s", original);
invalid = TRUE;
} else if(period->end == NULL && period->diff == NULL) {
crm_err("Invalid time period: %s", original);
invalid = TRUE;
}
bail:
if(invalid) {
crm_free(period->start);
crm_free(period->end);
crm_free(period->diff);
crm_free(period);
return NULL;
}
if(period->end == NULL && period->diff == NULL) {
}
if(period->start == NULL) {
period->start = subtract_time(period->end, period->diff);
normalize_time(period->start);
} else if(period->end == NULL) {
period->end = add_time(period->start, period->diff);
normalize_time(period->end);
}
is_date_sane(period->start);
is_date_sane(period->end);
return period;
}
int month2days[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
/* http://www.personal.ecu.edu/mccartyr/ISOwdALG.txt */
int
january1(int year)
{
int YY = (year - 1) % 100;
int C = (year - 1) - YY;
int G = YY + YY/4;
int jan1 = 1 + (((((C / 100) % 4) * 5) + G) % 7);
crm_debug_6("YY=%d, C=%d, G=%d", YY, C, G);
crm_debug_5("January 1 %.4d: %d", year, jan1);
return jan1;
}
int
weeks_in_year(int year)
{
int weeks = 52;
int jan1 = january1(year);
/* if jan1 == thursday */
if(jan1 == 4) {
weeks++;
} else {
jan1 = january1(year+1);
/* if dec31 == thursday aka. jan1 of next year is a friday */
if(jan1 == 5) {
weeks++;
}
}
return weeks;
}
gboolean
convert_from_gregorian(ha_time_t *a_date)
{
CRM_CHECK(gregorian_to_ordinal(a_date), return FALSE);
CRM_CHECK(ordinal_to_weekdays(a_date), return FALSE);
return TRUE;
}
gboolean
gregorian_to_ordinal(ha_time_t *a_date)
{
CRM_CHECK(a_date->has->years, return FALSE);
CRM_CHECK(a_date->has->months, return FALSE);
CRM_CHECK(a_date->has->days, return FALSE);
CRM_CHECK(a_date->months > 0, return FALSE);
CRM_CHECK(a_date->days > 0, return FALSE);
a_date->yeardays = month2days[a_date->months-1];
a_date->yeardays += a_date->days;
a_date->has->yeardays = TRUE;
if(is_leap_year(a_date->years) && a_date->months > 2) {
(a_date->yeardays)++;
}
crm_debug_4("Converted %.4d-%.2d-%.2d to %.4d-%.3d",
a_date->years, a_date->months, a_date->days,
a_date->years, a_date->yeardays);
return TRUE;
}
gboolean
convert_from_ordinal(ha_time_t *a_date)
{
CRM_CHECK(ordinal_to_gregorian(a_date), return FALSE);
CRM_CHECK(ordinal_to_weekdays(a_date), return FALSE);
return TRUE;
}
gboolean ordinal_to_gregorian(ha_time_t *a_date)
{
CRM_CHECK(a_date->has->years, return FALSE);
CRM_CHECK(a_date->has->yeardays, return FALSE);
CRM_CHECK(a_date->yeardays > 0, return FALSE);
a_date->days = a_date->yeardays;
a_date->months = 11;
if(is_leap_year(a_date->years) && a_date->yeardays > 366) {
crm_err("Year %.4d only has 366 days (supplied %.3d)",
a_date->years, a_date->yeardays);
a_date->yeardays = 366;
} else if(!is_leap_year(a_date->years) && a_date->yeardays > 365) {
crm_err("Year %.4d only has 365 days (supplied %.3d)",
a_date->years, a_date->yeardays);
a_date->yeardays = 365;
}
while(a_date->months > 0
&& a_date->yeardays <= month2days[a_date->months]) {
crm_debug_6("month %d: %d vs. %d",
a_date->months, a_date->yeardays,
month2days[a_date->months]);
(a_date->months)--;
}
a_date->days -= month2days[a_date->months];
(a_date->months)++;
CRM_CHECK(a_date->months > 0, return FALSE);
if(is_leap_year(a_date->years) && a_date->months > 2) {
(a_date->days)--;
}
if(a_date->days == 0) {
/* annoying underflow */
a_date->days = days_per_month(a_date->months, a_date->years);
(a_date->months)--;
}
a_date->has->days = TRUE;
a_date->has->months = TRUE;
a_date->has->years = TRUE;
crm_debug_4("Converted %.4d-%.3d to %.4d-%.2d-%.2d",
a_date->years, a_date->yeardays,
a_date->years, a_date->months, a_date->days);
return TRUE;
}
gboolean
ordinal_to_weekdays(ha_time_t *a_date)
{
int year_num = 0;
int jan1 = january1(a_date->years);
int h = -1;
CRM_CHECK(a_date->has->years, return FALSE);
CRM_CHECK(a_date->has->yeardays, return FALSE);
CRM_CHECK(a_date->yeardays > 0, return FALSE);
h = a_date->yeardays + jan1 - 1;
a_date->weekdays = 1 + ((h-1) % 7);
a_date->has->weekdays = TRUE;
if(a_date->yeardays <= (8-jan1) && jan1 > 4) {
year_num = a_date->years - 1;
a_date->weeks = weeks_in_year(year_num);
a_date->has->weeks = TRUE;
} else {
year_num = a_date->years;
}
if(year_num == a_date->years) {
int i = 365;
if(is_leap_year(year_num)) {
i = 366;
}
if( (i - a_date->yeardays) < (4 - a_date->weekdays) ) {
year_num = a_date->years + 1;
a_date->weeks = 1;
a_date->has->weeks = TRUE;
}
}
if(year_num == a_date->years) {
int j = a_date->yeardays + (7-a_date->weekdays) + (jan1 - 1);
a_date->weeks = j / 7;
a_date->has->weeks = TRUE;
if(jan1 > 4) {
a_date->weeks -= 1;
}
}
a_date->weekyears = year_num;
a_date->has->weekyears = TRUE;
crm_debug_4("Converted %.4d-%.3d to %.4dW%.2d-%d",
a_date->years, a_date->yeardays,
a_date->weekyears, a_date->weeks, a_date->weekdays);
return TRUE;
}
gboolean
convert_from_weekdays(ha_time_t *a_date)
{
gboolean conversion = FALSE;
int jan1 = january1(a_date->weekyears);
CRM_CHECK(a_date->has->weekyears, return FALSE);
CRM_CHECK(a_date->has->weeks, return FALSE);
CRM_CHECK(a_date->has->weekdays, return FALSE);
CRM_CHECK(a_date->weeks > 0, return FALSE);
CRM_CHECK(a_date->weekdays > 0, return FALSE);
CRM_CHECK(a_date->weekdays < 8, return FALSE);
a_date->has->years = TRUE;
a_date->years = a_date->weekyears;
a_date->has->yeardays = TRUE;
a_date->yeardays = (7 * (a_date->weeks-1));
/* break up the addition to make sure overflows are correctly handled */
if(a_date->yeardays == 0) {
a_date->yeardays = a_date->weekdays;
} else {
add_yeardays(a_date, a_date->weekdays);
}
crm_debug_5("Pre-conversion: %dW%d-%d to %.4d-%.3d",
a_date->weekyears, a_date->weeks, a_date->weekdays,
a_date->years, a_date->yeardays);
conversion = ordinal_to_gregorian(a_date);
if(conversion) {
if(jan1 < 4) {
sub_days(a_date, jan1-1);
} else if(jan1 > 4) {
add_days(a_date, jan1-4);
}
}
return conversion;
}
void
ha_set_time(ha_time_t *lhs, ha_time_t *rhs, gboolean offset)
{
crm_debug_6("lhs=%p, rhs=%p, offset=%d", lhs, rhs, offset);
CRM_CHECK(lhs != NULL && rhs != NULL, return);
CRM_CHECK(lhs->has != NULL && rhs->has != NULL, return);
lhs->years = rhs->years;
lhs->has->years = rhs->has->years;
lhs->weekyears = rhs->weekyears;
lhs->has->weekyears = rhs->has->weekyears;
lhs->months = rhs->months;
lhs->has->months = rhs->has->months;
lhs->weeks = rhs->weeks;
lhs->has->weeks = rhs->has->weeks;
lhs->days = rhs->days;
lhs->has->days = rhs->has->days;
lhs->weekdays = rhs->weekdays;
lhs->has->weekdays = rhs->has->weekdays;
lhs->yeardays = rhs->yeardays;
lhs->has->yeardays = rhs->has->yeardays;
lhs->hours = rhs->hours;
lhs->has->hours = rhs->has->hours;
lhs->minutes = rhs->minutes;
lhs->has->minutes = rhs->has->minutes;
lhs->seconds = rhs->seconds;
lhs->has->seconds = rhs->has->seconds;
if(lhs->offset) {
reset_time(lhs->offset);
}
if(offset && rhs->offset) {
ha_set_time(lhs->offset, rhs->offset, FALSE);
}
}
void
ha_set_tm_time(ha_time_t *lhs, struct tm *rhs)
{
int wday = rhs->tm_wday;
int h_offset = 0;
int m_offset = 0;
if(rhs->tm_year > 0) {
/* years since 1900 */
lhs->years = 1900 + rhs->tm_year;
lhs->has->years = TRUE;
}
if(rhs->tm_yday >= 0) {
/* days since January 1 [0-365] */
lhs->yeardays = 1 + rhs->tm_yday;
lhs->has->yeardays =TRUE;
}
if(rhs->tm_hour >= 0) {
lhs->hours = rhs->tm_hour;
lhs->has->hours =TRUE;
}
if(rhs->tm_min >= 0) {
lhs->minutes = rhs->tm_min;
lhs->has->minutes =TRUE;
}
if(rhs->tm_sec >= 0) {
lhs->seconds = rhs->tm_sec;
lhs->has->seconds =TRUE;
}
convert_from_ordinal(lhs);
/* months since January [0-11] */
CRM_CHECK(rhs->tm_mon < 0 || lhs->months == (1 + rhs->tm_mon), return);
/* day of the month [1-31] */
CRM_CHECK(rhs->tm_mday < 0 || lhs->days == rhs->tm_mday, return);
/* days since Sunday [0-6] */
if(wday == 0) {
wday= 7;
}
CRM_CHECK(rhs->tm_wday < 0 || lhs->weekdays == wday, return);
CRM_CHECK(lhs->offset != NULL, return);
CRM_CHECK(lhs->offset->has != NULL, return);
/* tm_gmtoff == offset from UTC in seconds */
h_offset = GMTOFF(rhs) / (3600);
m_offset = (GMTOFF(rhs) - (3600 * h_offset)) / (60);
crm_debug_6("Offset (s): %ld, offset (hh:mm): %.2d:%.2d",
GMTOFF(rhs), h_offset, m_offset);
lhs->offset->hours = h_offset;
lhs->offset->has->hours = TRUE;
lhs->offset->minutes = m_offset;
lhs->offset->has->minutes = TRUE;
normalize_time(lhs);
}
void
ha_set_timet_time(ha_time_t *lhs, time_t *rhs)
{
ha_set_tm_time(lhs, localtime(rhs));
}
ha_time_t *
add_time(ha_time_t *lhs, ha_time_t *rhs)
{
ha_time_t *answer = NULL;
CRM_CHECK(lhs != NULL && rhs != NULL, return NULL);
answer = new_ha_date(FALSE);
ha_set_time(answer, lhs, TRUE);
normalize_time(lhs);
normalize_time(answer);
if(rhs->has->years) {
add_years(answer, rhs->years);
}
if(rhs->has->months) {
add_months(answer, rhs->months);
}
if(rhs->has->weeks) {
add_weeks(answer, rhs->weeks);
}
if(rhs->has->days) {
add_days(answer, rhs->days);
}
add_hours(answer, rhs->hours);
add_minutes(answer, rhs->minutes);
add_seconds(answer, rhs->seconds);
normalize_time(answer);
return answer;
}
ha_time_t *
subtract_time(ha_time_t *lhs, ha_time_t *rhs)
{
ha_time_t *answer = NULL;
CRM_CHECK(lhs != NULL && rhs != NULL, return NULL);
answer = new_ha_date(FALSE);
ha_set_time(answer, lhs, TRUE);
normalize_time(lhs);
normalize_time(rhs);
normalize_time(answer);
sub_years(answer, rhs->years);
sub_months(answer, rhs->months);
sub_weeks(answer, rhs->weeks);
sub_days(answer, rhs->days);
sub_hours(answer, rhs->hours);
sub_minutes(answer, rhs->minutes);
sub_seconds(answer, rhs->seconds);
normalize_time(answer);
return answer;
}
/* ha_time_interval_t* */
/* parse_time_interval(char **interval_str) */
/* { */
/* return NULL; */
/* } */
int month_days[14] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 29 };
int
days_per_month(int month, int year)
{
if(month == 2 && is_leap_year(year)) {
month = 13;
}
return month_days[month];
}
gboolean
is_leap_year(int year)
{
gboolean is_leap = FALSE;
if(year % 4 == 0) {
is_leap = TRUE;
}
if(year % 100 == 0 && year % 400 != 0 ) {
is_leap = FALSE;
}
return is_leap;
}
gboolean
parse_int(char **str, int field_width, int uppper_bound, int *result)
{
int lpc = 0;
int intermediate = 0;
gboolean fraction = FALSE;
gboolean negate = FALSE;
CRM_CHECK(str != NULL, return FALSE);
CRM_CHECK(*str != NULL, return FALSE);
CRM_CHECK(result != NULL, return FALSE);
*result = 0;
if(strlen(*str) <= 0) {
return FALSE;
}
crm_debug_6("max width: %d, first char: %c", field_width, (*str)[0]);
if((*str)[0] == '.' || (*str)[0] == ',') {
fraction = TRUE;
field_width = -1;
(*str)++;
} else if((*str)[0] == '-') {
negate = TRUE;
(*str)++;
} else if((*str)[0] == '+'
|| (*str)[0] == ':') {
(*str)++;
}
for(; (fraction || lpc < field_width) && isdigit((int) (*str)[0]); lpc++) {
if(fraction) {
intermediate = ((*str)[0] - '0')/(10^lpc);
} else {
*result *= 10;
intermediate = (*str)[0] - '0';
}
*result += intermediate;
(*str)++;
}
if(fraction) {
*result = (int)(*result * uppper_bound);
} else if(uppper_bound > 0 && *result > uppper_bound) {
*result = uppper_bound;
}
if(negate) {
*result = 0 - *result;
}
if(lpc > 0) {
crm_debug_5("Found int: %d", *result);
return TRUE;
}
return FALSE;
}
gboolean
check_for_ordinal(const char *str)
{
if(isdigit((int) str[2]) == FALSE) {
crm_debug_6("char 3 == %c", str[2]);
return FALSE;
}
if(isspace((int) str[3])) {
return TRUE;
} else if(str[3] == 0) {
return TRUE;
} else if(str[3] == 'T') {
return TRUE;
} else if(str[3] == '/') {
return TRUE;
}
crm_debug_6("char 4 == %c", str[3]);
return FALSE;
}
int str_lookup(const char *str, enum date_fields field)
{
return 0;
}
void
reset_time(ha_time_t *a_time)
{
a_time->years = 0;
a_time->has->years = FALSE;
a_time->weekyears = 0;
a_time->has->weekyears = FALSE;
a_time->months = 0;
a_time->has->months = FALSE;
a_time->weeks = 0;
a_time->has->weeks = FALSE;
a_time->days = 0;
a_time->has->days = FALSE;
a_time->weekdays = 0;
a_time->has->weekdays = FALSE;
a_time->yeardays = 0;
a_time->has->yeardays = FALSE;
a_time->hours = 0;
a_time->has->hours = FALSE;
a_time->minutes = 0;
a_time->has->minutes = FALSE;
a_time->seconds = 0;
a_time->has->seconds = FALSE;
}
void
reset_tm(struct tm *some_tm)
{
some_tm->tm_sec = -1; /* seconds after the minute [0-60] */
some_tm->tm_min = -1; /* minutes after the hour [0-59] */
some_tm->tm_hour = -1; /* hours since midnight [0-23] */
some_tm->tm_mday = -1; /* day of the month [1-31] */
some_tm->tm_mon = -1; /* months since January [0-11] */
some_tm->tm_year = -1; /* years since 1900 */
some_tm->tm_wday = -1; /* days since Sunday [0-6] */
some_tm->tm_yday = -1; /* days since January 1 [0-365] */
some_tm->tm_isdst = -1; /* Daylight Savings Time flag */
#if defined(HAVE_TM_GMTOFF)
some_tm->tm_gmtoff = -1; /* offset from CUT in seconds */
#endif
#if defined(HAVE_TM_ZONE)
some_tm->tm_zone = NULL;/* timezone abbreviation */
#endif
}
gboolean
is_date_sane(ha_time_t *a_date)
{
int ydays = 0;
int mdays = 0;
int weeks = 0;
CRM_CHECK(a_date != NULL, return FALSE);
ydays = is_leap_year(a_date->years)?366:365;
mdays = days_per_month(a_date->months, a_date->years);
weeks = weeks_in_year(a_date->weekyears);
crm_debug_5("max ydays: %d, max mdays: %d, max weeks: %d",
ydays, mdays, weeks);
CRM_CHECK(a_date->has->years, return FALSE);
CRM_CHECK(a_date->has->weekyears, return FALSE);
CRM_CHECK(a_date->has->months, return FALSE);
CRM_CHECK(a_date->months > 0, return FALSE);
CRM_CHECK(a_date->months <= 12, return FALSE);
CRM_CHECK(a_date->has->weeks, return FALSE);
CRM_CHECK(a_date->weeks > 0, return FALSE);
CRM_CHECK(a_date->weeks <= weeks, return FALSE);
CRM_CHECK(a_date->has->days, return FALSE);
CRM_CHECK(a_date->days > 0, return FALSE);
CRM_CHECK(a_date->days <= mdays, return FALSE);
CRM_CHECK(a_date->has->weekdays, return FALSE);
CRM_CHECK(a_date->weekdays > 0, return FALSE);
CRM_CHECK(a_date->weekdays <= 7, return FALSE);
CRM_CHECK(a_date->has->yeardays, return FALSE);
CRM_CHECK(a_date->yeardays > 0, return FALSE);
CRM_CHECK(a_date->yeardays <= ydays, return FALSE);
CRM_CHECK(a_date->hours >= 0, return FALSE);
CRM_CHECK(a_date->hours < 24, return FALSE);
CRM_CHECK(a_date->minutes >= 0, return FALSE);
CRM_CHECK(a_date->minutes < 60, return FALSE);
CRM_CHECK(a_date->seconds >= 0, return FALSE);
CRM_CHECK(a_date->seconds <= 60, return FALSE);
return TRUE;
}
#define do_cmp_field(lhs, rhs, field) \
{ \
if(lhs->field > rhs->field) { \
crm_debug_2("%s: %d > %d", \
#field, lhs->field, rhs->field); \
return 1; \
} else if(lhs->field < rhs->field) { \
crm_debug_2("%s: %d < %d", \
#field, lhs->field, rhs->field); \
return -1; \
} \
}
int
compare_date(ha_time_t *lhs, ha_time_t *rhs)
{
if(lhs == NULL && rhs == NULL) {
return 0;
} else if(lhs == NULL) {
return -1;
} else if(rhs == NULL) {
return 1;
}
normalize_time(lhs);
normalize_time(rhs);
do_cmp_field(lhs->normalized, rhs->normalized, years);
do_cmp_field(lhs->normalized, rhs->normalized, yeardays);
do_cmp_field(lhs->normalized, rhs->normalized, hours);
do_cmp_field(lhs->normalized, rhs->normalized, minutes);
do_cmp_field(lhs->normalized, rhs->normalized, seconds);
return 0;
}
ha_time_t *
new_ha_date(gboolean set_to_now)
{
time_t tm_now;
ha_time_t *now = NULL;
tzset();
tm_now = time(NULL);
crm_malloc0(now, sizeof(ha_time_t));
crm_malloc0(now->has, sizeof(ha_has_time_t));
crm_malloc0(now->offset, sizeof(ha_time_t));
crm_malloc0(now->offset->has, sizeof(ha_has_time_t));
if(set_to_now) {
ha_set_timet_time(now, &tm_now);
}
return now;
}
void
free_ha_date(ha_time_t *a_date)
{
if(a_date == NULL) {
return;
}
free_ha_date(a_date->normalized);
free_ha_date(a_date->offset);
crm_free(a_date->has);
crm_free(a_date);
}
void
log_tm_date(int log_level, struct tm *some_tm)
{
const char *tzn;
#if defined(HAVE_TM_ZONE)
tzn = some_tm->tm_zone;
#elif defined(HAVE_TZNAME)
tzn = tzname[0];
#else
tzn = NULL;
#endif
do_crm_log(log_level,
"%.2d/%.2d/%.4d %.2d:%.2d:%.2d %s"
" (wday=%d, yday=%d, dst=%d, offset=%ld)",
some_tm->tm_mday,
some_tm->tm_mon,
1900+some_tm->tm_year,
some_tm->tm_hour,
some_tm->tm_min,
some_tm->tm_sec,
tzn,
some_tm->tm_wday==0?7:some_tm->tm_wday,
1+some_tm->tm_yday,
some_tm->tm_isdst,
GMTOFF(some_tm));
}
diff --git a/lib/crm/pengine/clone.c b/lib/crm/pengine/clone.c
index efd352d628..ba397d37f5 100644
--- a/lib/crm/pengine/clone.c
+++ b/lib/crm/pengine/clone.c
@@ -1,300 +1,295 @@
/* $Id: clone.c,v 1.7 2006/08/14 09:14:45 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 <crm/pengine/status.h>
#include <utils.h>
#include <crm/msg_xml.h>
#define VARIANT_CLONE 1
#include <lib/crm/pengine/variant.h>
void clone_create_notifications(
resource_t *rsc, action_t *action, action_t *action_complete,
pe_working_set_t *data_set);
-#define get_clone_variant_data(data, rsc) \
- CRM_ASSERT(rsc->variant == pe_clone || rsc->variant == pe_master); \
- data = (clone_variant_data_t *)rsc->variant_opaque;
-
-
static gboolean
create_child_clone(resource_t *rsc, int sub_id, pe_working_set_t *data_set)
{
gboolean rc = TRUE;
char *inc_num = NULL;
char *inc_max = NULL;
resource_t *child_rsc = NULL;
crm_data_t * child_copy = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE);
inc_num = crm_itoa(sub_id);
inc_max = crm_itoa(clone_data->clone_max);
child_copy = copy_xml(clone_data->xml_obj_child);
crm_xml_add(child_copy, XML_RSC_ATTR_INCARNATION, inc_num);
if(common_unpack(child_copy, &child_rsc,
rsc, data_set) == FALSE) {
pe_err("Failed unpacking resource %s",
crm_element_value(child_copy, XML_ATTR_ID));
goto bail;
}
/* child_rsc->globally_unique = rsc->globally_unique; */
crm_debug_3("Setting clone attributes for: %s", child_rsc->id);
clone_data->child_list = g_list_append(
clone_data->child_list, child_rsc);
add_hash_param(child_rsc->meta, XML_RSC_ATTR_INCARNATION_MAX, inc_max);
print_resource(LOG_DEBUG_3, "Added", child_rsc, FALSE);
bail:
crm_free(inc_num);
crm_free(inc_max);
return rc;
}
gboolean master_unpack(resource_t *rsc, pe_working_set_t *data_set)
{
const char *master_max = g_hash_table_lookup(
rsc->meta, XML_RSC_ATTR_MASTER_MAX);
const char *master_node_max = g_hash_table_lookup(
rsc->meta, XML_RSC_ATTR_MASTER_NODEMAX);
add_hash_param(rsc->parameters, crm_meta_name("stateful"),
XML_BOOLEAN_TRUE);
if(clone_unpack(rsc, data_set)) {
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
clone_data->master_max = crm_parse_int(master_max, "1");
clone_data->master_node_max = crm_parse_int(master_node_max, "1");
return TRUE;
}
return FALSE;
}
gboolean clone_unpack(resource_t *rsc, pe_working_set_t *data_set)
{
int lpc = 0;
crm_data_t *xml_tmp = NULL;
crm_data_t *xml_self = NULL;
crm_data_t *xml_obj = rsc->xml;
clone_variant_data_t *clone_data = NULL;
resource_t *self = NULL;
const char *ordered = g_hash_table_lookup(
rsc->meta, XML_RSC_ATTR_ORDERED);
const char *interleave = g_hash_table_lookup(
rsc->meta, XML_RSC_ATTR_INTERLEAVE);
const char *max_clones = g_hash_table_lookup(
rsc->meta, XML_RSC_ATTR_INCARNATION_MAX);
const char *max_clones_node = g_hash_table_lookup(
rsc->meta, XML_RSC_ATTR_INCARNATION_NODEMAX);
crm_debug_3("Processing resource %s...", rsc->id);
crm_malloc0(clone_data, sizeof(clone_variant_data_t));
rsc->variant_opaque = clone_data;
clone_data->child_list = NULL;
clone_data->interleave = FALSE;
clone_data->ordered = FALSE;
clone_data->active_clones = 0;
clone_data->xml_obj_child = NULL;
clone_data->clone_node_max = crm_parse_int(max_clones_node, "1");
clone_data->clone_max = crm_parse_int(max_clones, "-1");
if(clone_data->clone_max < 0) {
clone_data->clone_max = g_list_length(data_set->nodes);
}
if(crm_is_true(interleave)) {
clone_data->interleave = TRUE;
}
if(crm_is_true(ordered)) {
clone_data->ordered = TRUE;
}
crm_debug_2("Options for %s", rsc->id);
crm_debug_2("\tClone max: %d", clone_data->clone_max);
crm_debug_2("\tClone node max: %d", clone_data->clone_node_max);
crm_debug_2("\tClone is unique: %s", rsc->globally_unique?"true":"false");
clone_data->xml_obj_child = find_xml_node(
xml_obj, XML_CIB_TAG_GROUP, FALSE);
if(clone_data->xml_obj_child == NULL) {
clone_data->xml_obj_child = find_xml_node(
xml_obj, XML_CIB_TAG_RESOURCE, TRUE);
}
if(clone_data->xml_obj_child == NULL) {
crm_config_err("%s has nothing to clone", rsc->id);
return FALSE;
}
xml_self = copy_xml(rsc->xml);
/* this is a bit of a hack - but simplifies everything else */
ha_msg_mod(xml_self, F_XML_TAGNAME, XML_CIB_TAG_RESOURCE);
/* set_id(xml_self, "self", -1); */
xml_tmp = find_xml_node(xml_obj, "operations", FALSE);
if(xml_tmp != NULL) {
add_node_copy(xml_self, xml_tmp);
}
if(common_unpack(xml_self, &self, NULL, data_set)) {
clone_data->self = self;
} else {
crm_log_xml_err(xml_self, "Couldnt unpack dummy child");
clone_data->self = self;
return FALSE;
}
clone_data->notify_confirm = clone_data->self->notify;
for(lpc = 0; lpc < clone_data->clone_max; lpc++) {
create_child_clone(rsc, lpc, data_set);
}
crm_debug_3("Added %d children to resource %s...",
clone_data->clone_max, rsc->id);
return TRUE;
}
resource_t *
clone_find_child(resource_t *rsc, const char *id)
{
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
return pe_find_resource(clone_data->child_list, id);
}
GListPtr clone_children(resource_t *rsc)
{
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
return clone_data->child_list;
}
gboolean clone_active(resource_t *rsc, gboolean all)
{
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
slist_iter(
child_rsc, resource_t, clone_data->child_list, lpc,
gboolean child_active = child_rsc->fns->active(child_rsc, all);
if(all == FALSE && child_active) {
return TRUE;
} else if(all && child_active == FALSE) {
return FALSE;
}
);
if(all) {
return TRUE;
} else {
return FALSE;
}
}
void clone_print(
resource_t *rsc, const char *pre_text, long options, void *print_data)
{
const char *child_text = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
if(pre_text != NULL) {
child_text = " ";
} else {
child_text = " ";
}
if(rsc->variant == pe_master) {
status_print("%sMaster/Slave Set: %s",
pre_text?pre_text:"", clone_data->self->id);
} else {
status_print("%sClone Set: %s",
pre_text?pre_text:"", clone_data->self->id);
}
if(options & pe_print_html) {
status_print("\n<ul>\n");
} else if((options & pe_print_log) == 0) {
status_print("\n");
}
slist_iter(
child_rsc, resource_t, clone_data->child_list, lpc,
if(options & pe_print_html) {
status_print("<li>\n");
}
child_rsc->fns->print(
child_rsc, child_text, options, print_data);
if(options & pe_print_html) {
status_print("</li>\n");
}
);
if(options & pe_print_html) {
status_print("</ul>\n");
}
}
void clone_free(resource_t *rsc)
{
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
crm_debug_3("Freeing %s", rsc->id);
slist_iter(
child_rsc, resource_t, clone_data->child_list, lpc,
crm_debug_3("Freeing child %s", child_rsc->id);
free_xml(child_rsc->xml);
child_rsc->fns->free(child_rsc);
);
crm_debug_3("Freeing child list");
pe_free_shallow_adv(clone_data->child_list, FALSE);
if(clone_data->self) {
free_xml(clone_data->self->xml);
clone_data->self->fns->free(clone_data->self);
}
common_free(rsc);
}
enum rsc_role_e
clone_resource_state(resource_t *rsc)
{
return RSC_ROLE_UNKNOWN;
}
diff --git a/lib/crm/pengine/variant.h b/lib/crm/pengine/variant.h
index d047fa6f23..dad312254f 100644
--- a/lib/crm/pengine/variant.h
+++ b/lib/crm/pengine/variant.h
@@ -1,86 +1,88 @@
/* $Id: utils.h,v 1.4 2006/06/21 11:06:13 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
*/
#ifndef PE_VARIANT__H
#define PE_VARIANT__H
#if VARIANT_CLONE
typedef struct clone_variant_data_s {
resource_t *self;
int clone_max;
int clone_node_max;
int master_max;
int master_node_max;
int active_clones;
int max_nodes;
gboolean interleave;
gboolean ordered;
crm_data_t *xml_obj_child;
gboolean notify_confirm;
GListPtr child_list; /* resource_t* */
} clone_variant_data_t;
# define get_clone_variant_data(data, rsc) \
+ CRM_ASSERT(rsc != NULL); \
CRM_ASSERT(rsc->variant == pe_clone || rsc->variant == pe_master); \
data = (clone_variant_data_t *)rsc->variant_opaque;
#elif VARIANT_GROUP
typedef struct group_variant_data_s {
int num_children;
GListPtr child_list; /* resource_t* */
resource_t *self;
resource_t *first_child;
resource_t *last_child;
gboolean colocated;
gboolean ordered;
gboolean child_starting;
gboolean child_stopping;
} group_variant_data_t;
# define get_group_variant_data(data, rsc) \
CRM_ASSERT(rsc != NULL); \
CRM_ASSERT(rsc->variant == pe_group); \
CRM_ASSERT(rsc->variant_opaque != NULL); \
data = (group_variant_data_t *)rsc->variant_opaque; \
#elif VARIANT_NATIVE
typedef struct native_variant_data_s {
} native_variant_data_t;
# define get_native_variant_data(data, rsc) \
+ CRM_ASSERT(rsc != NULL); \
CRM_ASSERT(rsc->variant == pe_native); \
CRM_ASSERT(rsc->variant_opaque != NULL); \
data = (native_variant_data_t *)rsc->variant_opaque;
#endif
#endif

File Metadata

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

Event Timeline