14#include <libxml/xpath.h>
22is_matched_failure(
const char *rsc_id,
const xmlNode *conf_op_xml,
23 const xmlNode *lrm_op_xml)
25 gboolean matched = FALSE;
26 const char *conf_op_name = NULL;
27 const char *lrm_op_task = NULL;
28 const char *conf_op_interval_spec = NULL;
29 guint conf_op_interval_ms = 0;
30 guint lrm_op_interval_ms = 0;
31 const char *lrm_op_id = NULL;
32 char *last_failure_key = NULL;
34 if (rsc_id == NULL || conf_op_xml == NULL || lrm_op_xml == NULL) {
47 if ((conf_op_interval_ms != lrm_op_interval_ms)
52 lrm_op_id = pcmk__xe_id(lrm_op_xml);
53 last_failure_key =
pcmk__op_key(rsc_id,
"last_failure", 0);
59 char *expected_op_key =
pcmk__op_key(rsc_id, conf_op_name,
67 if (rc != target_rc) {
71 free(expected_op_key);
74 free(last_failure_key);
80 const xmlNode *xml_op)
102 gboolean should_block = FALSE;
107 int max = pcmk__xpath_num_results(xpathObj);
110 for (lpc = 0; lpc < max; lpc++) {
114 should_block = is_matched_failure(xml_name, pref, xml_op);
120 const char *conf_op_name = NULL;
121 const char *conf_op_interval_spec = NULL;
122 guint conf_op_interval_ms = 0;
124 char *lrm_op_xpath = NULL;
125 xmlXPathObject *lrm_op_xpathObj = NULL;
132 &conf_op_interval_ms);
134#define XPATH_FMT "//" PCMK__XE_NODE_STATE "[@" PCMK_XA_UNAME "='%s']" \
135 "//" PCMK__XE_LRM_RESOURCE "[@" PCMK_XA_ID "='%s']" \
136 "/" PCMK__XE_LRM_RSC_OP "[@" PCMK_XA_OPERATION "='%s']" \
137 "[@" PCMK_META_INTERVAL "='%u']"
142 conf_op_interval_ms);
148 if (lrm_op_xpathObj) {
149 int max2 = pcmk__xpath_num_results(lrm_op_xpathObj);
152 for (lpc2 = 0; lpc2 < max2; lpc2++) {
153 xmlNode *lrm_op_xml = NULL;
156 should_block = is_matched_failure(xml_name, pref,
163 xmlXPathFreeObject(lrm_op_xpathObj);
173 xmlXPathFreeObject(xpathObj);
209generate_fail_regex(
const char *prefix,
const char *rsc_name,
bool is_unique,
212 char *pattern = NULL;
213 const char *op_pattern =
"#.+_[0-9]+";
219 const char *instance_pattern = (is_unique?
"" :
"(:[0-9]+)?");
222 instance_pattern, op_pattern);
223 if (regcomp(re, pattern, REG_EXTENDED|REG_NOSUB) != 0) {
245generate_fail_regexes(
const pcmk_resource_t *rsc, regex_t *failcount_re,
246 regex_t *lastfailure_re)
249 char *rsc_name = rsc_fail_name(rsc);
260 regfree(failcount_re);
268struct failcount_data {
272 const xmlNode *xml_op;
273 regex_t failcount_re;
274 regex_t lastfailure_re;
288update_failcount_for_attr(gpointer key, gpointer value, gpointer user_data)
290 struct failcount_data *fc_data = user_data;
293 if (regexec(&(fc_data->failcount_re), (
const char *) key, 0, NULL, 0) == 0) {
299 "because '%s' is not a valid fail count: %s",
300 (
const char *) key, pcmk__node_name(fc_data->node),
305 pcmk__rsc_trace(fc_data->rsc,
"Added %s (%s) to %s fail count (now %s)",
306 (
const char *) key, (
const char *) value,
313 if (regexec(&(fc_data->lastfailure_re), (
const char *) key, 0, NULL,
319 crm_info(
"Ignoring invalid value '%s' for %s: %s",
320 (
const char *) value, (
const char *) key,
pcmk_rc_str(rc));
323 fc_data->last_failure = (time_t) QB_MAX(fc_data->last_failure, last_ll);
335update_launched_failcount(gpointer
data, gpointer user_data)
338 struct failcount_data *fc_data = user_data;
339 time_t launched_last_failure = 0;
342 &launched_last_failure,
343 fc_data->flags, fc_data->xml_op);
344 fc_data->last_failure = QB_MAX(fc_data->last_failure, launched_last_failure);
347#define readable_expiration(rsc) \
348 pcmk__readable_interval((rsc)->priv->failure_expiration_ms)
368 time_t *last_failure, uint32_t
flags,
const xmlNode *xml_op)
370 struct failcount_data fc_data = {
376 .last_failure = (time_t) 0,
380 CRM_CHECK(generate_fail_regexes(rsc, &fc_data.failcount_re,
383 g_hash_table_foreach(node->
priv->
attrs, update_failcount_for_attr,
385 regfree(&(fc_data.failcount_re));
386 regfree(&(fc_data.lastfailure_re));
390 && block_failure(node, rsc, xml_op)) {
393 "because it conflicts with "
401 && (fc_data.last_failure > 0)
407 if (now > (fc_data.last_failure + expiration)) {
409 rsc->
id, pcmk__node_name(node),
411 fc_data.failcount = 0;
426 && (rsc->
priv->
launched != NULL) && !pcmk__is_bundled(rsc)) {
428 g_list_foreach(rsc->
priv->
launched, update_launched_failcount,
430 if (fc_data.failcount > 0) {
432 "Container %s and the resources within it "
433 "have failed %s time%s on %s",
436 pcmk__node_name(node));
439 }
else if (fc_data.failcount > 0) {
443 pcmk__node_name(node));
446 if (last_failure != NULL) {
447 if ((fc_data.failcount > 0) && (fc_data.last_failure > 0)) {
448 *last_failure = fc_data.last_failure;
453 return fc_data.failcount;
479 crm_notice(
"Clearing failure of %s on %s because %s " QB_XS
" %s",
480 rsc->
id, pcmk__node_name(node), reason, clear->
uuid);
#define PCMK_ACTION_CLEAR_FAILCOUNT
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
guint pcmk__timeout_ms2s(guint timeout_ms)
#define PCMK__LAST_FAILURE_PREFIX
#define PCMK__FAIL_COUNT_PREFIX
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
pcmk_action_t * pe__clear_failcount(pcmk_resource_t *rsc, const pcmk_node_t *node, const char *reason, pcmk_scheduler_t *scheduler)
Schedule a controller operation to clear a fail count.
#define readable_expiration(rsc)
int pe_get_failcount(const pcmk_node_t *node, pcmk_resource_t *rsc, time_t *last_failure, uint32_t flags, const xmlNode *xml_op)
#define crm_info(fmt, args...)
#define crm_warn(fmt, args...)
#define crm_notice(fmt, args...)
#define CRM_CHECK(expr, failure_action)
#define pcmk__config_warn(fmt...)
pcmk_scheduler_t * scheduler
#define pcmk__insert_meta(obj, name, value)
#define PCMK_META_INTERVAL
#define PCMK_META_ON_FAIL
#define PCMK__META_OP_NO_WAIT
pcmk_action_t * custom_action(pcmk_resource_t *rsc, char *key, const char *task, const pcmk_node_t *on_node, gboolean optional, pcmk_scheduler_t *scheduler)
Create or update an action object.
char * clone_strip(const char *last_rsc_id)
int pe__target_rc_from_xml(const xmlNode *xml_op)
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
#define pcmk__rsc_info(rsc, fmt, args...)
#define pcmk__rsc_trace(rsc, fmt, args...)
time_t pcmk__scheduler_epoch_time(pcmk_scheduler_t *scheduler)
#define pcmk__rsc_debug(rsc, fmt, args...)
int pcmk_parse_score(const char *score_s, int *score, int default_score)
Parse an integer score from a string.
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
int pcmk__add_scores(int score1, int score2)
int pcmk_parse_interval_spec(const char *input, guint *result_ms)
Parse milliseconds from a Pacemaker interval specification.
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk__plural_s(i)
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
guint failure_expiration_ms
pcmk_scheduler_t * scheduler
pcmk__resource_private_t * priv
pcmk__node_private_t * priv
Wrappers for and extensions to libxml2.
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
#define PCMK_XA_OPERATION
#define PCMK_XE_PRIMITIVE
xmlXPathObject * pcmk__xpath_search(xmlDoc *doc, const char *path)
xmlNode * pcmk__xpath_result(xmlXPathObject *xpath_obj, int index)