pacemaker  1.1.24-3850484742
Scalable High-Availability cluster resource manager
common.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 #include <crm_internal.h>
19 #include <crm/crm.h>
20 #include <crm/msg_xml.h>
21 #include <crm/common/xml.h>
22 #include <crm/common/util.h>
23 
24 #include <glib.h>
25 
26 #include <crm/pengine/internal.h>
27 
28 gboolean was_processing_error = FALSE;
29 gboolean was_processing_warning = FALSE;
30 
31 static gboolean
32 check_health(const char *value)
33 {
34  if (safe_str_eq(value, "none")) {
35  return TRUE;
36 
37  } else if (safe_str_eq(value, "custom")) {
38  return TRUE;
39 
40  } else if (safe_str_eq(value, "only-green")) {
41  return TRUE;
42 
43  } else if (safe_str_eq(value, "progressive")) {
44  return TRUE;
45 
46  } else if (safe_str_eq(value, "migrate-on-red")) {
47  return TRUE;
48  }
49  return FALSE;
50 }
51 
52 static gboolean
53 check_stonith_action(const char *value)
54 {
55  if (safe_str_eq(value, "reboot")) {
56  return TRUE;
57 
58  } else if (safe_str_eq(value, "poweroff")) {
59  return TRUE;
60 
61  } else if (safe_str_eq(value, "off")) {
62  return TRUE;
63  }
64  return FALSE;
65 }
66 
67 static gboolean
68 check_placement_strategy(const char *value)
69 {
70  if (safe_str_eq(value, "default")) {
71  return TRUE;
72 
73  } else if (safe_str_eq(value, "utilization")) {
74  return TRUE;
75 
76  } else if (safe_str_eq(value, "minimal")) {
77  return TRUE;
78 
79  } else if (safe_str_eq(value, "balanced")) {
80  return TRUE;
81  }
82  return FALSE;
83 }
84 
85 /* *INDENT-OFF* */
87  /* name, old-name, validate, default, description */
88  { "no-quorum-policy", "no_quorum_policy", "enum", "stop, freeze, ignore, suicide", "stop", &check_quorum,
89  "What to do when the cluster does not have quorum", NULL },
90  { "symmetric-cluster", "symmetric_cluster", "boolean", NULL, "true", &check_boolean,
91  "All resources can run anywhere by default", NULL },
92  { "default-resource-stickiness", "default_resource_stickiness", "integer",
93  NULL, NULL, &check_number,
94  "Deprecated (use resource-stickiness in rsc_defaults instead)", NULL },
95  { "is-managed-default", "is_managed_default", "boolean", NULL, NULL,
96  &check_boolean, "Deprecated (use is-managed in rsc_defaults instead)",
97  NULL },
98  { "maintenance-mode", NULL, "boolean", NULL, "false", &check_boolean,
99  "Should the cluster monitor resources and start/stop them as required", NULL },
100  { "start-failure-is-fatal", NULL, "boolean", NULL, "true", &check_boolean, "Always treat start failures as fatal",
101  "When set to TRUE, the cluster will immediately ban a resource from a node if it fails to start there. When FALSE, the cluster will instead check the resource's fail count against its migration-threshold." },
102  { "enable-startup-probes", NULL, "boolean", NULL, "true", &check_boolean,
103  "Should the cluster check for active resources during startup", NULL },
104 
105  /* Stonith Options */
106  { "stonith-enabled", "stonith_enabled", "boolean", NULL, "true", &check_boolean,
107  "Failed nodes are STONITH'd", NULL },
108  { "stonith-action", "stonith_action", "enum", "reboot, off, poweroff", "reboot", &check_stonith_action,
109  "Action to send to STONITH device ('poweroff' is a deprecated alias for 'off')", NULL },
110  { "stonith-timeout", NULL, "time", NULL, "60s", &check_timer,
111  "How long to wait for the STONITH action (reboot,on,off) to complete", NULL },
112  { XML_ATTR_HAVE_WATCHDOG, NULL, "boolean", NULL, "false", &check_boolean,
113  "Enable watchdog integration", "Set automatically by the cluster if SBD is detected. User configured values are ignored." },
114  { "concurrent-fencing", NULL, "boolean", NULL,
115 #ifdef DEFAULT_CONCURRENT_FENCING_TRUE
116  "true",
117 #else
118  "false",
119 #endif
120  &check_boolean,
121  "Allow performing fencing operations in parallel", NULL },
122  { "startup-fencing", "startup_fencing", "boolean", NULL, "true", &check_boolean,
123  "STONITH unseen nodes", "Advanced Use Only! Not using the default is very unsafe!" },
124 #ifdef ENABLE_PRIORITY_FENCING_DELAY
125  {
126  XML_CONFIG_ATTR_PRIORITY_FENCING_DELAY, NULL, "time", NULL,
127  "0", &check_timer,
128  "Apply fencing delay targeting the lost nodes with the highest total resource priority",
129  "Apply specified delay for the fencings that are targeting the lost "
130  "nodes with the highest total resource priority in case we don't "
131  "have the majority of the nodes in our cluster partition, so that "
132  "the more significant nodes potentially win any fencing match, "
133  "which is especially meaningful under split-brain of 2-node "
134  "cluster. A promoted resource instance takes the base priority + 1 "
135  "on calculation if the base priority is not 0. Any static/random "
136  "delays that are introduced by `pcmk_delay_base/max` configured "
137  "for the corresponding fencing resources will be added to this "
138  "delay. This delay should be significantly greater than, safely "
139  "twice, the maximum `pcmk_delay_base/max`. By default, priority "
140  "fencing delay is disabled."
141  },
142 #endif
143 
144  /* Timeouts etc */
145  { "cluster-delay", "transition_idle_timeout", "time", NULL, "60s", &check_time,
146  "Round trip delay over the network (excluding action execution)",
147  "The \"correct\" value will depend on the speed and load of your network and cluster nodes." },
148  { "batch-limit", NULL, "integer", NULL, "0", &check_number,
149  "The number of jobs that the TE is allowed to execute in parallel",
150  "The \"correct\" value will depend on the speed and load of your network and cluster nodes." },
151  { "migration-limit", NULL, "integer", NULL, "-1", &check_number,
152  "The number of migration jobs that the TE is allowed to execute in parallel on a node"},
153  { "default-action-timeout", "default_action_timeout", "time", NULL, NULL,
154  &check_time, "Deprecated (use 'timeout' in op_defaults instead)", NULL },
155 
156  /* Orphans and stopping */
157  { "stop-all-resources", NULL, "boolean", NULL, "false", &check_boolean,
158  "Should the cluster stop all active resources (except those needed for fencing)", NULL },
159  { "stop-orphan-resources", "stop_orphan_resources", "boolean", NULL, "true", &check_boolean,
160  "Should deleted resources be stopped", NULL },
161  { "stop-orphan-actions", "stop_orphan_actions", "boolean", NULL, "true", &check_boolean,
162  "Should deleted actions be cancelled", NULL },
163  { "remove-after-stop", "remove_after_stop", "boolean", NULL, "false", &check_boolean,
164  "Remove resources from the LRM after they are stopped",
165  "Always set this to false. Other values are, at best, poorly tested and potentially dangerous." },
166 /* { "", "", , "0", "", NULL }, */
167 
168  /* Storing inputs */
169  { "pe-error-series-max", NULL, "integer", NULL, "-1", &check_number,
170  "The number of PE inputs resulting in ERRORs to save", "Zero to disable, -1 to store unlimited." },
171  { "pe-warn-series-max", NULL, "integer", NULL, "5000", &check_number,
172  "The number of PE inputs resulting in WARNINGs to save", "Zero to disable, -1 to store unlimited." },
173  { "pe-input-series-max", NULL, "integer", NULL, "4000", &check_number,
174  "The number of other PE inputs to save", "Zero to disable, -1 to store unlimited." },
175 
176  /* Node health */
177  { "node-health-strategy", NULL, "enum", "none, migrate-on-red, only-green, progressive, custom", "none", &check_health,
178  "The strategy combining node attributes to determine overall node health.",
179  "Requires external entities to create node attributes (named with the prefix '#health') with values: 'red', 'yellow' or 'green'."},
180  { "node-health-base", NULL, "integer", NULL, "0", &check_number,
181  "The base score assigned to a node",
182  "Only used when node-health-strategy is set to progressive." },
183  { "node-health-green", NULL, "integer", NULL, "0", &check_number,
184  "The score 'green' translates to in rsc_location constraints",
185  "Only used when node-health-strategy is set to custom or progressive." },
186  { "node-health-yellow", NULL, "integer", NULL, "0", &check_number,
187  "The score 'yellow' translates to in rsc_location constraints",
188  "Only used when node-health-strategy is set to custom or progressive." },
189  { "node-health-red", NULL, "integer", NULL, "-INFINITY", &check_number,
190  "The score 'red' translates to in rsc_location constraints",
191  "Only used when node-health-strategy is set to custom or progressive." },
192 
193  /*Placement Strategy*/
194  { "placement-strategy", NULL, "enum", "default, utilization, minimal, balanced", "default", &check_placement_strategy,
195  "The strategy to determine resource placement", NULL},
196 };
197 /* *INDENT-ON* */
198 
199 void
201 {
202  config_metadata("Policy Engine", "1.0",
203  "Policy Engine Options",
204  "This is a fake resource that details the options that can be configured for the Policy Engine.",
205  pe_opts, DIMOF(pe_opts));
206 }
207 
208 void
209 verify_pe_options(GHashTable * options)
210 {
211  verify_all_options(options, pe_opts, DIMOF(pe_opts));
212 }
213 
214 const char *
215 pe_pref(GHashTable * options, const char *name)
216 {
217  return get_cluster_pref(options, pe_opts, DIMOF(pe_opts), name);
218 }
219 
220 const char *
222 {
223  const char *result = "<unknown>";
224 
225  switch (fail) {
226  case action_fail_ignore:
227  result = "ignore";
228  break;
229  case action_fail_block:
230  result = "block";
231  break;
232  case action_fail_recover:
233  result = "recover";
234  break;
235  case action_fail_migrate:
236  result = "migrate";
237  break;
238  case action_fail_stop:
239  result = "stop";
240  break;
241  case action_fail_fence:
242  result = "fence";
243  break;
244  case action_fail_standby:
245  result = "standby";
246  break;
248  result = "restart-container";
249  break;
251  result = "reset-remote";
252  break;
253  }
254  return result;
255 }
256 
257 enum action_tasks
258 text2task(const char *task)
259 {
260  if (safe_str_eq(task, CRMD_ACTION_STOP)) {
261  return stop_rsc;
262  } else if (safe_str_eq(task, CRMD_ACTION_STOPPED)) {
263  return stopped_rsc;
264  } else if (safe_str_eq(task, CRMD_ACTION_START)) {
265  return start_rsc;
266  } else if (safe_str_eq(task, CRMD_ACTION_STARTED)) {
267  return started_rsc;
268  } else if (safe_str_eq(task, CRM_OP_SHUTDOWN)) {
269  return shutdown_crm;
270  } else if (safe_str_eq(task, CRM_OP_FENCE)) {
271  return stonith_node;
272  } else if (safe_str_eq(task, CRMD_ACTION_STATUS)) {
273  return monitor_rsc;
274  } else if (safe_str_eq(task, CRMD_ACTION_NOTIFY)) {
275  return action_notify;
276  } else if (safe_str_eq(task, CRMD_ACTION_NOTIFIED)) {
277  return action_notified;
278  } else if (safe_str_eq(task, CRMD_ACTION_PROMOTE)) {
279  return action_promote;
280  } else if (safe_str_eq(task, CRMD_ACTION_DEMOTE)) {
281  return action_demote;
282  } else if (safe_str_eq(task, CRMD_ACTION_PROMOTED)) {
283  return action_promoted;
284  } else if (safe_str_eq(task, CRMD_ACTION_DEMOTED)) {
285  return action_demoted;
286  }
287 #if SUPPORT_TRACING
288  if (safe_str_eq(task, CRMD_ACTION_CANCEL)) {
289  return no_action;
290  } else if (safe_str_eq(task, CRMD_ACTION_DELETE)) {
291  return no_action;
292  } else if (safe_str_eq(task, CRMD_ACTION_STATUS)) {
293  return no_action;
294  } else if (safe_str_eq(task, CRM_OP_PROBED)) {
295  return no_action;
296  } else if (safe_str_eq(task, CRM_OP_LRM_REFRESH)) {
297  return no_action;
298  } else if (safe_str_eq(task, CRMD_ACTION_MIGRATE)) {
299  return no_action;
300  } else if (safe_str_eq(task, CRMD_ACTION_MIGRATED)) {
301  return no_action;
302  } else if (safe_str_eq(task, "fail")) {
303  return no_action;
304  }
305  crm_trace("Unsupported action: %s", task);
306 #endif
307 
308  return no_action;
309 }
310 
311 const char *
313 {
314  const char *result = "<unknown>";
315 
316  switch (task) {
317  case no_action:
318  result = "no_action";
319  break;
320  case stop_rsc:
321  result = CRMD_ACTION_STOP;
322  break;
323  case stopped_rsc:
324  result = CRMD_ACTION_STOPPED;
325  break;
326  case start_rsc:
327  result = CRMD_ACTION_START;
328  break;
329  case started_rsc:
330  result = CRMD_ACTION_STARTED;
331  break;
332  case shutdown_crm:
333  result = CRM_OP_SHUTDOWN;
334  break;
335  case stonith_node:
336  result = CRM_OP_FENCE;
337  break;
338  case monitor_rsc:
339  result = CRMD_ACTION_STATUS;
340  break;
341  case action_notify:
342  result = CRMD_ACTION_NOTIFY;
343  break;
344  case action_notified:
345  result = CRMD_ACTION_NOTIFIED;
346  break;
347  case action_promote:
348  result = CRMD_ACTION_PROMOTE;
349  break;
350  case action_promoted:
351  result = CRMD_ACTION_PROMOTED;
352  break;
353  case action_demote:
354  result = CRMD_ACTION_DEMOTE;
355  break;
356  case action_demoted:
357  result = CRMD_ACTION_DEMOTED;
358  break;
359  }
360 
361  return result;
362 }
363 
364 const char *
366 {
367  switch (role) {
368  case RSC_ROLE_UNKNOWN:
369  return RSC_ROLE_UNKNOWN_S;
370  case RSC_ROLE_STOPPED:
371  return RSC_ROLE_STOPPED_S;
372  case RSC_ROLE_STARTED:
373  return RSC_ROLE_STARTED_S;
374  case RSC_ROLE_SLAVE:
375  return RSC_ROLE_SLAVE_S;
376  case RSC_ROLE_MASTER:
377  return RSC_ROLE_MASTER_S;
378  }
380  CRM_CHECK(role < RSC_ROLE_MAX, return RSC_ROLE_UNKNOWN_S);
381  // coverity[dead_error_line]
382  return RSC_ROLE_UNKNOWN_S;
383 }
384 
385 enum rsc_role_e
386 text2role(const char *role)
387 {
388  CRM_ASSERT(role != NULL);
389  if (safe_str_eq(role, RSC_ROLE_STOPPED_S)) {
390  return RSC_ROLE_STOPPED;
391  } else if (safe_str_eq(role, RSC_ROLE_STARTED_S)) {
392  return RSC_ROLE_STARTED;
393  } else if (safe_str_eq(role, RSC_ROLE_SLAVE_S)) {
394  return RSC_ROLE_SLAVE;
395  } else if (safe_str_eq(role, RSC_ROLE_MASTER_S)) {
396  return RSC_ROLE_MASTER;
397  } else if (safe_str_eq(role, RSC_ROLE_UNKNOWN_S)) {
398  return RSC_ROLE_UNKNOWN;
399  }
400  crm_err("Unknown role: %s", role);
401  return RSC_ROLE_UNKNOWN;
402 }
403 
404 int
405 merge_weights(int w1, int w2)
406 {
407  int result = w1 + w2;
408 
409  if (w1 <= -INFINITY || w2 <= -INFINITY) {
410  if (w1 >= INFINITY || w2 >= INFINITY) {
411  crm_trace("-INFINITY + INFINITY == -INFINITY");
412  }
413  return -INFINITY;
414 
415  } else if (w1 >= INFINITY || w2 >= INFINITY) {
416  return INFINITY;
417  }
418 
419  /* detect wrap-around */
420  if (result > 0) {
421  if (w1 <= 0 && w2 < 0) {
422  result = -INFINITY;
423  }
424 
425  } else if (w1 > 0 && w2 > 0) {
426  result = INFINITY;
427  }
428 
429  /* detect +/- INFINITY */
430  if (result >= INFINITY) {
431  result = INFINITY;
432 
433  } else if (result <= -INFINITY) {
434  result = -INFINITY;
435  }
436 
437  crm_trace("%d + %d = %d", w1, w2, result);
438  return result;
439 }
440 
441 void
442 add_hash_param(GHashTable * hash, const char *name, const char *value)
443 {
444  CRM_CHECK(hash != NULL, return);
445 
446  crm_trace("adding: name=%s value=%s", crm_str(name), crm_str(value));
447  if (name == NULL || value == NULL) {
448  return;
449 
450  } else if (safe_str_eq(value, "#default")) {
451  return;
452 
453  } else if (g_hash_table_lookup(hash, name) == NULL) {
454  g_hash_table_insert(hash, strdup(name), strdup(value));
455  }
456 }
457 
458 const char *
459 pe_node_attribute_calculated(pe_node_t *node, const char *name, resource_t *rsc)
460 {
461  const char *source;
462 
463  if(node == NULL) {
464  return NULL;
465 
466  } else if(rsc == NULL) {
467  return g_hash_table_lookup(node->details->attrs, name);
468  }
469 
470  source = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET);
471  if(source == NULL || safe_str_eq("host", source) == FALSE) {
472  return g_hash_table_lookup(node->details->attrs, name);
473  }
474 
475  /* Use attributes set for the containers location
476  * instead of for the container itself
477  *
478  * Useful when the container is using the host's local
479  * storage
480  */
481 
482  CRM_ASSERT(node->details->remote_rsc);
484 
485  if(node->details->remote_rsc->container->running_on) {
487  pe_rsc_trace(rsc, "%s: Looking for %s on the container host %s", rsc->id, name, host->details->uname);
488  return g_hash_table_lookup(host->details->attrs, name);
489  }
490 
491  pe_rsc_trace(rsc, "%s: Not looking for %s on the container host: %s is inactive",
492  rsc->id, name, node->details->remote_rsc->container->id);
493  return NULL;
494 }
495 
496 const char *
497 pe_node_attribute_raw(pe_node_t *node, const char *name)
498 {
499  if(node == NULL) {
500  return NULL;
501  }
502  return g_hash_table_lookup(node->details->attrs, name);
503 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:190
const char * uname
Definition: status.h:173
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:442
A dumping ground.
#define CRMD_ACTION_MIGRATED
Definition: crm.h:165
#define INFINITY
Definition: crm.h:73
int merge_weights(int w1, int w2)
Definition: common.c:405
#define CRM_OP_FENCE
Definition: crm.h:119
void pe_metadata(void)
Definition: common.c:200
#define XML_CONFIG_ATTR_PRIORITY_FENCING_DELAY
Definition: msg_xml.h:381
#define RSC_ROLE_STARTED_S
Definition: common.h:93
#define CRMD_ACTION_NOTIFY
Definition: crm.h:178
const char * pe_node_attribute_raw(pe_node_t *node, const char *name)
Definition: common.c:497
#define CRMD_ACTION_PROMOTE
Definition: crm.h:173
const char * pe_node_attribute_calculated(pe_node_t *node, const char *name, resource_t *rsc)
Definition: common.c:459
AIS_Host host
Definition: internal.h:80
const char * task2text(enum action_tasks task)
Definition: common.c:312
resource_t * remote_rsc
Definition: status.h:190
gboolean check_number(const char *value)
Definition: utils.c:131
#define XML_RSC_ATTR_TARGET
Definition: msg_xml.h:204
action_fail_response
Definition: common.h:29
gboolean was_processing_error
Definition: common.c:28
gboolean was_processing_warning
Definition: common.c:29
char * id
Definition: status.h:292
#define CRMD_ACTION_START
Definition: crm.h:167
enum rsc_role_e text2role(const char *role)
Definition: common.c:386
#define CRM_OP_LRM_REFRESH
Definition: crm.h:123
#define CRMD_ACTION_DEMOTED
Definition: crm.h:176
#define CRMD_ACTION_STOP
Definition: crm.h:170
struct node_shared_s * details
Definition: status.h:213
void config_metadata(const char *name, const char *version, const char *desc_short, const char *desc_long, pe_cluster_option *option_list, int len)
Definition: utils.c:366
#define CRMD_ACTION_DEMOTE
Definition: crm.h:175
const char * role2text(enum rsc_role_e role)
Definition: common.c:365
Utility functions.
resource_t * container
Definition: status.h:343
gboolean check_quorum(const char *value)
Definition: utils.c:161
#define crm_trace(fmt, args...)
Definition: logging.h:280
Wrappers for and extensions to libxml2.
gboolean check_time(const char *value)
Definition: utils.c:102
#define RSC_ROLE_MASTER_S
Definition: common.h:95
#define CRMD_ACTION_PROMOTED
Definition: crm.h:174
gboolean check_boolean(const char *value)
Definition: utils.c:120
void verify_pe_options(GHashTable *options)
Definition: common.c:209
#define CRM_OP_SHUTDOWN
Definition: crm.h:118
const char * pe_pref(GHashTable *options, const char *name)
Definition: common.c:215
#define CRMD_ACTION_STOPPED
Definition: crm.h:171
GHashTable * meta
Definition: status.h:333
#define crm_err(fmt, args...)
Definition: logging.h:274
GHashTable * attrs
Definition: status.h:192
#define XML_ATTR_HAVE_WATCHDOG
Definition: msg_xml.h:91
#define RSC_ROLE_SLAVE_S
Definition: common.h:94
#define DIMOF(a)
Definition: crm.h:29
#define CRMD_ACTION_MIGRATE
Definition: crm.h:164
#define RSC_ROLE_STOPPED_S
Definition: common.h:92
#define CRM_ASSERT(expr)
Definition: error.h:20
#define crm_str(x)
Definition: logging.h:300
void verify_all_options(GHashTable *options, pe_cluster_option *option_list, int len)
Definition: utils.c:401
rsc_role_e
Definition: common.h:81
#define CRM_OP_PROBED
Definition: crm.h:127
enum action_tasks text2task(const char *task)
Definition: common.c:258
#define RSC_ROLE_UNKNOWN_S
Definition: common.h:91
Definition: status.h:209
#define RSC_ROLE_MAX
Definition: common.h:89
gboolean check_timer(const char *value)
Definition: utils.c:111
#define CRMD_ACTION_NOTIFIED
Definition: crm.h:179
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:16
#define safe_str_eq(a, b)
Definition: util.h:74
pe_cluster_option pe_opts[]
Definition: common.c:86
const char * get_cluster_pref(GHashTable *options, pe_cluster_option *option_list, int len, const char *name)
Definition: utils.c:347
const char * fail2text(enum action_fail_response fail)
Definition: common.c:221
#define CRMD_ACTION_STARTED
Definition: crm.h:168
#define CRMD_ACTION_CANCEL
Definition: crm.h:161
action_tasks
Definition: common.h:52
#define CRMD_ACTION_DELETE
Definition: crm.h:160
#define CRMD_ACTION_STATUS
Definition: crm.h:181
GListPtr running_on
Definition: status.h:326