mirror of https://github.com/sipwise/heartbeat.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
353 lines
10 KiB
353 lines
10 KiB
/*
|
|
* 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 <lha_internal.h>
|
|
#include <crm/crm.h>
|
|
#include <crm/cib.h>
|
|
#include <crm/msg_xml.h>
|
|
#include <crm/common/xml.h>
|
|
#include <crm/common/util.h>
|
|
|
|
#include <glib.h>
|
|
|
|
#include <crm/pengine/status.h>
|
|
#include <crm/pengine/common.h>
|
|
|
|
gboolean was_processing_error = FALSE;
|
|
gboolean was_processing_warning = FALSE;
|
|
|
|
static gboolean
|
|
check_quorum(const char *value)
|
|
{
|
|
if(safe_str_eq(value, "stop")) {
|
|
return TRUE;
|
|
|
|
} else if(safe_str_eq(value, "freeze")) {
|
|
return TRUE;
|
|
|
|
} else if(safe_str_eq(value, "ignore")) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
check_stonith_action(const char *value)
|
|
{
|
|
if(safe_str_eq(value, "reboot")) {
|
|
return TRUE;
|
|
|
|
} else if(safe_str_eq(value, "poweroff")) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
pe_cluster_option pe_opts[] = {
|
|
/* name, old-name, validate, default, description */
|
|
{ "no-quorum-policy", "no_quorum_policy", "enum", "stop, freeze, ignore", "stop", &check_quorum,
|
|
"What to do when the cluster does not have quorum", NULL },
|
|
{ "symmetric-cluster", "symmetric_cluster", "boolean", NULL, "true", &check_boolean,
|
|
"All resources can run anywhere by default", NULL },
|
|
{ "stonith-enabled", "stonith_enabled", "boolean", NULL, "false", &check_boolean,
|
|
"Failed nodes are STONITH'd", NULL },
|
|
{ "stonith-action", "stonith_action", "enum", "reboot, poweroff", "reboot", &check_stonith_action,
|
|
"Action to send to STONITH device", NULL },
|
|
{ "default-resource-stickiness", "default_resource_stickiness", "integer", NULL, "0", &check_number, "", NULL },
|
|
{ "default-resource-failure-stickiness", "default_resource_failure_stickiness", "integer", NULL, "0", &check_number, "", NULL },
|
|
{ "is-managed-default", "is_managed_default", "boolean", NULL, "true", &check_boolean,
|
|
"Should the cluster start/stop resources as required", NULL },
|
|
{ "cluster-delay", "transition_idle_timeout", "time", NULL, "60s", &check_time,
|
|
"Round trip delay over the network (excluding action execution)",
|
|
"The \"correct\" value will depend on the speed and load of your network and cluster nodes." },
|
|
{ "batch-limit", NULL, "integer", NULL, "30", &check_number,
|
|
"The number of jobs that the TE is allowed to execute in parallel",
|
|
"The \"correct\" value will depend on the speed and load of your network and cluster nodes." },
|
|
{ "default-action-timeout", "default_action_timeout", "time", NULL, "20s", &check_time,
|
|
"How long to wait for actions to complete", NULL },
|
|
{ "stop-orphan-resources", "stop_orphan_resources", "boolean", NULL, "true", &check_boolean,
|
|
"Should deleted resources be stopped", NULL },
|
|
{ "stop-orphan-actions", "stop_orphan_actions", "boolean", NULL, "true", &check_boolean,
|
|
"Should deleted actions be cancelled", NULL },
|
|
{ "remove-after-stop", "remove_after_stop", "boolean", NULL, "false", &check_boolean,
|
|
"Remove resources from the LRM after they are stopped",
|
|
"Always set this to false. Other values are, at best, poorly tested and potentially dangerous." },
|
|
/* { "", "", , "0", "", NULL }, */
|
|
{ "pe-error-series-max", NULL, "integer", NULL, "-1", &check_number,
|
|
"The number of PE inputs resulting in ERRORs to save", "Zero to disable, -1 to store unlimited." },
|
|
{ "pe-warn-series-max", NULL, "integer", NULL, "-1", &check_number,
|
|
"The number of PE inputs resulting in WARNINGs to save", "Zero to disable, -1 to store unlimited." },
|
|
{ "pe-input-series-max", NULL, "integer", NULL, "-1", &check_number,
|
|
"The number of other PE inputs to save", "Zero to disable, -1 to store unlimited." },
|
|
{ "startup-fencing", "startup_fencing", "boolean", NULL, "true", &check_boolean,
|
|
"STONITH unseen nodes", "Advanced Use Only! Not using the default is very unsafe!" },
|
|
{ "start-failure-is-fatal", NULL, "boolean", NULL, "true", &check_boolean, "Always treat start failures as fatal",
|
|
"This was the old default. However when set to FALSE, the cluster will instead use the resource's failcount and value for resource-failure-stickiness" }
|
|
};
|
|
|
|
void
|
|
pe_metadata(void)
|
|
{
|
|
config_metadata("Policy Engine", "1.0",
|
|
"Policy Engine Options",
|
|
"This is a fake resource that details the options that can be configured for the Policy Engine.",
|
|
pe_opts, DIMOF(pe_opts));
|
|
}
|
|
|
|
void
|
|
verify_pe_options(GHashTable *options)
|
|
{
|
|
verify_all_options(options, pe_opts, DIMOF(pe_opts));
|
|
}
|
|
|
|
const char *
|
|
pe_pref(GHashTable *options, const char *name)
|
|
{
|
|
return get_cluster_pref(options, pe_opts, DIMOF(pe_opts), name);
|
|
}
|
|
|
|
const char *
|
|
fail2text(enum action_fail_response fail)
|
|
{
|
|
const char *result = "<unknown>";
|
|
switch(fail)
|
|
{
|
|
case action_fail_ignore:
|
|
result = "ignore";
|
|
break;
|
|
case action_fail_block:
|
|
result = "block";
|
|
break;
|
|
case action_fail_recover:
|
|
result = "recover";
|
|
break;
|
|
case action_fail_migrate:
|
|
result = "migrate";
|
|
break;
|
|
case action_fail_stop:
|
|
result = "stop";
|
|
break;
|
|
case action_migrate_failure:
|
|
result = "atomic migration recovery";
|
|
break;
|
|
case action_fail_fence:
|
|
result = "fence";
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
enum action_tasks
|
|
text2task(const char *task)
|
|
{
|
|
if(safe_str_eq(task, CRMD_ACTION_STOP)) {
|
|
return stop_rsc;
|
|
} else if(safe_str_eq(task, CRMD_ACTION_STOPPED)) {
|
|
return stopped_rsc;
|
|
} else if(safe_str_eq(task, CRMD_ACTION_START)) {
|
|
return start_rsc;
|
|
} else if(safe_str_eq(task, CRMD_ACTION_STARTED)) {
|
|
return started_rsc;
|
|
} else if(safe_str_eq(task, CRM_OP_SHUTDOWN)) {
|
|
return shutdown_crm;
|
|
} else if(safe_str_eq(task, CRM_OP_FENCE)) {
|
|
return stonith_node;
|
|
} else if(safe_str_eq(task, CRMD_ACTION_STATUS)) {
|
|
return monitor_rsc;
|
|
} else if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) {
|
|
return action_notify;
|
|
} else if(safe_str_eq(task, CRMD_ACTION_NOTIFIED)) {
|
|
return action_notified;
|
|
} else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) {
|
|
return action_promote;
|
|
} else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) {
|
|
return action_demote;
|
|
} else if(safe_str_eq(task, CRMD_ACTION_PROMOTED)) {
|
|
return action_promoted;
|
|
} else if(safe_str_eq(task, CRMD_ACTION_DEMOTED)) {
|
|
return action_demoted;
|
|
} else if(safe_str_eq(task, CRMD_ACTION_CANCEL)) {
|
|
return no_action;
|
|
} else if(safe_str_eq(task, CRMD_ACTION_DELETE)) {
|
|
return no_action;
|
|
} else if(safe_str_eq(task, CRMD_ACTION_STATUS)) {
|
|
return no_action;
|
|
} else if(safe_str_eq(task, CRM_OP_PROBED)) {
|
|
return no_action;
|
|
} else if(safe_str_eq(task, CRM_OP_LRM_REFRESH)) {
|
|
return no_action;
|
|
} else if(safe_str_eq(task, CRMD_ACTION_MIGRATED)) {
|
|
return no_action;
|
|
} else if(safe_str_eq(task, "fail")) {
|
|
return no_action;
|
|
} else if(safe_str_eq(task, "stonith_up")) {
|
|
return no_action;
|
|
} else if(safe_str_eq(task, "all_stopped")) {
|
|
return no_action;
|
|
}
|
|
crm_config_warn("Unsupported action: %s", task);
|
|
return no_action;
|
|
}
|
|
|
|
|
|
const char *
|
|
task2text(enum action_tasks task)
|
|
{
|
|
const char *result = "<unknown>";
|
|
switch(task)
|
|
{
|
|
case no_action:
|
|
result = "no_action";
|
|
break;
|
|
case stop_rsc:
|
|
result = CRMD_ACTION_STOP;
|
|
break;
|
|
case stopped_rsc:
|
|
result = CRMD_ACTION_STOPPED;
|
|
break;
|
|
case start_rsc:
|
|
result = CRMD_ACTION_START;
|
|
break;
|
|
case started_rsc:
|
|
result = CRMD_ACTION_STARTED;
|
|
break;
|
|
case shutdown_crm:
|
|
result = CRM_OP_SHUTDOWN;
|
|
break;
|
|
case stonith_node:
|
|
result = CRM_OP_FENCE;
|
|
break;
|
|
case monitor_rsc:
|
|
result = CRMD_ACTION_STATUS;
|
|
break;
|
|
case action_notify:
|
|
result = CRMD_ACTION_NOTIFY;
|
|
break;
|
|
case action_notified:
|
|
result = CRMD_ACTION_NOTIFIED;
|
|
break;
|
|
case action_promote:
|
|
result = CRMD_ACTION_PROMOTE;
|
|
break;
|
|
case action_promoted:
|
|
result = CRMD_ACTION_PROMOTED;
|
|
break;
|
|
case action_demote:
|
|
result = CRMD_ACTION_DEMOTE;
|
|
break;
|
|
case action_demoted:
|
|
result = CRMD_ACTION_DEMOTED;
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
const char *
|
|
role2text(enum rsc_role_e role)
|
|
{
|
|
CRM_CHECK(role >= RSC_ROLE_UNKNOWN, return RSC_ROLE_UNKNOWN_S);
|
|
CRM_CHECK(role < RSC_ROLE_MAX, return RSC_ROLE_UNKNOWN_S);
|
|
switch(role) {
|
|
case RSC_ROLE_UNKNOWN:
|
|
return RSC_ROLE_UNKNOWN_S;
|
|
case RSC_ROLE_STOPPED:
|
|
return RSC_ROLE_STOPPED_S;
|
|
case RSC_ROLE_STARTED:
|
|
return RSC_ROLE_STARTED_S;
|
|
case RSC_ROLE_SLAVE:
|
|
return RSC_ROLE_SLAVE_S;
|
|
case RSC_ROLE_MASTER:
|
|
return RSC_ROLE_MASTER_S;
|
|
}
|
|
return RSC_ROLE_UNKNOWN_S;
|
|
}
|
|
|
|
enum rsc_role_e
|
|
text2role(const char *role)
|
|
{
|
|
if(safe_str_eq(role, RSC_ROLE_STOPPED_S)) {
|
|
return RSC_ROLE_STOPPED;
|
|
} else if(safe_str_eq(role, RSC_ROLE_STARTED_S)) {
|
|
return RSC_ROLE_STARTED;
|
|
} else if(safe_str_eq(role, RSC_ROLE_SLAVE_S)) {
|
|
return RSC_ROLE_SLAVE;
|
|
} else if(safe_str_eq(role, RSC_ROLE_MASTER_S)) {
|
|
return RSC_ROLE_MASTER;
|
|
} else if(safe_str_eq(role, RSC_ROLE_UNKNOWN_S)) {
|
|
return RSC_ROLE_UNKNOWN;
|
|
}
|
|
crm_err("Unknown role: %s", role);
|
|
return RSC_ROLE_UNKNOWN;
|
|
}
|
|
|
|
int
|
|
merge_weights(int w1, int w2)
|
|
{
|
|
int result = w1 + w2;
|
|
|
|
if(w1 <= -INFINITY || w2 <= -INFINITY) {
|
|
if(w1 >= INFINITY || w2 >= INFINITY) {
|
|
crm_debug_2("-INFINITY + INFINITY == -INFINITY");
|
|
}
|
|
return -INFINITY;
|
|
|
|
} else if(w1 >= INFINITY || w2 >= INFINITY) {
|
|
return INFINITY;
|
|
}
|
|
|
|
/* detect wrap-around */
|
|
if(result > 0) {
|
|
if(w1 <= 0 && w2 < 0) {
|
|
result = -INFINITY;
|
|
}
|
|
|
|
} else if(w1 > 0 && w2 > 0) {
|
|
result = INFINITY;
|
|
}
|
|
|
|
/* detect +/- INFINITY */
|
|
if(result >= INFINITY) {
|
|
result = INFINITY;
|
|
|
|
} else if(result <= -INFINITY) {
|
|
result = -INFINITY;
|
|
}
|
|
|
|
crm_debug_5("%d + %d = %d", w1, w2, result);
|
|
return result;
|
|
}
|
|
|
|
void
|
|
add_hash_param(GHashTable *hash, const char *name, const char *value)
|
|
{
|
|
CRM_CHECK(hash != NULL, return);
|
|
|
|
crm_debug_3("adding: name=%s value=%s", crm_str(name), crm_str(value));
|
|
if(name == NULL || value == NULL) {
|
|
return;
|
|
|
|
} else if(safe_str_eq(value, "#default")) {
|
|
return;
|
|
|
|
} else if(g_hash_table_lookup(hash, name) == NULL) {
|
|
g_hash_table_insert(hash, crm_strdup(name), crm_strdup(value));
|
|
}
|
|
}
|