Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4512681
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
118 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/daemons/fenced/pacemaker-fenced.c b/daemons/fenced/pacemaker-fenced.c
index 57d74db322..9ca3eae787 100644
--- a/daemons/fenced/pacemaker-fenced.c
+++ b/daemons/fenced/pacemaker-fenced.c
@@ -1,1709 +1,1740 @@
/*
* Copyright 2009-2022 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h> // PRIu32, PRIx32
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/common/ipc.h>
#include <crm/common/ipc_internal.h>
#include <crm/cluster/internal.h>
#include <crm/stonith-ng.h>
#include <crm/fencing/internal.h>
#include <crm/common/xml.h>
#include <crm/common/xml_internal.h>
#include <crm/common/mainloop.h>
#include <crm/cib/internal.h>
#include <crm/pengine/status.h>
#include <pacemaker-internal.h>
#include <pacemaker-fenced.h>
char *stonith_our_uname = NULL;
long stonith_watchdog_timeout_ms = 0;
GList *stonith_watchdog_targets = NULL;
static GMainLoop *mainloop = NULL;
gboolean stand_alone = FALSE;
static gboolean no_cib_connect = FALSE;
static gboolean stonith_shutdown_flag = FALSE;
static qb_ipcs_service_t *ipcs = NULL;
static xmlNode *local_cib = NULL;
static pe_working_set_t *fenced_data_set = NULL;
static const unsigned long long data_set_flags = pe_flag_quick_location
| pe_flag_no_compat
| pe_flag_no_counts;
static cib_t *cib_api = NULL;
static pcmk__output_t *out = NULL;
pcmk__supported_format_t formats[] = {
PCMK__SUPPORTED_FORMAT_LOG,
PCMK__SUPPORTED_FORMAT_NONE,
PCMK__SUPPORTED_FORMAT_TEXT,
{ NULL, NULL, NULL }
};
static void stonith_shutdown(int nsig);
static void stonith_cleanup(void);
static int32_t
st_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
{
if (stonith_shutdown_flag) {
crm_info("Ignoring new client [%d] during shutdown",
pcmk__client_pid(c));
return -EPERM;
}
if (pcmk__new_client(c, uid, gid) == NULL) {
return -EIO;
}
return 0;
}
/* Exit code means? */
static int32_t
st_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size)
{
uint32_t id = 0;
uint32_t flags = 0;
int call_options = 0;
xmlNode *request = NULL;
pcmk__client_t *c = pcmk__find_client(qbc);
const char *op = NULL;
if (c == NULL) {
crm_info("Invalid client: %p", qbc);
return 0;
}
request = pcmk__client_data2xml(c, data, &id, &flags);
if (request == NULL) {
pcmk__ipc_send_ack(c, id, flags, "nack", NULL, CRM_EX_PROTOCOL);
return 0;
}
op = crm_element_value(request, F_CRM_TASK);
if(pcmk__str_eq(op, CRM_OP_RM_NODE_CACHE, pcmk__str_casei)) {
crm_xml_add(request, F_TYPE, T_STONITH_NG);
crm_xml_add(request, F_STONITH_OPERATION, op);
crm_xml_add(request, F_STONITH_CLIENTID, c->id);
crm_xml_add(request, F_STONITH_CLIENTNAME, pcmk__client_name(c));
crm_xml_add(request, F_STONITH_CLIENTNODE, stonith_our_uname);
send_cluster_message(NULL, crm_msg_stonith_ng, request, FALSE);
free_xml(request);
return 0;
}
if (c->name == NULL) {
const char *value = crm_element_value(request, F_STONITH_CLIENTNAME);
if (value == NULL) {
value = "unknown";
}
c->name = crm_strdup_printf("%s.%u", value, c->pid);
}
crm_element_value_int(request, F_STONITH_CALLOPTS, &call_options);
crm_trace("Flags %#08" PRIx32 "/%#08x for command %" PRIu32
" from client %s", flags, call_options, id, pcmk__client_name(c));
if (pcmk_is_set(call_options, st_opt_sync_call)) {
CRM_ASSERT(flags & crm_ipc_client_response);
CRM_LOG_ASSERT(c->request_id == 0); /* This means the client has two synchronous events in-flight */
c->request_id = id; /* Reply only to the last one */
}
crm_xml_add(request, F_STONITH_CLIENTID, c->id);
crm_xml_add(request, F_STONITH_CLIENTNAME, pcmk__client_name(c));
crm_xml_add(request, F_STONITH_CLIENTNODE, stonith_our_uname);
crm_log_xml_trace(request, "ipc-received");
stonith_command(c, id, flags, request, NULL);
free_xml(request);
return 0;
}
/* Error code means? */
static int32_t
st_ipc_closed(qb_ipcs_connection_t * c)
{
pcmk__client_t *client = pcmk__find_client(c);
if (client == NULL) {
return 0;
}
crm_trace("Connection %p closed", c);
pcmk__free_client(client);
/* 0 means: yes, go ahead and destroy the connection */
return 0;
}
static void
st_ipc_destroy(qb_ipcs_connection_t * c)
{
crm_trace("Connection %p destroyed", c);
st_ipc_closed(c);
}
static void
stonith_peer_callback(xmlNode * msg, void *private_data)
{
const char *remote_peer = crm_element_value(msg, F_ORIG);
const char *op = crm_element_value(msg, F_STONITH_OPERATION);
if (pcmk__str_eq(op, "poke", pcmk__str_none)) {
return;
}
crm_log_xml_trace(msg, "Peer[inbound]");
stonith_command(NULL, 0, 0, msg, remote_peer);
}
#if SUPPORT_COROSYNC
static void
stonith_peer_ais_callback(cpg_handle_t handle,
const struct cpg_name *groupName,
uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
{
uint32_t kind = 0;
xmlNode *xml = NULL;
const char *from = NULL;
char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
if(data == NULL) {
return;
}
if (kind == crm_class_cluster) {
xml = string2xml(data);
if (xml == NULL) {
crm_err("Invalid XML: '%.120s'", data);
free(data);
return;
}
crm_xml_add(xml, F_ORIG, from);
/* crm_xml_add_int(xml, F_SEQ, wrapper->id); */
stonith_peer_callback(xml, NULL);
}
free_xml(xml);
free(data);
return;
}
static void
stonith_peer_cs_destroy(gpointer user_data)
{
crm_crit("Lost connection to cluster layer, shutting down");
stonith_shutdown(0);
}
#endif
void
do_local_reply(xmlNode *notify_src, pcmk__client_t *client, int call_options)
{
/* send callback to originating child */
int local_rc = pcmk_rc_ok;
int rid = 0;
uint32_t ipc_flags = crm_ipc_server_event;
if (pcmk_is_set(call_options, st_opt_sync_call)) {
CRM_LOG_ASSERT(client->request_id);
rid = client->request_id;
client->request_id = 0;
ipc_flags = crm_ipc_flags_none;
}
local_rc = pcmk__ipc_send_xml(client, rid, notify_src, ipc_flags);
if (local_rc == pcmk_rc_ok) {
crm_trace("Sent response %d to client %s",
rid, pcmk__client_name(client));
} else {
crm_warn("%synchronous reply to client %s failed: %s",
(pcmk_is_set(call_options, st_opt_sync_call)? "S" : "As"),
pcmk__client_name(client), pcmk_rc_str(local_rc));
}
}
uint64_t
get_stonith_flag(const char *name)
{
if (pcmk__str_eq(name, T_STONITH_NOTIFY_FENCE, pcmk__str_casei)) {
return st_callback_notify_fence;
} else if (pcmk__str_eq(name, STONITH_OP_DEVICE_ADD, pcmk__str_casei)) {
return st_callback_device_add;
} else if (pcmk__str_eq(name, STONITH_OP_DEVICE_DEL, pcmk__str_casei)) {
return st_callback_device_del;
} else if (pcmk__str_eq(name, T_STONITH_NOTIFY_HISTORY, pcmk__str_casei)) {
return st_callback_notify_history;
} else if (pcmk__str_eq(name, T_STONITH_NOTIFY_HISTORY_SYNCED, pcmk__str_casei)) {
return st_callback_notify_history_synced;
}
return st_callback_unknown;
}
static void
stonith_notify_client(gpointer key, gpointer value, gpointer user_data)
{
xmlNode *update_msg = user_data;
pcmk__client_t *client = value;
const char *type = NULL;
CRM_CHECK(client != NULL, return);
CRM_CHECK(update_msg != NULL, return);
type = crm_element_value(update_msg, F_SUBTYPE);
CRM_CHECK(type != NULL, crm_log_xml_err(update_msg, "notify"); return);
if (client->ipcs == NULL) {
crm_trace("Skipping client with NULL channel");
return;
}
if (pcmk_is_set(client->flags, get_stonith_flag(type))) {
int rc = pcmk__ipc_send_xml(client, 0, update_msg,
crm_ipc_server_event);
if (rc != pcmk_rc_ok) {
crm_warn("%s notification of client %s failed: %s "
CRM_XS " id=%.8s rc=%d", type, pcmk__client_name(client),
pcmk_rc_str(rc), client->id, rc);
} else {
crm_trace("Sent %s notification to client %s",
type, pcmk__client_name(client));
}
}
}
void
do_stonith_async_timeout_update(const char *client_id, const char *call_id, int timeout)
{
pcmk__client_t *client = NULL;
xmlNode *notify_data = NULL;
if (!timeout || !call_id || !client_id) {
return;
}
client = pcmk__find_client_by_id(client_id);
if (!client) {
return;
}
notify_data = create_xml_node(NULL, T_STONITH_TIMEOUT_VALUE);
crm_xml_add(notify_data, F_TYPE, T_STONITH_TIMEOUT_VALUE);
crm_xml_add(notify_data, F_STONITH_CALLID, call_id);
crm_xml_add_int(notify_data, F_STONITH_TIMEOUT, timeout);
crm_trace("timeout update is %d for client %s and call id %s", timeout, client_id, call_id);
if (client) {
pcmk__ipc_send_xml(client, 0, notify_data, crm_ipc_server_event);
}
free_xml(notify_data);
}
/*!
* \internal
* \brief Notify relevant IPC clients of a fencing operation result
*
* \param[in] type Notification type
* \param[in] result Result of fencing operation (assume success if NULL)
* \param[in] data If not NULL, add to notification as call data
*/
void
fenced_send_notification(const char *type, const pcmk__action_result_t *result,
xmlNode *data)
{
/* TODO: Standardize the contents of data */
xmlNode *update_msg = create_xml_node(NULL, "notify");
CRM_LOG_ASSERT(type != NULL);
crm_xml_add(update_msg, F_TYPE, T_STONITH_NOTIFY);
crm_xml_add(update_msg, F_SUBTYPE, type);
crm_xml_add(update_msg, F_STONITH_OPERATION, type);
stonith__xe_set_result(update_msg, result);
if (data != NULL) {
add_message_xml(update_msg, F_STONITH_CALLDATA, data);
}
crm_trace("Notifying clients");
pcmk__foreach_ipc_client(stonith_notify_client, update_msg);
free_xml(update_msg);
crm_trace("Notify complete");
}
/*!
* \internal
* \brief Send notifications for a configuration change to subscribed clients
*
* \param[in] op Notification type (STONITH_OP_DEVICE_ADD,
* STONITH_OP_DEVICE_DEL, STONITH_OP_LEVEL_ADD, or
* STONITH_OP_LEVEL_DEL)
* \param[in] result Operation result
* \param[in] desc Description of what changed
* \param[in] active Current number of devices or topologies in use
*/
static void
send_config_notification(const char *op, const pcmk__action_result_t *result,
const char *desc, int active)
{
xmlNode *notify_data = create_xml_node(NULL, op);
CRM_CHECK(notify_data != NULL, return);
crm_xml_add(notify_data, F_STONITH_DEVICE, desc);
crm_xml_add_int(notify_data, F_STONITH_ACTIVE, active);
fenced_send_notification(op, result, notify_data);
free_xml(notify_data);
}
/*!
* \internal
* \brief Send notifications for a device change to subscribed clients
*
* \param[in] op Notification type (STONITH_OP_DEVICE_ADD or
* STONITH_OP_DEVICE_DEL)
* \param[in] result Operation result
* \param[in] desc ID of device that changed
*/
void
fenced_send_device_notification(const char *op,
const pcmk__action_result_t *result,
const char *desc)
{
send_config_notification(op, result, desc, g_hash_table_size(device_list));
}
/*!
* \internal
* \brief Send notifications for a topology level change to subscribed clients
*
* \param[in] op Notification type (STONITH_OP_LEVEL_ADD or
* STONITH_OP_LEVEL_DEL)
* \param[in] result Operation result
* \param[in] desc String representation of level (<target>[<level_index>])
*/
void
fenced_send_level_notification(const char *op,
const pcmk__action_result_t *result,
const char *desc)
{
send_config_notification(op, result, desc, g_hash_table_size(topology));
}
static void
topology_remove_helper(const char *node, int level)
{
char *desc = NULL;
pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
xmlNode *data = create_xml_node(NULL, XML_TAG_FENCING_LEVEL);
crm_xml_add(data, F_STONITH_ORIGIN, __func__);
crm_xml_add_int(data, XML_ATTR_STONITH_INDEX, level);
crm_xml_add(data, XML_ATTR_STONITH_TARGET, node);
fenced_unregister_level(data, &desc, &result);
fenced_send_level_notification(STONITH_OP_LEVEL_DEL, &result, desc);
pcmk__reset_result(&result);
free_xml(data);
free(desc);
}
static void
remove_cib_device(xmlXPathObjectPtr xpathObj)
{
int max = numXpathResults(xpathObj), lpc = 0;
for (lpc = 0; lpc < max; lpc++) {
const char *rsc_id = NULL;
const char *standard = NULL;
xmlNode *match = getXpathResult(xpathObj, lpc);
CRM_LOG_ASSERT(match != NULL);
if(match != NULL) {
standard = crm_element_value(match, XML_AGENT_ATTR_CLASS);
}
if (!pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
continue;
}
rsc_id = crm_element_value(match, XML_ATTR_ID);
stonith_device_remove(rsc_id, true);
}
}
static void
remove_topology_level(xmlNode *match)
{
int index = 0;
char *key = NULL;
CRM_CHECK(match != NULL, return);
key = stonith_level_key(match, fenced_target_by_unknown);
crm_element_value_int(match, XML_ATTR_STONITH_INDEX, &index);
topology_remove_helper(key, index);
free(key);
}
static void
add_topology_level(xmlNode *match)
{
char *desc = NULL;
pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
CRM_CHECK(match != NULL, return);
fenced_register_level(match, &desc, &result);
fenced_send_level_notification(STONITH_OP_LEVEL_ADD, &result, desc);
pcmk__reset_result(&result);
free(desc);
}
static void
remove_fencing_topology(xmlXPathObjectPtr xpathObj)
{
int max = numXpathResults(xpathObj), lpc = 0;
for (lpc = 0; lpc < max; lpc++) {
xmlNode *match = getXpathResult(xpathObj, lpc);
CRM_LOG_ASSERT(match != NULL);
if (match && crm_element_value(match, XML_DIFF_MARKER)) {
/* Deletion */
int index = 0;
char *target = stonith_level_key(match, fenced_target_by_unknown);
crm_element_value_int(match, XML_ATTR_STONITH_INDEX, &index);
if (target == NULL) {
crm_err("Invalid fencing target in element %s", ID(match));
} else if (index <= 0) {
crm_err("Invalid level for %s in element %s", target, ID(match));
} else {
topology_remove_helper(target, index);
}
/* } else { Deal with modifications during the 'addition' stage */
}
}
}
static void
register_fencing_topology(xmlXPathObjectPtr xpathObj)
{
int max = numXpathResults(xpathObj), lpc = 0;
for (lpc = 0; lpc < max; lpc++) {
xmlNode *match = getXpathResult(xpathObj, lpc);
remove_topology_level(match);
add_topology_level(match);
}
}
/* Fencing
<diff crm_feature_set="3.0.6">
<diff-removed>
<fencing-topology>
<fencing-level id="f-p1.1" target="pcmk-1" index="1" devices="poison-pill" __crm_diff_marker__="removed:top"/>
<fencing-level id="f-p1.2" target="pcmk-1" index="2" devices="power" __crm_diff_marker__="removed:top"/>
<fencing-level devices="disk,network" id="f-p2.1"/>
</fencing-topology>
</diff-removed>
<diff-added>
<fencing-topology>
<fencing-level id="f-p.1" target="pcmk-1" index="1" devices="poison-pill" __crm_diff_marker__="added:top"/>
<fencing-level id="f-p2.1" target="pcmk-2" index="1" devices="disk,something"/>
<fencing-level id="f-p3.1" target="pcmk-2" index="2" devices="power" __crm_diff_marker__="added:top"/>
</fencing-topology>
</diff-added>
</diff>
*/
static void
fencing_topology_init(void)
{
xmlXPathObjectPtr xpathObj = NULL;
const char *xpath = "//" XML_TAG_FENCING_LEVEL;
crm_trace("Full topology refresh");
free_topology_list();
init_topology_list();
/* Grab everything */
xpathObj = xpath_search(local_cib, xpath);
register_fencing_topology(xpathObj);
freeXpathObject(xpathObj);
}
#define rsc_name(x) x->clone_name?x->clone_name:x->id
/*!
* \internal
* \brief Check whether our uname is in a resource's allowed node list
*
* \param[in] rsc Resource to check
*
* \return Pointer to node object if found, NULL otherwise
*/
static pe_node_t *
our_node_allowed_for(const pe_resource_t *rsc)
{
GHashTableIter iter;
pe_node_t *node = NULL;
if (rsc && stonith_our_uname) {
g_hash_table_iter_init(&iter, rsc->allowed_nodes);
while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
if (node && strcmp(node->details->uname, stonith_our_uname) == 0) {
break;
}
node = NULL;
}
}
return node;
}
static void
watchdog_device_update(void)
{
if (stonith_watchdog_timeout_ms > 0) {
if (!g_hash_table_lookup(device_list, STONITH_WATCHDOG_ID) &&
!stonith_watchdog_targets) {
/* getting here watchdog-fencing enabled, no device there yet
and reason isn't stonith_watchdog_targets preventing that
*/
int rc;
xmlNode *xml;
xml = create_device_registration_xml(
STONITH_WATCHDOG_ID,
st_namespace_internal,
STONITH_WATCHDOG_AGENT,
NULL, /* stonith_device_register will add our
own name as PCMK_STONITH_HOST_LIST param
so we can skip that here
*/
NULL);
rc = stonith_device_register(xml, TRUE);
free_xml(xml);
if (rc != pcmk_ok) {
crm_crit("Cannot register watchdog pseudo fence agent");
crm_exit(CRM_EX_FATAL);
}
}
} else {
/* be silent if no device - todo parameter to stonith_device_remove */
if (g_hash_table_lookup(device_list, STONITH_WATCHDOG_ID)) {
stonith_device_remove(STONITH_WATCHDOG_ID, true);
}
}
}
static void
update_stonith_watchdog_timeout_ms(xmlNode *cib)
{
long timeout_ms = 0;
xmlNode *stonith_watchdog_xml = NULL;
const char *value = NULL;
stonith_watchdog_xml = get_xpath_object("//nvpair[@name='stonith-watchdog-timeout']",
cib, LOG_NEVER);
if (stonith_watchdog_xml) {
value = crm_element_value(stonith_watchdog_xml, XML_NVPAIR_ATTR_VALUE);
}
if (value) {
timeout_ms = crm_get_msec(value);
}
if (timeout_ms < 0) {
timeout_ms = pcmk__auto_watchdog_timeout();
}
stonith_watchdog_timeout_ms = timeout_ms;
}
/*!
* \internal
* \brief If a resource or any of its children are STONITH devices, update their
* definitions given a cluster working set.
*
* \param[in,out] rsc Resource to check
* \param[in,out] data_set Cluster working set with device information
*/
static void
cib_device_update(pe_resource_t *rsc, pe_working_set_t *data_set)
{
pe_node_t *node = NULL;
const char *value = NULL;
const char *rclass = NULL;
pe_node_t *parent = NULL;
/* If this is a complex resource, check children rather than this resource itself. */
if(rsc->children) {
GList *gIter = NULL;
for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
cib_device_update(gIter->data, data_set);
if(pe_rsc_is_clone(rsc)) {
crm_trace("Only processing one copy of the clone %s", rsc->id);
break;
}
}
return;
}
/* We only care about STONITH resources. */
rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
if (!pcmk__str_eq(rclass, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
return;
}
/* If this STONITH resource is disabled, remove it. */
if (pe__resource_is_disabled(rsc)) {
crm_info("Device %s has been disabled", rsc->id);
return;
}
/* if watchdog-fencing is disabled handle any watchdog-fence
resource as if it was disabled
*/
if ((stonith_watchdog_timeout_ms <= 0) &&
pcmk__str_eq(rsc->id, STONITH_WATCHDOG_ID, pcmk__str_none)) {
crm_info("Watchdog-fencing disabled thus handling "
"device %s as disabled", rsc->id);
return;
}
/* Check whether our node is allowed for this resource (and its parent if in a group) */
node = our_node_allowed_for(rsc);
if (rsc->parent && (rsc->parent->variant == pe_group)) {
parent = our_node_allowed_for(rsc->parent);
}
if(node == NULL) {
/* Our node is disallowed, so remove the device */
GHashTableIter iter;
crm_info("Device %s has been disabled on %s: unknown", rsc->id, stonith_our_uname);
g_hash_table_iter_init(&iter, rsc->allowed_nodes);
while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
crm_trace("Available: %s = %d", pe__node_name(node), node->weight);
}
return;
} else if(node->weight < 0 || (parent && parent->weight < 0)) {
/* Our node (or its group) is disallowed by score, so remove the device */
int score = (node->weight < 0)? node->weight : parent->weight;
crm_info("Device %s has been disabled on %s: score=%s",
rsc->id, stonith_our_uname, pcmk_readable_score(score));
return;
} else {
/* Our node is allowed, so update the device information */
int rc;
xmlNode *data;
GHashTable *rsc_params = NULL;
GHashTableIter gIter;
stonith_key_value_t *params = NULL;
const char *name = NULL;
const char *agent = crm_element_value(rsc->xml, XML_EXPR_ATTR_TYPE);
const char *rsc_provides = NULL;
crm_debug("Device %s is allowed on %s: score=%d", rsc->id, stonith_our_uname, node->weight);
rsc_params = pe_rsc_params(rsc, node, data_set);
get_meta_attributes(rsc->meta, rsc, node, data_set);
rsc_provides = g_hash_table_lookup(rsc->meta, PCMK_STONITH_PROVIDES);
g_hash_table_iter_init(&gIter, rsc_params);
while (g_hash_table_iter_next(&gIter, (gpointer *) & name, (gpointer *) & value)) {
if (!name || !value) {
continue;
}
params = stonith_key_value_add(params, name, value);
crm_trace(" %s=%s", name, value);
}
data = create_device_registration_xml(rsc_name(rsc), st_namespace_any,
agent, params, rsc_provides);
stonith_key_value_freeall(params, 1, 1);
rc = stonith_device_register(data, TRUE);
CRM_ASSERT(rc == pcmk_ok);
free_xml(data);
}
}
/*!
* \internal
* \brief Update all STONITH device definitions based on current CIB
*/
static void
cib_devices_update(void)
{
GHashTableIter iter;
stonith_device_t *device = NULL;
crm_info("Updating devices to version %s.%s.%s",
crm_element_value(local_cib, XML_ATTR_GENERATION_ADMIN),
crm_element_value(local_cib, XML_ATTR_GENERATION),
crm_element_value(local_cib, XML_ATTR_NUMUPDATES));
if (fenced_data_set->now != NULL) {
crm_time_free(fenced_data_set->now);
fenced_data_set->now = NULL;
}
fenced_data_set->localhost = stonith_our_uname;
pcmk__schedule_actions(local_cib, data_set_flags, fenced_data_set);
g_hash_table_iter_init(&iter, device_list);
while (g_hash_table_iter_next(&iter, NULL, (void **)&device)) {
if (device->cib_registered) {
device->dirty = TRUE;
}
}
/* have list repopulated if cib has a watchdog-fencing-resource
TODO: keep a cached list for queries happening while we are refreshing
*/
g_list_free_full(stonith_watchdog_targets, free);
stonith_watchdog_targets = NULL;
g_list_foreach(fenced_data_set->resources, (GFunc) cib_device_update, fenced_data_set);
g_hash_table_iter_init(&iter, device_list);
while (g_hash_table_iter_next(&iter, NULL, (void **)&device)) {
if (device->dirty) {
g_hash_table_iter_remove(&iter);
}
}
fenced_data_set->input = NULL; // Wasn't a copy, so don't let API free it
pe_reset_working_set(fenced_data_set);
}
static void
update_cib_stonith_devices_v2(const char *event, xmlNode * msg)
{
xmlNode *change = NULL;
char *reason = NULL;
bool needs_update = FALSE;
xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
for (change = pcmk__xml_first_child(patchset); change != NULL;
change = pcmk__xml_next(change)) {
const char *op = crm_element_value(change, XML_DIFF_OP);
const char *xpath = crm_element_value(change, XML_DIFF_PATH);
const char *shortpath = NULL;
if ((op == NULL) ||
(strcmp(op, "move") == 0) ||
strstr(xpath, "/"XML_CIB_TAG_STATUS)) {
continue;
} else if (pcmk__str_eq(op, "delete", pcmk__str_casei) && strstr(xpath, "/"XML_CIB_TAG_RESOURCE)) {
const char *rsc_id = NULL;
char *search = NULL;
char *mutable = NULL;
if (strstr(xpath, XML_TAG_ATTR_SETS) ||
strstr(xpath, XML_TAG_META_SETS)) {
needs_update = TRUE;
reason = strdup("(meta) attribute deleted from resource");
break;
}
mutable = strdup(xpath);
rsc_id = strstr(mutable, "primitive[@id=\'");
if (rsc_id != NULL) {
rsc_id += strlen("primitive[@id=\'");
search = strchr(rsc_id, '\'');
}
if (search != NULL) {
*search = 0;
stonith_device_remove(rsc_id, true);
/* watchdog_device_update called afterwards
to fall back to implicit definition if needed */
} else {
crm_warn("Ignoring malformed CIB update (resource deletion)");
}
free(mutable);
} else if (strstr(xpath, "/"XML_CIB_TAG_RESOURCES) ||
strstr(xpath, "/"XML_CIB_TAG_CONSTRAINTS) ||
strstr(xpath, "/"XML_CIB_TAG_RSCCONFIG)) {
shortpath = strrchr(xpath, '/'); CRM_ASSERT(shortpath);
reason = crm_strdup_printf("%s %s", op, shortpath+1);
needs_update = TRUE;
break;
}
}
if(needs_update) {
crm_info("Updating device list from CIB: %s", reason);
cib_devices_update();
} else {
crm_trace("No updates for device list found in CIB");
}
free(reason);
}
static void
update_cib_stonith_devices_v1(const char *event, xmlNode * msg)
{
const char *reason = "none";
gboolean needs_update = FALSE;
xmlXPathObjectPtr xpath_obj = NULL;
/* process new constraints */
xpath_obj = xpath_search(msg, "//" F_CIB_UPDATE_RESULT "//" XML_CONS_TAG_RSC_LOCATION);
if (numXpathResults(xpath_obj) > 0) {
int max = numXpathResults(xpath_obj), lpc = 0;
/* Safest and simplest to always recompute */
needs_update = TRUE;
reason = "new location constraint";
for (lpc = 0; lpc < max; lpc++) {
xmlNode *match = getXpathResult(xpath_obj, lpc);
crm_log_xml_trace(match, "new constraint");
}
}
freeXpathObject(xpath_obj);
/* process deletions */
xpath_obj = xpath_search(msg, "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//" XML_CIB_TAG_RESOURCE);
if (numXpathResults(xpath_obj) > 0) {
remove_cib_device(xpath_obj);
}
freeXpathObject(xpath_obj);
/* process additions */
xpath_obj = xpath_search(msg, "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_CIB_TAG_RESOURCE);
if (numXpathResults(xpath_obj) > 0) {
int max = numXpathResults(xpath_obj), lpc = 0;
for (lpc = 0; lpc < max; lpc++) {
const char *rsc_id = NULL;
const char *standard = NULL;
xmlNode *match = getXpathResult(xpath_obj, lpc);
rsc_id = crm_element_value(match, XML_ATTR_ID);
standard = crm_element_value(match, XML_AGENT_ATTR_CLASS);
if (!pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
continue;
}
crm_trace("Fencing resource %s was added or modified", rsc_id);
reason = "new resource";
needs_update = TRUE;
}
}
freeXpathObject(xpath_obj);
if(needs_update) {
crm_info("Updating device list from CIB: %s", reason);
cib_devices_update();
}
}
static void
update_cib_stonith_devices(const char *event, xmlNode * msg)
{
int format = 1;
xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
CRM_ASSERT(patchset);
crm_element_value_int(patchset, "format", &format);
switch(format) {
case 1:
update_cib_stonith_devices_v1(event, msg);
break;
case 2:
update_cib_stonith_devices_v2(event, msg);
break;
default:
crm_warn("Unknown patch format: %d", format);
}
}
/* Needs to hold node name + attribute name + attribute value + 75 */
#define XPATH_MAX 512
/*!
* \internal
* \brief Check whether a node has a specific attribute name/value
*
* \param[in] node Name of node to check
* \param[in] name Name of an attribute to look for
* \param[in] value The value the named attribute needs to be set to in order to be considered a match
*
* \return TRUE if the locally cached CIB has the specified node attribute
*/
gboolean
node_has_attr(const char *node, const char *name, const char *value)
{
char xpath[XPATH_MAX];
xmlNode *match;
int n;
CRM_CHECK(local_cib != NULL, return FALSE);
/* Search for the node's attributes in the CIB. While the schema allows
* multiple sets of instance attributes, and allows instance attributes to
* use id-ref to reference values elsewhere, that is intended for resources,
* so we ignore that here.
*/
n = snprintf(xpath, XPATH_MAX, "//" XML_CIB_TAG_NODES
"/" XML_CIB_TAG_NODE "[@uname='%s']/" XML_TAG_ATTR_SETS
"/" XML_CIB_TAG_NVPAIR "[@name='%s' and @value='%s']",
node, name, value);
match = get_xpath_object(xpath, local_cib, LOG_NEVER);
CRM_CHECK(n < XPATH_MAX, return FALSE);
return (match != NULL);
}
/*!
* \internal
* \brief Check whether a node does watchdog-fencing
*
* \param[in] node Name of node to check
*
* \return TRUE if node found in stonith_watchdog_targets
* or stonith_watchdog_targets is empty indicating
* all nodes are doing watchdog-fencing
*/
gboolean
node_does_watchdog_fencing(const char *node)
{
return ((stonith_watchdog_targets == NULL) ||
pcmk__str_in_list(node, stonith_watchdog_targets, pcmk__str_casei));
}
static void
update_fencing_topology(const char *event, xmlNode * msg)
{
int format = 1;
const char *xpath;
xmlXPathObjectPtr xpathObj = NULL;
xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
CRM_ASSERT(patchset);
crm_element_value_int(patchset, "format", &format);
if(format == 1) {
/* Process deletions (only) */
xpath = "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//" XML_TAG_FENCING_LEVEL;
xpathObj = xpath_search(msg, xpath);
remove_fencing_topology(xpathObj);
freeXpathObject(xpathObj);
/* Process additions and changes */
xpath = "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_TAG_FENCING_LEVEL;
xpathObj = xpath_search(msg, xpath);
register_fencing_topology(xpathObj);
freeXpathObject(xpathObj);
} else if(format == 2) {
xmlNode *change = NULL;
int add[] = { 0, 0, 0 };
int del[] = { 0, 0, 0 };
xml_patch_versions(patchset, add, del);
for (change = pcmk__xml_first_child(patchset); change != NULL;
change = pcmk__xml_next(change)) {
const char *op = crm_element_value(change, XML_DIFF_OP);
const char *xpath = crm_element_value(change, XML_DIFF_PATH);
if(op == NULL) {
continue;
} else if(strstr(xpath, "/" XML_TAG_FENCING_LEVEL) != NULL) {
/* Change to a specific entry */
crm_trace("Handling %s operation %d.%d.%d for %s", op, add[0], add[1], add[2], xpath);
if(strcmp(op, "move") == 0) {
continue;
} else if(strcmp(op, "create") == 0) {
add_topology_level(change->children);
} else if(strcmp(op, "modify") == 0) {
xmlNode *match = first_named_child(change, XML_DIFF_RESULT);
if(match) {
remove_topology_level(match->children);
add_topology_level(match->children);
}
} else if(strcmp(op, "delete") == 0) {
/* Nuclear option, all we have is the path and an id... not enough to remove a specific entry */
crm_info("Re-initializing fencing topology after %s operation %d.%d.%d for %s",
op, add[0], add[1], add[2], xpath);
fencing_topology_init();
return;
}
} else if (strstr(xpath, "/" XML_TAG_FENCING_TOPOLOGY) != NULL) {
/* Change to the topology in general */
crm_info("Re-initializing fencing topology after top-level %s operation %d.%d.%d for %s",
op, add[0], add[1], add[2], xpath);
fencing_topology_init();
return;
} else if (strstr(xpath, "/" XML_CIB_TAG_CONFIGURATION)) {
/* Changes to the whole config section, possibly including the topology as a whild */
if(first_named_child(change, XML_TAG_FENCING_TOPOLOGY) == NULL) {
crm_trace("Nothing for us in %s operation %d.%d.%d for %s.",
op, add[0], add[1], add[2], xpath);
} else if(strcmp(op, "delete") == 0 || strcmp(op, "create") == 0) {
crm_info("Re-initializing fencing topology after top-level %s operation %d.%d.%d for %s.",
op, add[0], add[1], add[2], xpath);
fencing_topology_init();
return;
}
} else {
crm_trace("Nothing for us in %s operation %d.%d.%d for %s",
op, add[0], add[1], add[2], xpath);
}
}
} else {
crm_warn("Unknown patch format: %d", format);
}
}
static bool have_cib_devices = FALSE;
static void
update_cib_cache_cb(const char *event, xmlNode * msg)
{
int rc = pcmk_ok;
long timeout_ms_saved = stonith_watchdog_timeout_ms;
gboolean need_full_refresh = FALSE;
if(!have_cib_devices) {
crm_trace("Skipping updates until we get a full dump");
return;
} else if(msg == NULL) {
crm_trace("Missing %s update", event);
return;
}
/* Maintain a local copy of the CIB so that we have full access
* to device definitions, location constraints, and node attributes
*/
if (local_cib != NULL) {
int rc = pcmk_ok;
xmlNode *patchset = NULL;
crm_element_value_int(msg, F_CIB_RC, &rc);
if (rc != pcmk_ok) {
return;
}
patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
xml_log_patchset(LOG_TRACE, "Config update", patchset);
rc = xml_apply_patchset(local_cib, patchset, TRUE);
switch (rc) {
case pcmk_ok:
case -pcmk_err_old_data:
break;
case -pcmk_err_diff_resync:
case -pcmk_err_diff_failed:
crm_notice("[%s] Patch aborted: %s (%d)", event, pcmk_strerror(rc), rc);
free_xml(local_cib);
local_cib = NULL;
break;
default:
crm_warn("[%s] ABORTED: %s (%d)", event, pcmk_strerror(rc), rc);
free_xml(local_cib);
local_cib = NULL;
}
}
if (local_cib == NULL) {
crm_trace("Re-requesting full CIB");
rc = cib_api->cmds->query(cib_api, NULL, &local_cib, cib_scope_local | cib_sync_call);
if(rc != pcmk_ok) {
crm_err("Couldn't retrieve the CIB: %s (%d)", pcmk_strerror(rc), rc);
return;
}
CRM_ASSERT(local_cib != NULL);
need_full_refresh = TRUE;
}
pcmk__refresh_node_caches_from_cib(local_cib);
update_stonith_watchdog_timeout_ms(local_cib);
if (timeout_ms_saved != stonith_watchdog_timeout_ms) {
need_full_refresh = TRUE;
} else {
update_fencing_topology(event, msg);
update_cib_stonith_devices(event, msg);
watchdog_device_update();
}
if (need_full_refresh) {
fencing_topology_init();
cib_devices_update();
watchdog_device_update();
}
}
static void
init_cib_cache_cb(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
{
crm_info("Updating device list from CIB");
have_cib_devices = TRUE;
local_cib = copy_xml(output);
pcmk__refresh_node_caches_from_cib(local_cib);
update_stonith_watchdog_timeout_ms(local_cib);
fencing_topology_init();
cib_devices_update();
watchdog_device_update();
}
static void
stonith_shutdown(int nsig)
{
crm_info("Terminating with %d clients", pcmk__ipc_client_count());
stonith_shutdown_flag = TRUE;
if (mainloop != NULL && g_main_loop_is_running(mainloop)) {
g_main_loop_quit(mainloop);
} else {
stonith_cleanup();
crm_exit(CRM_EX_OK);
}
}
static void
cib_connection_destroy(gpointer user_data)
{
if (stonith_shutdown_flag) {
crm_info("Connection to the CIB manager closed");
return;
} else {
crm_crit("Lost connection to the CIB manager, shutting down");
}
if (cib_api) {
cib_api->cmds->signoff(cib_api);
}
stonith_shutdown(0);
}
static void
stonith_cleanup(void)
{
if (cib_api) {
cib_api->cmds->del_notify_callback(cib_api, T_CIB_DIFF_NOTIFY, update_cib_cache_cb);
cib_api->cmds->signoff(cib_api);
}
if (ipcs) {
qb_ipcs_destroy(ipcs);
}
crm_peer_destroy();
pcmk__client_cleanup();
free_stonith_remote_op_list();
free_topology_list();
free_device_list();
free_metadata_cache();
fenced_unregister_handlers();
free(stonith_our_uname);
stonith_our_uname = NULL;
free_xml(local_cib);
local_cib = NULL;
}
static pcmk__cli_option_t long_options[] = {
// long option, argument type, storage, short option, description, flags
{
"stand-alone", no_argument, 0, 's',
"\tDeprecated (will be removed in a future release)",
pcmk__option_default
},
{
"stand-alone-w-cpg", no_argument, 0, 'c',
"\tIntended for use in regression testing only",
pcmk__option_default
},
{
"logfile", required_argument, 0, 'l',
NULL, pcmk__option_default
},
{
"verbose", no_argument, 0, 'V',
NULL, pcmk__option_default
},
{
"version", no_argument, 0, '$',
NULL, pcmk__option_default
},
{
"help", no_argument, 0, '?',
NULL, pcmk__option_default
},
{ 0, 0, 0, 0 }
};
static void
setup_cib(void)
{
int rc, retries = 0;
cib_api = cib_new();
if (cib_api == NULL) {
crm_err("No connection to the CIB manager");
return;
}
do {
sleep(retries);
rc = cib_api->cmds->signon(cib_api, CRM_SYSTEM_STONITHD, cib_command);
} while (rc == -ENOTCONN && ++retries < 5);
if (rc != pcmk_ok) {
crm_err("Could not connect to the CIB manager: %s (%d)", pcmk_strerror(rc), rc);
} else if (pcmk_ok !=
cib_api->cmds->add_notify_callback(cib_api, T_CIB_DIFF_NOTIFY, update_cib_cache_cb)) {
crm_err("Could not set CIB notification callback");
} else {
rc = cib_api->cmds->query(cib_api, NULL, NULL, cib_scope_local);
cib_api->cmds->register_callback(cib_api, rc, 120, FALSE, NULL, "init_cib_cache_cb",
init_cib_cache_cb);
cib_api->cmds->set_connection_dnotify(cib_api, cib_connection_destroy);
crm_info("Watching for fencing topology changes");
}
}
struct qb_ipcs_service_handlers ipc_callbacks = {
.connection_accept = st_ipc_accept,
.connection_created = NULL,
.msg_process = st_ipc_dispatch,
.connection_closed = st_ipc_closed,
.connection_destroyed = st_ipc_destroy
};
/*!
* \internal
* \brief Callback for peer status changes
*
* \param[in] type What changed
* \param[in] node What peer had the change
* \param[in] data Previous value of what changed
*/
static void
st_peer_update_callback(enum crm_status_type type, crm_node_t * node, const void *data)
{
if ((type != crm_status_processes)
&& !pcmk_is_set(node->flags, crm_remote_node)) {
/*
* This is a hack until we can send to a nodeid and/or we fix node name lookups
* These messages are ignored in stonith_peer_callback()
*/
xmlNode *query = create_xml_node(NULL, "stonith_command");
crm_xml_add(query, F_XML_TAGNAME, "stonith_command");
crm_xml_add(query, F_TYPE, T_STONITH_NG);
crm_xml_add(query, F_STONITH_OPERATION, "poke");
crm_debug("Broadcasting our uname because of node %u", node->id);
send_cluster_message(NULL, crm_msg_stonith_ng, query, FALSE);
free_xml(query);
}
}
+static pcmk__cluster_option_t fencer_options[] = {
+ /* name, old name, type, allowed values,
+ * default value, validator,
+ * short description,
+ * long description
+ */
+ {
+ PCMK_STONITH_HOST_ARGUMENT, NULL, "string", NULL, "port", NULL,
+ N_("Advanced use only: An alternate parameter to supply instead of 'port'"),
+ N_("some devices do not support the "
+ "standard 'port' parameter or may provide additional ones. Use "
+ "this to specify an alternate, device-specific, parameter "
+ "that should indicate the machine to be fenced. A value of "
+ "none can be used to tell the cluster not to supply any "
+ "additional parameters.")
+ },
+ {
+ PCMK_STONITH_HOST_MAP,NULL, "string", NULL, "", NULL,
+ N_("A mapping of host names to ports numbers for devices that do not support host names."),
+ N_("Eg. node1:1;node2:2,3 would tell the cluster to use port 1 for node1 and ports 2 and 3 for node2")
+ },
+ {
+ PCMK_STONITH_HOST_LIST,NULL, "string", NULL, "", NULL,
+ N_("Eg. node1,node2,node3"),
+ N_("A list of machines controlled by "
+ "this device (Optional unless pcmk_host_list=static-list)")
+ },
+ {
+ PCMK_STONITH_HOST_CHECK,NULL, "string", NULL, "dynamic-list", NULL,
+ N_("How to determine which machines are controlled by the device."),
+ N_("Allowed values: dynamic-list "
+ "(query the device via the 'list' command), static-list "
+ "(check the pcmk_host_list attribute), status "
+ "(query the device via the 'status' command), "
+ "none (assume every device can fence every "
+ "machine)")
+ },
+ {
+ PCMK_STONITH_DELAY_MAX,NULL, "time", NULL, "0s", NULL,
+ N_("Enable a base delay for fencing actions and specify base delay value."),
+ N_("Enable a delay of no more than the "
+ "time specified before executing fencing actions. Pacemaker "
+ "derives the overall delay by taking the value of "
+ "pcmk_delay_base and adding a random delay value such "
+ "that the sum is kept below this maximum.")
+ },
+ {
+ PCMK_STONITH_DELAY_BASE,NULL, "string", NULL, "0s", NULL,
+ N_("Enable a base delay for "
+ "fencing actions and specify base delay value."),
+ N_("This enables a static delay for "
+ "fencing actions, which can help avoid \"death matches\" where "
+ "two nodes try to fence each other at the same time. If "
+ "pcmk_delay_max is also used, a random delay will be "
+ "added such that the total delay is kept below that value."
+ "This can be set to a single time value to apply to any node "
+ "targeted by this device (useful if a separate device is "
+ "configured for each target), or to a node map (for example, "
+ "\"node1:1s;node2:5\") to set a different value per target.")
+ },
+ {
+ PCMK_STONITH_ACTION_LIMIT,NULL, "integer", NULL, "1", NULL,
+ N_("The maximum number of actions can be performed in parallel on this device"),
+ N_("Cluster property concurrent-fencing=true needs to be configured first."
+ "Then use this to specify the maximum number of actions can be performed in parallel on this device. -1 is unlimited.")
+ },
+ {
+ "pcmk_reboot_action",NULL, "string", NULL, "reboot", NULL,
+ N_("Advanced use only: An alternate command to run instead of 'reboot'"),
+ N_("Some devices do not support the standard commands or may provide additional ones.\n"
+ "Use this to specify an alternate, device-specific, command that implements the \'reboot\' action.")
+ },
+ {
+ "pcmk_reboot_timeout",NULL, "time", NULL, "60s", NULL,
+ N_("Advanced use only: Specify an alternate timeout to use for reboot actions instead of stonith-timeout"),
+ N_("Some devices need much more/less time to complete than normal."
+ "Use this to specify an alternate, device-specific, timeout for \'reboot\' actions.")
+ },
+ {
+ "pcmk_reboot_retries",NULL, "integer", NULL, "2", NULL,
+ N_("Advanced use only: The maximum number of times to retry the 'reboot' command within the timeout period"),
+ N_("Some devices do not support multiple connections."
+ " Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining."
+ " Use this option to alter the number of times Pacemaker retries \'reboot\' actions before giving up.")
+ },
+ {
+ "pcmk_off_action",NULL, "string", NULL, "off", NULL,
+ N_("Advanced use only: An alternate command to run instead of \'off\'"),
+ N_("Some devices do not support the standard commands or may provide additional ones."
+ "Use this to specify an alternate, device-specific, command that implements the \'off\' action.")
+ },
+ {
+ "pcmk_off_timeout",NULL, "time", NULL, "60s", NULL,
+ N_("Advanced use only: Specify an alternate timeout to use for off actions instead of stonith-timeout"),
+ N_("Some devices need much more/less time to complete than normal."
+ "Use this to specify an alternate, device-specific, timeout for \'off\' actions.")
+ },
+ {
+ "pcmk_off_retries",NULL, "integer", NULL, "2", NULL,
+ N_("Advanced use only: The maximum number of times to retry the 'off' command within the timeout period"),
+ N_("Some devices do not support multiple connections."
+ " Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining."
+ " Use this option to alter the number of times Pacemaker retries \'off\' actions before giving up.")
+ },
+ {
+ "pcmk_on_action",NULL, "string", NULL, "on", NULL,
+ N_("Advanced use only: An alternate command to run instead of 'on'"),
+ N_("Some devices do not support the standard commands or may provide additional ones."
+ "Use this to specify an alternate, device-specific, command that implements the \'on\' action.")
+ },
+ {
+ "pcmk_on_timeout",NULL, "time", NULL, "60s", NULL,
+ N_("Advanced use only: Specify an alternate timeout to use for on actions instead of stonith-timeout"),
+ N_("Some devices need much more/less time to complete than normal."
+ "Use this to specify an alternate, device-specific, timeout for \'on\' actions.")
+ },
+ {
+ "pcmk_on_retries",NULL, "integer", NULL, "2", NULL,
+ N_("Advanced use only: The maximum number of times to retry the 'on' command within the timeout period"),
+ N_("Some devices do not support multiple connections."
+ " Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining."
+ " Use this option to alter the number of times Pacemaker retries \'on\' actions before giving up.")
+ },
+ {
+ "pcmk_list_action",NULL, "string", NULL, "list", NULL,
+ N_("Advanced use only: An alternate command to run instead of \'list\'"),
+ N_("Some devices do not support the standard commands or may provide additional ones."
+ "Use this to specify an alternate, device-specific, command that implements the \'list\' action.")
+ },
+ {
+ "pcmk_list_timeout",NULL, "time", NULL, "60s", NULL,
+ N_("Advanced use only: Specify an alternate timeout to use for list actions instead of stonith-timeout"),
+ N_("Some devices need much more/less time to complete than normal."
+ "Use this to specify an alternate, device-specific, timeout for \'list\' actions.")
+ },
+ {
+ "pcmk_list_retries",NULL, "integer", NULL, "2", NULL,
+ N_("Advanced use only: The maximum number of times to retry the \'list\' command within the timeout period"),
+ N_("Some devices do not support multiple connections."
+ " Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining."
+ " Use this option to alter the number of times Pacemaker retries \'list\' actions before giving up.")
+ },
+ {
+ "pcmk_monitor_action",NULL, "string", NULL, "monitor", NULL,
+ N_("Advanced use only: An alternate command to run instead of \'monitor\'"),
+ N_("Some devices do not support the standard commands or may provide additional ones."
+ "Use this to specify an alternate, device-specific, command that implements the \'monitor\' action.")
+ },
+ {
+ "pcmk_monitor_timeout",NULL, "time", NULL, "60s", NULL,
+ N_("Advanced use only: Specify an alternate timeout to use for monitor actions instead of stonith-timeout"),
+ N_("Some devices need much more/less time to complete than normal.\n"
+ "Use this to specify an alternate, device-specific, timeout for \'monitor\' actions.")
+ },
+ {
+ "pcmk_monitor_retries",NULL, "integer", NULL, "2", NULL,
+ N_("Advanced use only: The maximum number of times to retry the \'monitor\' command within the timeout period"),
+ N_("Some devices do not support multiple connections."
+ " Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining."
+ " Use this option to alter the number of times Pacemaker retries \'monitor\' actions before giving up.")
+ },
+ {
+ "pcmk_status_action",NULL, "string", NULL, "status", NULL,
+ N_("Advanced use only: An alternate command to run instead of \'status\'"),
+ N_("Some devices do not support the standard commands or may provide additional ones."
+ "Use this to specify an alternate, device-specific, command that implements the \'status\' action.")
+ },
+ {
+ "pcmk_status_timeout",NULL, "time", NULL, "60s", NULL,
+ N_("Advanced use only: Specify an alternate timeout to use for status actions instead of stonith-timeout"),
+ N_("Some devices need much more/less time to complete than normal."
+ "Use this to specify an alternate, device-specific, timeout for \'status\' actions.")
+ },
+ {
+ "pcmk_status_retries",NULL, "integer", NULL, "2", NULL,
+ N_("Advanced use only: The maximum number of times to retry the \'status\' command within the timeout period"),
+ N_("Some devices do not support multiple connections."
+ " Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining."
+ " Use this option to alter the number of times Pacemaker retries \'status\' actions before giving up.")
+ },
+};
+
+void
+fencer_metadata(void)
+{
+ char *s = pcmk__format_option_metadata("pacemaker-fenced",
+ "Instance attributes available for all \"stonith\"-class resources",
+ "Instance attributes available for all \"stonith\"-class resources"
+ "and used by Pacemaker's fence daemon, formerly known as stonithd",
+ fencer_options,
+ PCMK__NELEM(fencer_options));
+ printf("%s", s);
+ free(s);
+}
+
+/*
+static const char *
+fenceder_options(GHashTable *options, const char *name)
+{
+ return pcmk__cluster_option(options, fenceder_options,
+ PCMK__NELEM(fenceder_options), name);
+}
+*/
int
main(int argc, char **argv)
{
int flag;
- int lpc = 0;
int argerr = 0;
int option_index = 0;
crm_cluster_t *cluster = NULL;
- const char *actions[] = { "reboot", "off", "on", "list", "monitor", "status" };
crm_ipc_t *old_instance = NULL;
int rc = pcmk_rc_ok;
crm_log_preinit(NULL, argc, argv);
pcmk__set_cli_options(NULL, "[options]", long_options,
"daemon for executing fencing devices in a "
"Pacemaker cluster");
while (1) {
flag = pcmk__next_cli_option(argc, argv, &option_index, NULL);
if (flag == -1) {
break;
}
switch (flag) {
case 'V':
crm_bump_log_level(argc, argv);
break;
case 'l':
{
int rc = pcmk__add_logfile(optarg);
if (rc != pcmk_rc_ok) {
/* Logging has not yet been initialized, so stderr is
* the only way to get information out
*/
fprintf(stderr, "Logging to %s is disabled: %s\n",
optarg, pcmk_rc_str(rc));
}
}
break;
case 's':
stand_alone = TRUE;
break;
case 'c':
stand_alone = FALSE;
no_cib_connect = TRUE;
break;
case '$':
case '?':
pcmk__cli_help(flag, CRM_EX_OK);
break;
default:
++argerr;
break;
}
}
if (argc - optind == 1 && pcmk__str_eq("metadata", argv[optind], pcmk__str_casei)) {
- printf("<?xml version=\"1.0\"?><!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n");
- printf("<resource-agent name=\"pacemaker-fenced\">\n");
- printf(" <version>1.0</version>\n");
- printf(" <longdesc lang=\"en\">Instance attributes available for all \"stonith\"-class resources"
- " and used by Pacemaker's fence daemon, formerly known as stonithd</longdesc>\n");
-#ifdef ENABLE_NLS
- printf(_(" <longdesc lang=\"en\">Instance attributes available for all \"stonith\"-class resources"
- " and used by Pacemaker's fence daemon, formerly known as stonithd</longdesc>\n"));
-#endif
- printf(" <shortdesc lang=\"en\">Instance attributes available for all \"stonith\"-class resources</shortdesc>\n");
-#ifdef ENABLE_NLS
- printf(_(" <shortdesc lang=\"en\">Instance attributes available for all \"stonith\"-class resources</shortdesc>\n"));
-#endif
- printf(" <parameters>\n");
-
-#if 0
- // priority is not implemented yet
- printf(" <parameter name=\"priority\" unique=\"0\">\n");
- printf(" <shortdesc lang=\"en\">Devices that are not in a topology "
- "are tried in order of highest to lowest integer priority</shortdesc>\n");
- printf(" <content type=\"integer\" default=\"0\"/>\n");
- printf(" </parameter>\n");
-#endif
-
- printf(" <parameter name=\"%s\" unique=\"0\">\n",
- PCMK_STONITH_HOST_ARGUMENT);
- printf(" <longdesc lang=\"en\">Some devices do not support the "
- "standard 'port' parameter or may provide additional ones. Use "
- "this to specify an alternate, device-specific, parameter "
- "that should indicate the machine to be fenced. A value of "
- "'%s' can be used to tell the cluster not to supply any "
- "additional parameters.\n"
- " </longdesc>\n", PCMK__VALUE_NONE);
-#ifdef ENABLE_NLS
- printf(_(" <longdesc lang=\"en\">Some devices do not support the "
- "standard 'port' parameter or may provide additional ones. Use "
- "this to specify an alternate, device-specific, parameter "
- "that should indicate the machine to be fenced. A value of "
- "'%s' can be used to tell the cluster not to supply any "
- "additional parameters.\n"
- " </longdesc>\n"), PCMK__VALUE_NONE);
-#endif
- printf
- (" <shortdesc lang=\"en\">Advanced use only: An alternate parameter to supply instead of 'port'</shortdesc>\n");
-#ifdef ENABLE_NLS
- printf
- (_(" <shortdesc lang=\"en\">Advanced use only: An alternate parameter to supply instead of 'port'</shortdesc>\n"));
-#endif
- printf(" <content type=\"string\" default=\"port\"/>\n");
- printf(" </parameter>\n");
-
- printf(" <parameter name=\"%s\" unique=\"0\">\n",
- PCMK_STONITH_HOST_MAP);
- printf
- (" <longdesc lang=\"en\">Eg. node1:1;node2:2,3 would tell the cluster to use port 1 for node1 and ports 2 and 3 for node2</longdesc>\n");
-#ifdef ENABLE_NLS
- printf
- (_(" <longdesc lang=\"en\">Eg. node1:1;node2:2,3 would tell the cluster to use port 1 for node1 and ports 2 and 3 for node2</longdesc>\n"));
-#endif
- printf
- (" <shortdesc lang=\"en\">A mapping of host names to ports numbers for devices that do not support host names.</shortdesc>\n");
-#ifdef ENABLE_NLS
- printf
- (_(" <shortdesc lang=\"en\">A mapping of host names to ports numbers for devices that do not support host names.</shortdesc>\n"));
-#endif
- printf(" <content type=\"string\" default=\"\"/>\n");
- printf(" </parameter>\n");
-
- printf(" <parameter name=\"%s\" unique=\"0\">\n",
- PCMK_STONITH_HOST_LIST);
- printf(" <longdesc lang=\"en\">Eg. node1,node2,node3</longdesc>\n");
- printf(" <shortdesc lang=\"en\">A list of machines controlled by "
- "this device (Optional unless %s=static-list).</shortdesc>\n",
- PCMK_STONITH_HOST_CHECK);
- printf(" <content type=\"string\" default=\"\"/>\n");
- printf(" </parameter>\n");
-
- printf(" <parameter name=\"%s\" unique=\"0\">\n",
- PCMK_STONITH_HOST_CHECK);
- printf(" <longdesc lang=\"en\">Allowed values: dynamic-list "
- "(query the device via the 'list' command), static-list "
- "(check the " PCMK_STONITH_HOST_LIST " attribute), status "
- "(query the device via the 'status' command), "
- PCMK__VALUE_NONE " (assume every device can fence every "
- "machine)</longdesc>\n");
- printf
- (" <shortdesc lang=\"en\">How to determine which machines are controlled by the device.</shortdesc>\n");
- printf(" <content type=\"string\" default=\"dynamic-list\"/>\n");
- printf(" </parameter>\n");
-
- printf(" <parameter name=\"%s\" unique=\"0\">\n",
- PCMK_STONITH_DELAY_MAX);
- printf(" <longdesc lang=\"en\">This prevents double fencing when "
- "using slow devices such as sbd.\nUse this to enable a random "
- "delay for fencing actions.\nThe overall delay is derived from "
- "this random delay value adding a static delay so that the sum "
- "is kept below the maximum delay.</longdesc>\n");
- printf(" <shortdesc lang=\"en\">Enable a delay of no more than the "
- "time specified before executing fencing actions. Pacemaker "
- "derives the overall delay by taking the value of "
- PCMK_STONITH_DELAY_BASE " and adding a random delay value such "
- "that the sum is kept below this maximum.</shortdesc>\n");
- printf(" <content type=\"time\" default=\"0s\"/>\n");
- printf(" </parameter>\n");
-
- printf(" <parameter name=\"%s\" unique=\"0\">\n",
- PCMK_STONITH_DELAY_BASE);
- printf(" <longdesc lang=\"en\">This enables a static delay for "
- "fencing actions, which can help avoid \"death matches\" where "
- "two nodes try to fence each other at the same time. If "
- PCMK_STONITH_DELAY_MAX " is also used, a random delay will be "
- "added such that the total delay is kept below that value.\n"
- "This can be set to a single time value to apply to any node "
- "targeted by this device (useful if a separate device is "
- "configured for each target), or to a node map (for example, "
- "\"node1:1s;node2:5\") to set a different value per target.\n"
- " </longdesc>\n");
- printf(" <shortdesc lang=\"en\">Enable a base delay for "
- "fencing actions and specify base delay value.</shortdesc>\n");
- printf(" <content type=\"string\" default=\"0s\"/>\n");
- printf(" </parameter>\n");
-
- printf(" <parameter name=\"%s\" unique=\"0\">\n",
- PCMK_STONITH_ACTION_LIMIT);
- printf
- (" <longdesc lang=\"en\">Cluster property concurrent-fencing=true needs to be configured first.\n"
- "Then use this to specify the maximum number of actions can be performed in parallel on this device. -1 is unlimited.</longdesc>\n");
- printf
- (" <shortdesc lang=\"en\">The maximum number of actions can be performed in parallel on this device</shortdesc>\n");
- printf(" <content type=\"integer\" default=\"1\"/>\n");
- printf(" </parameter>\n");
-
-
- for (lpc = 0; lpc < PCMK__NELEM(actions); lpc++) {
- printf(" <parameter name=\"pcmk_%s_action\" unique=\"0\">\n", actions[lpc]);
- printf
- (" <longdesc lang=\"en\">Some devices do not support the standard commands or may provide additional ones.\n"
- "Use this to specify an alternate, device-specific, command that implements the '%s' action.</longdesc>\n",
- actions[lpc]);
- printf
- (" <shortdesc lang=\"en\">Advanced use only: An alternate command to run instead of '%s'</shortdesc>\n",
- actions[lpc]);
- printf(" <content type=\"string\" default=\"%s\"/>\n", actions[lpc]);
- printf(" </parameter>\n");
-
- printf(" <parameter name=\"pcmk_%s_timeout\" unique=\"0\">\n", actions[lpc]);
- printf
- (" <longdesc lang=\"en\">Some devices need much more/less time to complete than normal.\n"
- "Use this to specify an alternate, device-specific, timeout for '%s' actions.</longdesc>\n",
- actions[lpc]);
- printf
- (" <shortdesc lang=\"en\">Advanced use only: Specify an alternate timeout to use for %s actions instead of stonith-timeout</shortdesc>\n",
- actions[lpc]);
- printf(" <content type=\"time\" default=\"60s\"/>\n");
- printf(" </parameter>\n");
-
- printf(" <parameter name=\"pcmk_%s_retries\" unique=\"0\">\n", actions[lpc]);
- printf(" <longdesc lang=\"en\">Some devices do not support multiple connections."
- " Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining."
- " Use this option to alter the number of times Pacemaker retries '%s' actions before giving up."
- "</longdesc>\n", actions[lpc]);
- printf
- (" <shortdesc lang=\"en\">Advanced use only: The maximum number of times to retry the '%s' command within the timeout period</shortdesc>\n",
- actions[lpc]);
- printf(" <content type=\"integer\" default=\"2\"/>\n");
- printf(" </parameter>\n");
- }
-
- printf(" </parameters>\n");
- printf("</resource-agent>\n");
+ fencer_metadata();
return CRM_EX_OK;
- }
-
+ }
if (optind != argc) {
++argerr;
}
if (argerr) {
pcmk__cli_help('?', CRM_EX_USAGE);
}
crm_log_init(NULL, LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
crm_notice("Starting Pacemaker fencer");
old_instance = crm_ipc_new("stonith-ng", 0);
if (crm_ipc_connect(old_instance)) {
- /* IPC end-point already up */
+ // IPC end-point already up
crm_ipc_close(old_instance);
crm_ipc_destroy(old_instance);
crm_err("pacemaker-fenced is already active, aborting startup");
crm_exit(CRM_EX_OK);
} else {
- /* not up or not authentic, we'll proceed either way */
+ // not up or not authentic, we'll proceed either way
crm_ipc_destroy(old_instance);
old_instance = NULL;
}
mainloop_add_signal(SIGTERM, stonith_shutdown);
crm_peer_init();
fenced_data_set = pe_new_working_set();
CRM_ASSERT(fenced_data_set != NULL);
cluster = calloc(1, sizeof(crm_cluster_t));
CRM_ASSERT(cluster != NULL);
if (stand_alone == FALSE) {
if (is_corosync_cluster()) {
#if SUPPORT_COROSYNC
cluster->destroy = stonith_peer_cs_destroy;
cluster->cpg.cpg_deliver_fn = stonith_peer_ais_callback;
cluster->cpg.cpg_confchg_fn = pcmk_cpg_membership;
#endif
}
crm_set_status_callback(&st_peer_update_callback);
if (crm_cluster_connect(cluster) == FALSE) {
crm_crit("Cannot sign in to the cluster... terminating");
crm_exit(CRM_EX_FATAL);
}
stonith_our_uname = strdup(cluster->uname);
if (no_cib_connect == FALSE) {
setup_cib();
}
} else {
stonith_our_uname = strdup("localhost");
crm_warn("Stand-alone mode is deprecated and will be removed "
"in a future release");
}
init_device_list();
init_topology_list();
pcmk__serve_fenced_ipc(&ipcs, &ipc_callbacks);
pcmk__register_formats(NULL, formats);
rc = pcmk__output_new(&out, "log", NULL, argv);
if ((rc != pcmk_rc_ok) || (out == NULL)) {
crm_err("Can't log resource details due to internal error: %s\n",
pcmk_rc_str(rc));
crm_exit(CRM_EX_FATAL);
}
pe__register_messages(out);
pcmk__register_lib_messages(out);
pcmk__output_set_log_level(out, LOG_TRACE);
fenced_data_set->priv = out;
- /* Create the mainloop and run it... */
+ // Create the mainloop and run it...
mainloop = g_main_loop_new(NULL, FALSE);
crm_notice("Pacemaker fencer successfully started and accepting connections");
g_main_loop_run(mainloop);
stonith_cleanup();
free(cluster->uuid);
free(cluster->uname);
free(cluster);
pe_free_working_set(fenced_data_set);
out->finish(out, CRM_EX_OK, true, NULL);
pcmk__output_free(out);
pcmk__unregister_formats();
crm_exit(CRM_EX_OK);
}
diff --git a/daemons/fenced/pacemaker-fenced.h b/daemons/fenced/pacemaker-fenced.h
index 18e8da48f9..546799306a 100644
--- a/daemons/fenced/pacemaker-fenced.h
+++ b/daemons/fenced/pacemaker-fenced.h
@@ -1,293 +1,294 @@
/*
* Copyright 2009-2022 the Pacemaker project contributors
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <stdint.h> // uint32_t, uint64_t
#include <crm/common/mainloop.h>
/*!
* \internal
* \brief Check whether target has already been fenced recently
*
* \param[in] tolerance Number of seconds to look back in time
* \param[in] target Name of node to search for
* \param[in] action Action we want to match
*
* \return TRUE if an equivalent fencing operation took place in the last
* \p tolerance seconds, FALSE otherwise
*/
gboolean stonith_check_fence_tolerance(int tolerance, const char *target, const char *action);
typedef struct stonith_device_s {
char *id;
char *agent;
char *namespace;
/*! list of actions that must execute on the target node. Used for unfencing */
char *on_target_actions;
GList *targets;
time_t targets_age;
gboolean has_attr_map;
// Whether target's nodeid should be passed as a parameter to the agent
gboolean include_nodeid;
/* whether the cluster should automatically unfence nodes with the device */
gboolean automatic_unfencing;
guint priority;
uint32_t flags; // Group of enum st_device_flags
GHashTable *params;
GHashTable *aliases;
GList *pending_ops;
mainloop_timer_t *timer;
crm_trigger_t *work;
xmlNode *agent_metadata;
/*! A verified device is one that has contacted the
* agent successfully to perform a monitor operation */
gboolean verified;
gboolean cib_registered;
gboolean api_registered;
gboolean dirty;
} stonith_device_t;
/* These values are used to index certain arrays by "phase". Usually an
* operation has only one "phase", so phase is always zero. However, some
* reboots are remapped to "off" then "on", in which case "reboot" will be
* phase 0, "off" will be phase 1 and "on" will be phase 2.
*/
enum st_remap_phase {
st_phase_requested = 0,
st_phase_off = 1,
st_phase_on = 2,
st_phase_max = 3
};
typedef struct remote_fencing_op_s {
/* The unique id associated with this operation */
char *id;
/*! The node this operation will fence */
char *target;
/*! The fencing action to perform on the target. (reboot, on, off) */
char *action;
/*! When was the fencing action recorded (seconds since epoch) */
time_t created;
/*! Marks if the final notifications have been sent to local stonith clients. */
gboolean notify_sent;
/*! The number of query replies received */
guint replies;
/*! The number of query replies expected */
guint replies_expected;
/*! Does this node own control of this operation */
gboolean owner;
/*! After query is complete, This the high level timer that expires the entire operation */
guint op_timer_total;
/*! This timer expires the current fencing request. Many fencing
* requests may exist in a single operation */
guint op_timer_one;
/*! This timer expires the query request sent out to determine
* what nodes are contain what devices, and who those devices can fence */
guint query_timer;
/*! This is the default timeout to use for each fencing device if no
* custom timeout is received in the query. */
gint base_timeout;
/*! This is the calculated total timeout an operation can take before
* expiring. This is calculated by adding together all the timeout
* values associated with the devices this fencing operation may call */
gint total_timeout;
/*! Requested fencing delay.
* Value -1 means disable any static/random fencing delays. */
int delay;
/*! Delegate is the node being asked to perform a fencing action
* on behalf of the node that owns the remote operation. Some operations
* will involve multiple delegates. This value represents the final delegate
* that is used. */
char *delegate;
/*! The point at which the remote operation completed */
time_t completed;
//! Group of enum stonith_call_options associated with this operation
uint32_t call_options;
/*! The current state of the remote operation. This indicates
* what stage the op is in, query, exec, done, duplicate, failed. */
enum op_state state;
/*! The node that owns the remote operation */
char *originator;
/*! The local client id that initiated the fencing request */
char *client_id;
/*! The client's call_id that initiated the fencing request */
int client_callid;
/*! The name of client that initiated the fencing request */
char *client_name;
/*! List of the received query results for all the nodes in the cpg group */
GList *query_results;
/*! The original request that initiated the remote stonith operation */
xmlNode *request;
/*! The current topology level being executed */
guint level;
/*! The current operation phase being executed */
enum st_remap_phase phase;
/*! Devices with automatic unfencing (always run if "on" requested, never if remapped) */
GList *automatic_list;
/*! List of all devices at the currently executing topology level */
GList *devices_list;
/*! Current entry in the topology device list */
GList *devices;
/*! List of duplicate operations attached to this operation. Once this operation
* completes, the duplicate operations will be closed out as well. */
GList *duplicates;
/*! The point at which the remote operation completed(nsec) */
long long completed_nsec;
/*! The (potentially intermediate) result of the operation */
pcmk__action_result_t result;
} remote_fencing_op_t;
void fenced_broadcast_op_result(const remote_fencing_op_t *op, bool op_merged);
// Fencer-specific client flags
enum st_client_flags {
st_callback_unknown = UINT64_C(0),
st_callback_notify_fence = (UINT64_C(1) << 0),
st_callback_device_add = (UINT64_C(1) << 2),
st_callback_device_del = (UINT64_C(1) << 4),
st_callback_notify_history = (UINT64_C(1) << 5),
st_callback_notify_history_synced = (UINT64_C(1) << 6)
};
// How the user specified the target of a topology level
enum fenced_target_by {
fenced_target_by_unknown = -1, // Invalid or not yet parsed
fenced_target_by_name, // By target name
fenced_target_by_pattern, // By a pattern matching target names
fenced_target_by_attribute, // By a node attribute/value on target
};
/*
* Complex fencing requirements are specified via fencing topologies.
* A topology consists of levels; each level is a list of fencing devices.
* Topologies are stored in a hash table by node name. When a node needs to be
* fenced, if it has an entry in the topology table, the levels are tried
* sequentially, and the devices in each level are tried sequentially.
* Fencing is considered successful as soon as any level succeeds;
* a level is considered successful if all its devices succeed.
* Essentially, all devices at a given level are "and-ed" and the
* levels are "or-ed".
*
* This structure is used for the topology table entries.
* Topology levels start from 1, so levels[0] is unused and always NULL.
*/
typedef struct stonith_topology_s {
enum fenced_target_by kind; // How target was specified
/*! Node name regex or attribute name=value for which topology applies */
char *target;
char *target_value;
char *target_pattern;
char *target_attribute;
/*! Names of fencing devices at each topology level */
GList *levels[ST_LEVEL_MAX];
} stonith_topology_t;
void init_device_list(void);
void free_device_list(void);
void init_topology_list(void);
void free_topology_list(void);
void free_stonith_remote_op_list(void);
void init_stonith_remote_op_hash_table(GHashTable **table);
void free_metadata_cache(void);
void fenced_unregister_handlers(void);
uint64_t get_stonith_flag(const char *name);
void stonith_command(pcmk__client_t *client, uint32_t id, uint32_t flags,
xmlNode *op_request, const char *remote_peer);
int stonith_device_register(xmlNode *msg, gboolean from_cib);
void stonith_device_remove(const char *id, bool from_cib);
char *stonith_level_key(const xmlNode *msg, int mode);
void fenced_register_level(xmlNode *msg, char **desc,
pcmk__action_result_t *result);
void fenced_unregister_level(xmlNode *msg, char **desc,
pcmk__action_result_t *result);
stonith_topology_t *find_topology_for_host(const char *host);
void do_local_reply(xmlNode *notify_src, pcmk__client_t *client,
int call_options);
xmlNode *fenced_construct_reply(const xmlNode *request, xmlNode *data,
const pcmk__action_result_t *result);
void
do_stonith_async_timeout_update(const char *client, const char *call_id, int timeout);
void fenced_send_notification(const char *type,
const pcmk__action_result_t *result,
xmlNode *data);
void fenced_send_device_notification(const char *op,
const pcmk__action_result_t *result,
const char *desc);
void fenced_send_level_notification(const char *op,
const pcmk__action_result_t *result,
const char *desc);
remote_fencing_op_t *initiate_remote_stonith_op(const pcmk__client_t *client,
xmlNode *request,
gboolean manual_ack);
void fenced_process_fencing_reply(xmlNode *msg);
int process_remote_stonith_query(xmlNode * msg);
void *create_remote_stonith_op(const char *client, xmlNode * request, gboolean peer);
void stonith_fence_history(xmlNode *msg, xmlNode **output,
const char *remote_peer, int options);
void stonith_fence_history_trim(void);
bool fencing_peer_active(crm_node_t *peer);
void set_fencing_completed(remote_fencing_op_t * op);
int fenced_handle_manual_confirmation(const pcmk__client_t *client,
xmlNode *msg);
+void fencer_metadata(void);
gboolean node_has_attr(const char *node, const char *name, const char *value);
gboolean node_does_watchdog_fencing(const char *node);
static inline void
fenced_set_protocol_error(pcmk__action_result_t *result)
{
pcmk__set_result(result, CRM_EX_PROTOCOL, PCMK_EXEC_INVALID,
"Fencer API request missing required information (bug?)");
}
extern char *stonith_our_uname;
extern gboolean stand_alone;
extern GHashTable *device_list;
extern GHashTable *topology;
extern long stonith_watchdog_timeout_ms;
extern GList *stonith_watchdog_targets;
extern GHashTable *stonith_remote_op_list;
diff --git a/po/zh_CN.po b/po/zh_CN.po
index a709950685..0c119037e7 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -1,289 +1,712 @@
#
# Copyright 2003-2022 the Pacemaker project contributors
#
# The version control history for this file may have further details.
#
# This source code is licensed under the GNU Lesser General Public License
# version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Pacemaker 2\n"
"Report-Msgid-Bugs-To: developers@clusterlabs.org\n"
-"POT-Creation-Date: 2022-02-11 13:46+0800\n"
+"POT-Creation-Date: 2022-09-13 22:43+0800\n"
"PO-Revision-Date: 2021-11-08 11:04+0800\n"
"Last-Translator: Vivi <developers@clusterlabs.org>\n"
"Language-Team: CHINESE <wangluwei@uniontech.org>\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: daemons/controld/controld_control.c:525
msgid "Pacemaker version on cluster node elected Designated Controller (DC)"
msgstr "集群选定的控制器节点(DC)的 Pacemaker 版本"
#: daemons/controld/controld_control.c:526
msgid ""
"Includes a hash which identifies the exact changeset the code was built "
"from. Used for diagnostic purposes."
msgstr "它包含一个标识所构建代码变更版本的哈希值,其可用于诊断。"
#: daemons/controld/controld_control.c:531
msgid "The messaging stack on which Pacemaker is currently running"
msgstr "Pacemaker 正在使用的消息传输引擎"
#: daemons/controld/controld_control.c:532
msgid "Used for informational and diagnostic purposes."
msgstr "用于提供信息和诊断。"
#: daemons/controld/controld_control.c:536
msgid "An arbitrary name for the cluster"
msgstr "任意的集群名称"
#: daemons/controld/controld_control.c:537
msgid ""
"This optional value is mostly for users' convenience as desired in "
"administration, but may also be used in Pacemaker configuration rules via "
"the #cluster-name node attribute, and by higher-level tools and resource "
"agents."
-msgstr "该可选值主要是为了方便用户管理使用,"
-"也可以在pacemaker 配置规则中通过 #cluster-name 节点属性配置使用,"
-"也可以通过高级工具和资源代理使用。"
+msgstr ""
+"该可选值主要是为了方便用户管理使用,也可以在pacemaker 配置规则中通过 "
+"#cluster-name 节点属性配置使用,也可以通过高级工具和资源代理使用。"
#: daemons/controld/controld_control.c:545
msgid "How long to wait for a response from other nodes during start-up"
msgstr "启动过程中等待其他节点响应的时间"
#: daemons/controld/controld_control.c:546
msgid ""
"The optimal value will depend on the speed and load of your network and the "
"type of switches used."
msgstr "其最佳值将取决于你的网络速度和负载以及所用交换机的类型。"
#: daemons/controld/controld_control.c:551
msgid ""
"Zero disables polling, while positive values are an interval in "
"seconds(unless other units are specified, for example \"5min\")"
msgstr ""
"设置为0将禁用轮询,设置为正数将是以秒为单位的时间间隔(除非使用了其他单位,比"
"如\"5min\"表示5分钟)"
#: daemons/controld/controld_control.c:554
msgid ""
"Polling interval to recheck cluster state and evaluate rules with date "
"specifications"
msgstr "重新检查集群状态并且评估具有日期规格的配置规则的轮询间隔"
+#: daemons/controld/controld_control.c:556
+msgid ""
+"Pacemaker is primarily event-driven, and looks ahead to know when to recheck "
+"cluster state for failure timeouts and most time-based rules. However, it "
+"will also recheck the cluster after this amount of inactivity, to evaluate "
+"rules with date specifications and serve as a fail-safe for certain types of "
+"scheduler bugs."
+msgstr ""
+"Pacemaker 主要是通过事件驱动的,并能预期重新检查集群状态以评估大多数基于时间"
+"的规则以及过期的错误。然而无论如何,在集群经过该时间间隔的不活动状态后,它还"
+"将重新检查集群,以评估具有日期规格的规则,并为某些类型的调度程序缺陷提供故障"
+"保护。"
+
#: daemons/controld/controld_control.c:565
msgid "Maximum amount of system load that should be used by cluster nodes"
msgstr "集群节点应该使用的最大系统负载量"
#: daemons/controld/controld_control.c:566
msgid ""
"The cluster will slow down its recovery process when the amount of system "
"resources used (currently CPU) approaches this limit"
msgstr "当使用的系统资源量(当前为CPU)接近此限制时,集群将减慢其恢复过程"
#: daemons/controld/controld_control.c:572
msgid ""
"Maximum number of jobs that can be scheduled per node (defaults to 2x cores)"
msgstr "每个节点可以调度的最大作业数(默认为2x内核数)"
#: daemons/controld/controld_control.c:576
msgid "How a cluster node should react if notified of its own fencing"
msgstr "集群节点在收到针对自己的 fence 操作结果通知时应如何反应"
#: daemons/controld/controld_control.c:577
msgid ""
"A cluster node may receive notification of its own fencing if fencing is "
"misconfigured, or if fabric fencing is in use that doesn't cut cluster "
"communication. Allowed values are \"stop\" to attempt to immediately stop "
"Pacemaker and stay stopped, or \"panic\" to attempt to immediately reboot "
"the local node, falling back to stop on failure."
-msgstr "如果有错误的 fence 配置,或者在使用 fabric fence 机制 (并不会切断集群通信),"
-"则集群节点可能会收到针对自己的 fence 结果通知。允许的值为 \"stop\" 尝试立即停止 pacemaker "
-"并保持停用状态,或者 \"panic\" 尝试立即重新启动本地节点,并在失败时返回执行stop。"
+msgstr ""
+"如果有错误的 fence 配置,或者在使用 fabric fence 机制 (并不会切断集群通信),"
+"则集群节点可能会收到针对自己的 fence 结果通知。允许的值为 \"stop\" 尝试立即停"
+"止 pacemaker 并保持停用状态,或者 \"panic\" 尝试立即重新启动本地节点,并在失败"
+"时返回执行stop。"
#: daemons/controld/controld_control.c:587
msgid ""
"Declare an election failed if it is not decided within this much time. If "
"you need to adjust this value, it probably indicates the presence of a bug."
msgstr ""
-"如果集群在本项设置时间内没有作出决定则宣布选举失败。如果您需要调整该值,这可能代表"
-"存在某些缺陷。"
+"如果集群在本项设置时间内没有作出决定则宣布选举失败。如果您需要调整该值,这可"
+"能代表存在某些缺陷。"
#: daemons/controld/controld_control.c:595
msgid ""
"Exit immediately if shutdown does not complete within this much time. If you "
"need to adjust this value, it probably indicates the presence of a bug."
-msgstr "如果在这段时间内关机仍未完成,则立即退出。如果您需要调整该值,这可能代表"
-"存在某些缺陷。"
+msgstr ""
+"如果在这段时间内关机仍未完成,则立即退出。如果您需要调整该值,这可能代表存在"
+"某些缺陷。"
#: daemons/controld/controld_control.c:603
#: daemons/controld/controld_control.c:610
msgid ""
"If you need to adjust this value, it probably indicates the presence of a "
"bug."
msgstr "如果您需要调整该值,这可能代表存在某些缺陷。"
#: daemons/controld/controld_control.c:616
msgid ""
"*** Advanced Use Only *** Enabling this option will slow down cluster "
"recovery under all conditions"
-msgstr ""
-"*** Advanced Use Only *** 启用此选项将在所有情况下减慢集群恢复的速度"
+msgstr "*** Advanced Use Only *** 启用此选项将在所有情况下减慢集群恢复的速度"
#: daemons/controld/controld_control.c:618
msgid ""
"Delay cluster recovery for this much time to allow for additional events to "
"occur. Useful if your configuration is sensitive to the order in which ping "
"updates arrive."
-msgstr "集群恢复将被推迟指定的时间间隔,以等待更多事件发生。"
-"如果您的配置对 ping 更新到达的顺序很敏感,这就很有用"
+msgstr ""
+"集群恢复将被推迟指定的时间间隔,以等待更多事件发生。如果您的配置对 ping 更新"
+"到达的顺序很敏感,这就很有用"
#: daemons/controld/controld_control.c:625
+#, fuzzy
msgid ""
-"How long to wait before we can assume nodes are safely down when watchdog-"
-"based self-fencing via SBD is in use"
-msgstr "当基于 watchdog 的自我 fence 机制通过SBD 被执行时,"
-"我们可以假设节点安全关闭之前需要等待多长时间"
+"How long before nodes can be assumed to be safely down when watchdog-based "
+"self-fencing via SBD is in use"
+msgstr ""
+"当基于 watchdog 的自我 fence 机制通过SBD 被执行时,我们可以假设节点安全关闭之"
+"前需要等待多长时间"
#: daemons/controld/controld_control.c:627
msgid ""
-"If nonzero, along with `have-watchdog=true` automatically set by the "
-"cluster, when fencing is required, watchdog-based self-fencing will be "
-"performed via SBD without requiring a fencing resource explicitly "
-"configured. If `stonith-watchdog-timeout` is set to a positive value, unseen "
-"nodes are assumed to self-fence within this much time. +WARNING:+ It must be "
-"ensured that this value is larger than the `SBD_WATCHDOG_TIMEOUT` "
-"environment variable on all nodes. Pacemaker verifies the settings "
-"individually on all nodes and prevents startup or shuts down if configured "
-"wrongly on the fly. It's strongly recommended that `SBD_WATCHDOG_TIMEOUT` is "
-"set to the same value on all nodes. If `stonith-watchdog-timeout` is set to "
-"a negative value, and `SBD_WATCHDOG_TIMEOUT` is set, twice that value will "
-"be used. +WARNING:+ In this case, it's essential (currently not verified by "
-"Pacemaker) that `SBD_WATCHDOG_TIMEOUT` is set to the same value on all nodes."
-msgstr ""
-"如果值非零,且集群设置了 `have-watchdog=true` ,当需要 fence 操作时,基于 watchdog 的自我 fence 机制将通过SBD执行,"
-"而不需要显式配置 fence 资源。如果 `stonith-watchdog-timeout` 被设为正值,则假定不可见的节点在这段时间内自我fence。"
-" +WARNING:+ 必须确保该值大于所有节点上的`SBD_WATCHDOG_TIMEOUT` 环境变量。Pacemaker将在所有节点上单独验证设置,"
-"如发现有错误的动态配置,将防止节点启动或关闭。强烈建议在所有节点上将 `SBD_WATCHDOG_TIMEOUT` 设置为相同的值。"
-"如果 `stonith-watchdog-timeout` 设置为负值。并且设置了 `SBD_WATCHDOG_TIMEOUT` ,则将使用该值的两倍,"
-" +WARNING:+ 在这种情况下,必须将所有节点上 `SBD_WATCHDOG_TIMEOUT` 设置为相同的值(目前没有通过pacemaker验证)。"
-
-#: daemons/controld/controld_control.c:648
+"If this is set to a positive value, lost nodes are assumed to self-fence "
+"using watchdog-based SBD within this much time. This does not require a "
+"fencing resource to be explicitly configured, though a fence_watchdog "
+"resource can be configured, to limit use to specific nodes. If this is set "
+"to 0 (the default), the cluster will never assume watchdog-based self-"
+"fencing. If this is set to a negative value, the cluster will use twice the "
+"local value of the `SBD_WATCHDOG_TIMEOUT` environment variable if that is "
+"positive, or otherwise treat this as 0. WARNING: When used, this timeout "
+"must be larger than `SBD_WATCHDOG_TIMEOUT` on all nodes that use watchdog-"
+"based SBD, and Pacemaker will refuse to start on any of those nodes where "
+"this is not true for the local value or SBD is not active. When this is set "
+"to a negative value, `SBD_WATCHDOG_TIMEOUT` must be set to the same value on "
+"all nodes that use SBD, otherwise data corruption or loss could occur."
+msgstr ""
+
+#: daemons/controld/controld_control.c:646
msgid ""
"How many times fencing can fail before it will no longer be immediately re-"
"attempted on a target"
msgstr "fence操作失败多少次会停止立即尝试"
-#: daemons/controld/controld_control.c:556
+#: daemons/fenced/pacemaker-fenced.c:1388
+#, fuzzy
+msgid "Advanced use only: An alternate parameter to supply instead of 'port'"
+msgstr ""
+" <shortdesc lang=\"zh\">Advanced use only:(仅限高级使用)备用参数可替"
+"代'port'</shortdesc>\n"
+
+#: daemons/fenced/pacemaker-fenced.c:1389
+#, fuzzy
msgid ""
-"Pacemaker is primarily event-driven, and looks ahead to know when to recheck "
-"cluster state for failure timeouts and most time-based rules. However, it "
-"will also recheck the cluster after this amount of inactivity, to evaluate "
-"rules with date specifications and serve as a fail-safe for certain types of "
-"scheduler bugs."
+"some devices do not support the standard 'port' parameter or may provide "
+"additional ones. Use this to specify an alternate, device-specific, "
+"parameter that should indicate the machine to be fenced. A value of none can "
+"be used to tell the cluster not to supply any additional parameters."
msgstr ""
-"Pacemaker 主要是通过事件驱动的,并能预期重新检查集群状态以评估大多数基于时间"
-"的规则以及过期的错误。然而无论如何,在集群经过该时间间隔的不活动状态后,它还"
-"将重新检查集群,以评估具有日期规格的规则,并为某些类型的调度程序缺陷提供故障保护。"
+" <longdesc lang=\"zh\">某些设备可能不支持使用标准的'port'(端口)参数,也可"
+"能会提供额外的端口参数。\n"
+"使用此参数可以为需要fence(防护)的机器指定一个备用的,专用于该设备的参数,该参"
+"数应指出要fence的机器。\n"
+"使用值'%s'可用来告诉集群不提供任何额外的参数\n"
+" </longdesc>\n"
-#: daemons/fenced/pacemaker-fenced.c:1464
-#, c-format
+#: daemons/fenced/pacemaker-fenced.c:1398
+#, fuzzy
msgid ""
-" <longdesc lang=\"en\">Instance attributes available for all \"stonith\"-"
-"class resources and used by Pacemaker's fence daemon, formerly known as "
-"stonithd</longdesc>\n"
+"A mapping of host names to ports numbers for devices that do not support "
+"host names."
msgstr ""
-" <longdesc lang=\"zh\">实例属性可用于所有stonith类资源,并由Pacemaker的fence"
-"守护程序使用(以前称为stonithd)</longdesc>\n"
+" <shortdesc lang=\"zh\">为不支持主机名的设备提供主机名和端口号的映射</"
+"shortdesc>\n"
-#: daemons/fenced/pacemaker-fenced.c:1469
-#, c-format
+#: daemons/fenced/pacemaker-fenced.c:1399
+#, fuzzy
+msgid ""
+"Eg. node1:1;node2:2,3 would tell the cluster to use port 1 for node1 and "
+"ports 2 and 3 for node2"
+msgstr ""
+" <longdesc lang=\"zh\">例如:pcmk_host_map=\"node:1;node2:2,3\"表示让集群"
+"的节点node1使用端口1,节点node2使用端口2和端口3。</longdesc>\n"
+
+#: daemons/fenced/pacemaker-fenced.c:1403
+msgid "Eg. node1,node2,node3"
+msgstr "例如. node1,node2,node3"
+
+#: daemons/fenced/pacemaker-fenced.c:1404
+msgid ""
+"A list of machines controlled by this device (Optional unless "
+"pcmk_host_list=static-list)"
+msgstr ""
+"该设备控制的机器列表(除非可选 pcmk_host_list =静态列表)"
+
+#: daemons/fenced/pacemaker-fenced.c:1409
+msgid "How to determine which machines are controlled by the device."
+msgstr "如何确定设备控制哪些机器。"
+
+#: daemons/fenced/pacemaker-fenced.c:1410
+msgid ""
+"Allowed values: dynamic-list (query the device via the 'list' command), "
+"static-list (check the pcmk_host_list attribute), status (query the device "
+"via the 'status' command), none (assume every device can fence every machine)"
+msgstr ""
+"允许的值:Dynamic-List(通过“列表”命令查询设备),"
+"静态列表(检查PCMK_HOST_LIST属性),状态(通过'status'命令查询设备),"
+"无(假设每个设备都可frnce 每个机器 )"
+
+#: daemons/fenced/pacemaker-fenced.c:1419
+#: daemons/fenced/pacemaker-fenced.c:1428
+msgid "Enable a base delay for fencing actions and specify base delay value."
+msgstr "启用fencing 操作的基本延迟并指定基本延迟值。"
+
+#: daemons/fenced/pacemaker-fenced.c:1420
+msgid ""
+"Enable a delay of no more than the time specified before executing fencing "
+"actions. Pacemaker derives the overall delay by taking the value of "
+"pcmk_delay_base and adding a random delay value such that the sum is kept "
+"below this maximum."
+msgstr ""
+"启用不超过执行fencing之前指定的时间的延迟。"
+" Pacemaker通过获取PCMK_DELAY_BASE的值并添加随机延迟值来得出总体延迟,"
+"从而使总和保持在此最大值以下。"
+
+#: daemons/fenced/pacemaker-fenced.c:1430
+msgid ""
+"This enables a static delay for fencing actions, which can help avoid "
+"\"death matches\" where two nodes try to fence each other at the same time. "
+"If pcmk_delay_max is also used, a random delay will be added such that the "
+"total delay is kept below that value.This can be set to a single time value "
+"to apply to any node targeted by this device (useful if a separate device is "
+"configured for each target), or to a node map (for example, \"node1:1s;"
+"node2:5\") to set a different value per target."
+msgstr ""
+"这使fencing 动作有静态延迟,这可以帮助避免"
+"\"death matches\"两个节点试图同时互相fence."
+"如果还使用了PCMK_DELAY_MAX,则将添加随机延迟,"
+"以使总延迟保持在该值以下。可以将其设置为单个时间值,"
+"以应用于该设备针对的任何节点(如果配置了单独的设备,则有用 对于每个目标)"
+"或到节点映射(例如,\" node1:1s; node2:5 \")以设置每个目标的不同值。"
+
+#: daemons/fenced/pacemaker-fenced.c:1442
+msgid ""
+"The maximum number of actions can be performed in parallel on this device"
+msgstr ""
+"最大行为数可以在此设备上并行执行"
+
+#: daemons/fenced/pacemaker-fenced.c:1443
+msgid ""
+"Cluster property concurrent-fencing=true needs to be configured first.Then "
+"use this to specify the maximum number of actions can be performed in "
+"parallel on this device. -1 is unlimited."
+msgstr ""
+"Cluster 属性 concurrent-fencing = true需要首先配置。然后使用它来指定可以在此设备上并行执行的最大动作数。 -1是无限的"
+
+#: daemons/fenced/pacemaker-fenced.c:1448
+#, fuzzy
+msgid "Advanced use only: An alternate command to run instead of 'reboot'"
+msgstr ""
+" <shortdesc lang=\"zh\">Advanced use only:(仅限高级使用)备用参数可替"
+"代'port'</shortdesc>\n"
+
+#: daemons/fenced/pacemaker-fenced.c:1449
+#, fuzzy
+msgid ""
+"Some devices do not support the standard commands or may provide additional "
+"ones.\n"
+"Use this to specify an alternate, device-specific, command that implements "
+"the 'reboot' action."
+msgstr ""
+" <longdesc lang=\"zh\">某些设备可能不支持使用标准的'port'(端口)参数,也可"
+"能会提供额外的端口参数。\n"
+"使用此参数可以为需要fence(防护)的机器指定一个备用的,专用于该设备的参数,该参"
+"数应指出要fence的机器。\n"
+"使用值'%s'可用来告诉集群不提供任何额外的参数\n"
+" </longdesc>\n"
+
+#: daemons/fenced/pacemaker-fenced.c:1454
+msgid ""
+"Advanced use only: Specify an alternate timeout to use for reboot actions "
+"instead of stonith-timeout"
+msgstr ""
+"仅高级使用:指定用于'reboot' 操作的替代超时,而不是stonith timeout"
+
+#: daemons/fenced/pacemaker-fenced.c:1455
+#, fuzzy
+msgid ""
+"Some devices need much more/less time to complete than normal.Use this to "
+"specify an alternate, device-specific, timeout for 'reboot' actions."
+msgstr ""
+" <longdesc lang=\"zh\">某些设备可能不支持使用标准的'port'(端口)参数,也可"
+"能会提供额外的端口参数。\n"
+"使用此参数可以为需要fence(防护)的机器指定一个备用的,专用于该设备的参数,该参"
+"数应指出要fence的机器。\n"
+"使用值'%s'可用来告诉集群不提供任何额外的参数\n"
+" </longdesc>\n"
+
+#: daemons/fenced/pacemaker-fenced.c:1460
+msgid ""
+"Advanced use only: The maximum number of times to retry the 'reboot' command "
+"within the timeout period"
+msgstr ""
+"仅高级使用:在超时期内重试'reboot'命令的最大次数"
+
+#: daemons/fenced/pacemaker-fenced.c:1461
+msgid ""
+"Some devices do not support multiple connections. Operations may 'fail' if "
+"the device is busy with another task so Pacemaker will automatically retry "
+"the operation, if there is time remaining. Use this option to alter the "
+"number of times Pacemaker retries 'reboot' actions before giving up."
+msgstr ""
+""一些设备不支持多个连接。 如果设备忙于另一个任务,则操作可能会 'fail' ,因此Pacemaker将自动重试(如果剩下时间)。 使用此选项更改Pacemaker在放弃之前进行'reboot' 操作的次数。
+
+#: daemons/fenced/pacemaker-fenced.c:1467
+#, fuzzy
+msgid "Advanced use only: An alternate command to run instead of 'off'"
+msgstr ""
+" <shortdesc lang=\"zh\">Advanced use only:(仅限高级使用)备用参数可替"
+"代'port'</shortdesc>\n"
+
+#: daemons/fenced/pacemaker-fenced.c:1468
+#, fuzzy
+msgid ""
+"Some devices do not support the standard commands or may provide additional "
+"ones.Use this to specify an alternate, device-specific, command that "
+"implements the 'off' action."
+msgstr ""
+" <longdesc lang=\"zh\">某些设备可能不支持使用标准的'port'(端口)参数,也可"
+"能会提供额外的端口参数。\n"
+"使用此参数可以为需要fence(防护)的机器指定一个备用的,专用于该设备的参数,该参"
+"数应指出要fence的机器。\n"
+"使用值'%s'可用来告诉集群不提供任何额外的参数\n"
+" </longdesc>\n"
+
+#: daemons/fenced/pacemaker-fenced.c:1473
+msgid ""
+"Advanced use only: Specify an alternate timeout to use for off actions "
+"instead of stonith-timeout"
+msgstr ""
+"仅高级使用:指定用于off 操作的替代超时,而不是stonith timeout"
+
+#: daemons/fenced/pacemaker-fenced.c:1474
+#, fuzzy
+msgid ""
+"Some devices need much more/less time to complete than normal.Use this to "
+"specify an alternate, device-specific, timeout for 'off' actions."
+msgstr ""
+" <longdesc lang=\"zh\">某些设备可能不支持使用标准的'port'(端口)参数,也可"
+"能会提供额外的端口参数。\n"
+"使用此参数可以为需要fence(防护)的机器指定一个备用的,专用于该设备的参数,该参"
+"数应指出要fence的机器。\n"
+"使用值'%s'可用来告诉集群不提供任何额外的参数\n"
+" </longdesc>\n"
+
+#: daemons/fenced/pacemaker-fenced.c:1479
+msgid ""
+"Advanced use only: The maximum number of times to retry the 'off' command "
+"within the timeout period"
+msgstr ""
+"仅高级使用:在超时期内重试'off'命令的最大次数"
+
+#: daemons/fenced/pacemaker-fenced.c:1480
+msgid ""
+"Some devices do not support multiple connections. Operations may 'fail' if "
+"the device is busy with another task so Pacemaker will automatically retry "
+"the operation, if there is time remaining. Use this option to alter the "
+"number of times Pacemaker retries 'off' actions before giving up."
+msgstr ""
+
+#: daemons/fenced/pacemaker-fenced.c:1486
+#, fuzzy
+msgid "Advanced use only: An alternate command to run instead of 'on'"
+msgstr ""
+" <shortdesc lang=\"zh\">Advanced use only:(仅限高级使用)备用参数可替"
+"代'port'</shortdesc>\n"
+
+#: daemons/fenced/pacemaker-fenced.c:1487
+#, fuzzy
msgid ""
-" <shortdesc lang=\"en\">Instance attributes available for all \"stonith\"-"
-"class resources</shortdesc>\n"
+"Some devices do not support the standard commands or may provide additional "
+"ones.Use this to specify an alternate, device-specific, command that "
+"implements the 'on' action."
msgstr ""
-" <shortdesc lang=\"zh\">可用于所有stonith类资源的实例属性</shortdesc>\n"
+" <longdesc lang=\"zh\">某些设备可能不支持使用标准的'port'(端口)参数,也可"
+"能会提供额外的端口参数。\n"
+"使用此参数可以为需要fence(防护)的机器指定一个备用的,专用于该设备的参数,该参"
+"数应指出要fence的机器。\n"
+"使用值'%s'可用来告诉集群不提供任何额外的参数\n"
+" </longdesc>\n"
#: daemons/fenced/pacemaker-fenced.c:1492
-#, fuzzy, c-format
msgid ""
-" <longdesc lang=\"en\">Some devices do not support the standard 'port' "
-"parameter or may provide additional ones. Use this to specify an alternate, "
-"device-specific, parameter that should indicate the machine to be fenced. A "
-"value of '%s' can be used to tell the cluster not to supply any additional "
-"parameters.\n"
-" </longdesc>\n"
+"Advanced use only: Specify an alternate timeout to use for on actions "
+"instead of stonith-timeout"
+msgstr ""
+"仅高级使用:指定用于on 操作的替代超时,而不是stonith timeout"
+
+#: daemons/fenced/pacemaker-fenced.c:1493
+#, fuzzy
+msgid ""
+"Some devices need much more/less time to complete than normal.Use this to "
+"specify an alternate, device-specific, timeout for 'on' actions."
msgstr ""
" <longdesc lang=\"zh\">某些设备可能不支持使用标准的'port'(端口)参数,也可"
"能会提供额外的端口参数。\n"
"使用此参数可以为需要fence(防护)的机器指定一个备用的,专用于该设备的参数,该参"
"数应指出要fence的机器。\n"
"使用值'%s'可用来告诉集群不提供任何额外的参数\n"
" </longdesc>\n"
-#: daemons/fenced/pacemaker-fenced.c:1504
-#, c-format
+#: daemons/fenced/pacemaker-fenced.c:1498
+msgid ""
+"Advanced use only: The maximum number of times to retry the 'on' command "
+"within the timeout period"
+msgstr ""
+"仅高级使用:在超时期内重试'on'命令的最大次数"
+
+#: daemons/fenced/pacemaker-fenced.c:1499
msgid ""
-" <shortdesc lang=\"en\">Advanced use only: An alternate parameter to "
-"supply instead of 'port'</shortdesc>\n"
+"Some devices do not support multiple connections. Operations may 'fail' if "
+"the device is busy with another task so Pacemaker will automatically retry "
+"the operation, if there is time remaining. Use this option to alter the "
+"number of times Pacemaker retries 'on' actions before giving up."
+msgstr ""
+
+#: daemons/fenced/pacemaker-fenced.c:1505
+#, fuzzy
+msgid "Advanced use only: An alternate command to run instead of 'list'"
msgstr ""
" <shortdesc lang=\"zh\">Advanced use only:(仅限高级使用)备用参数可替"
"代'port'</shortdesc>\n"
-#: daemons/fenced/pacemaker-fenced.c:1515
-#, c-format
+#: daemons/fenced/pacemaker-fenced.c:1506
+#, fuzzy
msgid ""
-" <longdesc lang=\"en\">Eg. node1:1;node2:2,3 would tell the cluster to "
-"use port 1 for node1 and ports 2 and 3 for node2</longdesc>\n"
+"Some devices do not support the standard commands or may provide additional "
+"ones.Use this to specify an alternate, device-specific, command that "
+"implements the 'list' action."
msgstr ""
-" <longdesc lang=\"zh\">例如:pcmk_host_map=\"node:1;node2:2,3\"表示让集群"
-"的节点node1使用端口1,节点node2使用端口2和端口3。</longdesc>\n"
+" <longdesc lang=\"zh\">某些设备可能不支持使用标准的'port'(端口)参数,也可"
+"能会提供额外的端口参数。\n"
+"使用此参数可以为需要fence(防护)的机器指定一个备用的,专用于该设备的参数,该参"
+"数应指出要fence的机器。\n"
+"使用值'%s'可用来告诉集群不提供任何额外的参数\n"
+" </longdesc>\n"
-#: daemons/fenced/pacemaker-fenced.c:1521
-#, c-format
+#: daemons/fenced/pacemaker-fenced.c:1511
msgid ""
-" <shortdesc lang=\"en\">A mapping of host names to ports numbers for "
-"devices that do not support host names.</shortdesc>\n"
+"Advanced use only: Specify an alternate timeout to use for list actions "
+"instead of stonith-timeout"
+msgstr ""
+"仅高级使用:指定用于list 操作的替代超时,而不是stonith timeout"
+
+#: daemons/fenced/pacemaker-fenced.c:1512
+#, fuzzy
+msgid ""
+"Some devices need much more/less time to complete than normal.Use this to "
+"specify an alternate, device-specific, timeout for 'list' actions."
+msgstr ""
+" <longdesc lang=\"zh\">某些设备可能不支持使用标准的'port'(端口)参数,也可"
+"能会提供额外的端口参数。\n"
+"使用此参数可以为需要fence(防护)的机器指定一个备用的,专用于该设备的参数,该参"
+"数应指出要fence的机器。\n"
+"使用值'%s'可用来告诉集群不提供任何额外的参数\n"
+" </longdesc>\n"
+
+#: daemons/fenced/pacemaker-fenced.c:1517
+msgid ""
+"Advanced use only: The maximum number of times to retry the 'list' command "
+"within the timeout period"
+msgstr ""
+"仅高级使用:在超时期内重试'list'命令的最大次数"
+
+#: daemons/fenced/pacemaker-fenced.c:1518
+msgid ""
+"Some devices do not support multiple connections. Operations may 'fail' if "
+"the device is busy with another task so Pacemaker will automatically retry "
+"the operation, if there is time remaining. Use this option to alter the "
+"number of times Pacemaker retries 'list' actions before giving up."
msgstr ""
-" <shortdesc lang=\"zh\">为不支持主机名的设备提供主机名和端口号的映射</"
-"shortdesc>\n"
-#: lib/cib/cib_utils.c:558
+#: daemons/fenced/pacemaker-fenced.c:1524
+#, fuzzy
+msgid "Advanced use only: An alternate command to run instead of 'monitor'"
+msgstr ""
+" <shortdesc lang=\"zh\">Advanced use only:(仅限高级使用)备用参数可替"
+"代'port'</shortdesc>\n"
+
+#: daemons/fenced/pacemaker-fenced.c:1525
+#, fuzzy
+msgid ""
+"Some devices do not support the standard commands or may provide additional "
+"ones.Use this to specify an alternate, device-specific, command that "
+"implements the 'monitor' action."
+msgstr ""
+" <longdesc lang=\"zh\">某些设备可能不支持使用标准的'port'(端口)参数,也可"
+"能会提供额外的端口参数。\n"
+"使用此参数可以为需要fence(防护)的机器指定一个备用的,专用于该设备的参数,该参"
+"数应指出要fence的机器。\n"
+"使用值'%s'可用来告诉集群不提供任何额外的参数\n"
+" </longdesc>\n"
+
+#: daemons/fenced/pacemaker-fenced.c:1530
+msgid ""
+"Advanced use only: Specify an alternate timeout to use for monitor actions "
+"instead of stonith-timeout"
+msgstr ""
+"仅高级使用:指定用于monitor 操作的替代超时,而不是stonith timeout"
+
+#: daemons/fenced/pacemaker-fenced.c:1531
+msgid ""
+"Some devices need much more/less time to complete than normal.\n"
+"Use this to specify an alternate, device-specific, timeout for 'monitor' "
+"actions."
+msgstr ""
+"仅高级使用:在超时期内重试'monitor'命令的最大次数"
+
+#: daemons/fenced/pacemaker-fenced.c:1536
+msgid ""
+"Advanced use only: The maximum number of times to retry the 'monitor' "
+"command within the timeout period"
+msgstr ""
+
+#: daemons/fenced/pacemaker-fenced.c:1537
+msgid ""
+"Some devices do not support multiple connections. Operations may 'fail' if "
+"the device is busy with another task so Pacemaker will automatically retry "
+"the operation, if there is time remaining. Use this option to alter the "
+"number of times Pacemaker retries 'monitor' actions before giving up."
+msgstr ""
+
+#: daemons/fenced/pacemaker-fenced.c:1543
+#, fuzzy
+msgid "Advanced use only: An alternate command to run instead of 'status'"
+msgstr ""
+" <shortdesc lang=\"zh\">Advanced use only:(仅限高级使用)备用参数可替"
+"代'port'</shortdesc>\n"
+
+#: daemons/fenced/pacemaker-fenced.c:1544
+#, fuzzy
+msgid ""
+"Some devices do not support the standard commands or may provide additional "
+"ones.Use this to specify an alternate, device-specific, command that "
+"implements the 'status' action."
+msgstr ""
+" <longdesc lang=\"zh\">某些设备可能不支持使用标准的'port'(端口)参数,也可"
+"能会提供额外的端口参数。\n"
+"使用此参数可以为需要fence(防护)的机器指定一个备用的,专用于该设备的参数,该参"
+"数应指出要fence的机器。\n"
+"使用值'%s'可用来告诉集群不提供任何额外的参数\n"
+" </longdesc>\n"
+
+#: daemons/fenced/pacemaker-fenced.c:1549
+msgid ""
+"Advanced use only: Specify an alternate timeout to use for status actions "
+"instead of stonith-timeout"
+msgstr ""
+"仅高级使用:指定用于status 操作的替代超时,而不是stonith timeout"
+
+#: daemons/fenced/pacemaker-fenced.c:1550
+#, fuzzy
+msgid ""
+"Some devices need much more/less time to complete than normal.Use this to "
+"specify an alternate, device-specific, timeout for 'status' actions."
+msgstr ""
+" <longdesc lang=\"zh\">某些设备可能不支持使用标准的'port'(端口)参数,也可"
+"能会提供额外的端口参数。\n"
+"使用此参数可以为需要fence(防护)的机器指定一个备用的,专用于该设备的参数,该参"
+"数应指出要fence的机器。\n"
+"使用值'%s'可用来告诉集群不提供任何额外的参数\n"
+" </longdesc>\n"
+
+#: daemons/fenced/pacemaker-fenced.c:1555
+msgid ""
+"Advanced use only: The maximum number of times to retry the 'status' command "
+"within the timeout period"
+msgstr ""
+"仅高级使用:在超时期内重试'status'命令的最大次数"
+
+#: daemons/fenced/pacemaker-fenced.c:1556
+msgid ""
+"Some devices do not support multiple connections. Operations may 'fail' if "
+"the device is busy with another task so Pacemaker will automatically retry "
+"the operation, if there is time remaining. Use this option to alter the "
+"number of times Pacemaker retries 'status' actions before giving up."
+msgstr ""
+
+#: lib/cib/cib_utils.c:559
msgid "Enable Access Control Lists (ACLs) for the CIB"
msgstr "为CIB启用访问控制列表(ACL)"
-#: lib/cib/cib_utils.c:564
+#: lib/cib/cib_utils.c:565
msgid "Maximum IPC message backlog before disconnecting a cluster daemon"
msgstr "断开集群守护程序之前的最大IPC消息积压"
-#: lib/cib/cib_utils.c:565
+#: lib/cib/cib_utils.c:566
msgid ""
"Raise this if log has \"Evicting client\" messages for cluster daemon PIDs "
"(a good value is the number of resources in the cluster multiplied by the "
"number of nodes)."
msgstr ""
"如果日志中有针对集群守护程序PID的消息“Evicting client”,(则建议将值设为集群"
"中的资源数量乘以节点数量)"
-#: lib/common/options.c:591
+#: lib/common/options.c:621
msgid " Allowed values: "
msgstr ""
#: lib/pengine/common.c:119
msgid "Whether watchdog integration is enabled"
msgstr "是否启用看门狗集成设置"
-#: tools/crm_resource.c:1405
+#: tools/crm_resource.c:1408
#, fuzzy, c-format
msgid "Metadata query for %s failed: %s"
msgstr ",查询%s的元数据失败: %s\n"
-#: tools/crm_resource.c:1411
+#: tools/crm_resource.c:1414
#, c-format
msgid "'%s' is not a valid agent specification"
msgstr "'%s' 是一个无效的代理"
+
+#~ msgid ""
+#~ "If nonzero, along with `have-watchdog=true` automatically set by the "
+#~ "cluster, when fencing is required, watchdog-based self-fencing will be "
+#~ "performed via SBD without requiring a fencing resource explicitly "
+#~ "configured. If `stonith-watchdog-timeout` is set to a positive value, "
+#~ "unseen nodes are assumed to self-fence within this much time. +WARNING:+ "
+#~ "It must be ensured that this value is larger than the "
+#~ "`SBD_WATCHDOG_TIMEOUT` environment variable on all nodes. Pacemaker "
+#~ "verifies the settings individually on all nodes and prevents startup or "
+#~ "shuts down if configured wrongly on the fly. It's strongly recommended "
+#~ "that `SBD_WATCHDOG_TIMEOUT` is set to the same value on all nodes. If "
+#~ "`stonith-watchdog-timeout` is set to a negative value, and "
+#~ "`SBD_WATCHDOG_TIMEOUT` is set, twice that value will be used. +WARNING:+ "
+#~ "In this case, it's essential (currently not verified by Pacemaker) that "
+#~ "`SBD_WATCHDOG_TIMEOUT` is set to the same value on all nodes."
+#~ msgstr ""
+#~ "如果值非零,且集群设置了 `have-watchdog=true` ,当需要 fence 操作时,基于 "
+#~ "watchdog 的自我 fence 机制将通过SBD执行,而不需要显式配置 fence 资源。如"
+#~ "果 `stonith-watchdog-timeout` 被设为正值,则假定不可见的节点在这段时间内自"
+#~ "我fence。 +WARNING:+ 必须确保该值大于所有节点上的`SBD_WATCHDOG_TIMEOUT` 环"
+#~ "境变量。Pacemaker将在所有节点上单独验证设置,如发现有错误的动态配置,将防"
+#~ "止节点启动或关闭。强烈建议在所有节点上将 `SBD_WATCHDOG_TIMEOUT` 设置为相同"
+#~ "的值。如果 `stonith-watchdog-timeout` 设置为负值。并且设置了 "
+#~ "`SBD_WATCHDOG_TIMEOUT` ,则将使用该值的两倍, +WARNING:+ 在这种情况下,必"
+#~ "须将所有节点上 `SBD_WATCHDOG_TIMEOUT` 设置为相同的值(目前没有通过pacemaker"
+#~ "验证)。"
+
+#~ msgid ""
+#~ " <longdesc lang=\"en\">Instance attributes available for all \"stonith\"-"
+#~ "class resources and used by Pacemaker's fence daemon, formerly known as "
+#~ "stonithd</longdesc>\n"
+#~ msgstr ""
+#~ " <longdesc lang=\"zh\">实例属性可用于所有stonith类资源,并由Pacemaker的"
+#~ "fence守护程序使用(以前称为stonithd)</longdesc>\n"
+
+#~ msgid ""
+#~ " <shortdesc lang=\"en\">Instance attributes available for all \"stonith\"-"
+#~ "class resources</shortdesc>\n"
+#~ msgstr ""
+#~ " <shortdesc lang=\"zh\">可用于所有stonith类资源的实例属性</shortdesc>\n"
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Jun 25, 6:28 AM (10 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1952441
Default Alt Text
(118 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment