pacemaker  2.0.2-debe490
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pcmk_sched_utils.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2019 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This source code is licensed under the GNU General Public License version 2
5  * or later (GPLv2+) WITHOUT ANY WARRANTY.
6  */
7 
8 #include <crm_internal.h>
9 #include <crm/msg_xml.h>
10 #include <pacemaker-internal.h>
11 
13 rsc2node_new(const char *id, pe_resource_t *rsc,
14  int node_weight, const char *discover_mode,
15  pe_node_t *foo_node, pe_working_set_t *data_set)
16 {
17  pe__location_t *new_con = NULL;
18 
19  if (rsc == NULL || id == NULL) {
20  pe_err("Invalid constraint %s for rsc=%p", crm_str(id), rsc);
21  return NULL;
22 
23  } else if (foo_node == NULL) {
24  CRM_CHECK(node_weight == 0, return NULL);
25  }
26 
27  new_con = calloc(1, sizeof(pe__location_t));
28  if (new_con != NULL) {
29  new_con->id = strdup(id);
30  new_con->rsc_lh = rsc;
31  new_con->node_list_rh = NULL;
32  new_con->role_filter = RSC_ROLE_UNKNOWN;
33 
34 
35  if (discover_mode == NULL || safe_str_eq(discover_mode, "always")) {
37  } else if (safe_str_eq(discover_mode, "never")) {
39  } else if (safe_str_eq(discover_mode, "exclusive")) {
41  rsc->exclusive_discover = TRUE;
42  } else {
43  pe_err("Invalid %s value %s in location constraint", XML_LOCATION_ATTR_DISCOVERY, discover_mode);
44  }
45 
46  if (foo_node != NULL) {
47  node_t *copy = node_copy(foo_node);
48 
49  copy->weight = node_weight;
50  new_con->node_list_rh = g_list_prepend(NULL, copy);
51  }
52 
53  data_set->placement_constraints = g_list_prepend(data_set->placement_constraints, new_con);
54  rsc->rsc_location = g_list_prepend(rsc->rsc_location, new_con);
55  }
56 
57  return new_con;
58 }
59 
60 gboolean
62 {
63  if (node == NULL) {
64  return FALSE;
65  }
66 #if 0
67  if (node->weight < 0) {
68  return FALSE;
69  }
70 #endif
71 
72  if (node->details->online == FALSE
73  || node->details->shutdown || node->details->unclean
74  || node->details->standby || node->details->maintenance) {
75  crm_trace("%s: online=%d, unclean=%d, standby=%d, maintenance=%d",
76  node->details->uname, node->details->online,
77  node->details->unclean, node->details->standby, node->details->maintenance);
78  return FALSE;
79  }
80  return TRUE;
81 }
82 
83 struct node_weight_s {
84  pe_node_t *active;
85  pe_working_set_t *data_set;
86 };
87 
88 /* return -1 if 'a' is more preferred
89  * return 1 if 'b' is more preferred
90  */
91 
92 static gint
93 sort_node_weight(gconstpointer a, gconstpointer b, gpointer data)
94 {
95  const node_t *node1 = (const node_t *)a;
96  const node_t *node2 = (const node_t *)b;
97  struct node_weight_s *nw = data;
98 
99  int node1_weight = 0;
100  int node2_weight = 0;
101 
102  int result = 0;
103 
104  if (a == NULL) {
105  return 1;
106  }
107  if (b == NULL) {
108  return -1;
109  }
110 
111  node1_weight = node1->weight;
112  node2_weight = node2->weight;
113 
114  if (can_run_resources(node1) == FALSE) {
115  node1_weight = -INFINITY;
116  }
117  if (can_run_resources(node2) == FALSE) {
118  node2_weight = -INFINITY;
119  }
120 
121  if (node1_weight > node2_weight) {
122  crm_trace("%s (%d) > %s (%d) : weight",
123  node1->details->uname, node1_weight, node2->details->uname, node2_weight);
124  return -1;
125  }
126 
127  if (node1_weight < node2_weight) {
128  crm_trace("%s (%d) < %s (%d) : weight",
129  node1->details->uname, node1_weight, node2->details->uname, node2_weight);
130  return 1;
131  }
132 
133  crm_trace("%s (%d) == %s (%d) : weight",
134  node1->details->uname, node1_weight, node2->details->uname, node2_weight);
135 
136  if (safe_str_eq(nw->data_set->placement_strategy, "minimal")) {
137  goto equal;
138  }
139 
140  if (safe_str_eq(nw->data_set->placement_strategy, "balanced")) {
141  result = compare_capacity(node1, node2);
142  if (result < 0) {
143  crm_trace("%s > %s : capacity (%d)",
144  node1->details->uname, node2->details->uname, result);
145  return -1;
146  } else if (result > 0) {
147  crm_trace("%s < %s : capacity (%d)",
148  node1->details->uname, node2->details->uname, result);
149  return 1;
150  }
151  }
152 
153  /* now try to balance resources across the cluster */
154  if (node1->details->num_resources < node2->details->num_resources) {
155  crm_trace("%s (%d) > %s (%d) : resources",
156  node1->details->uname, node1->details->num_resources,
157  node2->details->uname, node2->details->num_resources);
158  return -1;
159 
160  } else if (node1->details->num_resources > node2->details->num_resources) {
161  crm_trace("%s (%d) < %s (%d) : resources",
162  node1->details->uname, node1->details->num_resources,
163  node2->details->uname, node2->details->num_resources);
164  return 1;
165  }
166 
167  if (nw->active && nw->active->details == node1->details) {
168  crm_trace("%s (%d) > %s (%d) : active",
169  node1->details->uname, node1->details->num_resources,
170  node2->details->uname, node2->details->num_resources);
171  return -1;
172  } else if (nw->active && nw->active->details == node2->details) {
173  crm_trace("%s (%d) < %s (%d) : active",
174  node1->details->uname, node1->details->num_resources,
175  node2->details->uname, node2->details->num_resources);
176  return 1;
177  }
178  equal:
179  crm_trace("%s = %s", node1->details->uname, node2->details->uname);
180  return strcmp(node1->details->uname, node2->details->uname);
181 }
182 
183 GList *
184 sort_nodes_by_weight(GList *nodes, pe_node_t *active_node,
185  pe_working_set_t *data_set)
186 {
187  struct node_weight_s nw = { active_node, data_set };
188 
189  return g_list_sort_with_data(nodes, sort_node_weight, &nw);
190 }
191 
192 void
194 {
195  if (rsc->allocated_to) {
196  node_t *old = rsc->allocated_to;
197 
198  crm_info("Deallocating %s from %s", rsc->id, old->details->uname);
200  rsc->allocated_to = NULL;
201 
202  old->details->allocated_rsc = g_list_remove(old->details->allocated_rsc, rsc);
203  old->details->num_resources--;
204  /* old->count--; */
206  free(old);
207  }
208 }
209 
210 gboolean
211 native_assign_node(resource_t * rsc, GListPtr nodes, node_t * chosen, gboolean force)
212 {
213  CRM_ASSERT(rsc->variant == pe_native);
214 
215  if (force == FALSE && chosen != NULL) {
216  bool unset = FALSE;
217 
218  if(chosen->weight < 0) {
219  unset = TRUE;
220 
221  // Allow the graph to assume that the remote resource will come up
222  } else if (!can_run_resources(chosen) && !pe__is_guest_node(chosen)) {
223  unset = TRUE;
224  }
225 
226  if(unset) {
227  crm_debug("All nodes for resource %s are unavailable"
228  ", unclean or shutting down (%s: %d, %d)",
229  rsc->id, chosen->details->uname, can_run_resources(chosen), chosen->weight);
231  chosen = NULL;
232  }
233  }
234 
235  /* todo: update the old node for each resource to reflect its
236  * new resource count
237  */
238 
239  native_deallocate(rsc);
241 
242  if (chosen == NULL) {
243  GListPtr gIter = NULL;
244  char *rc_inactive = crm_itoa(PCMK_OCF_NOT_RUNNING);
245 
246  crm_debug("Could not allocate a node for %s", rsc->id);
248 
249  for (gIter = rsc->actions; gIter != NULL; gIter = gIter->next) {
250  action_t *op = (action_t *) gIter->data;
251  const char *interval_ms_s = g_hash_table_lookup(op->meta, XML_LRM_ATTR_INTERVAL_MS);
252 
253  crm_debug("Processing %s", op->uuid);
254  if(safe_str_eq(RSC_STOP, op->task)) {
255  update_action_flags(op, pe_action_optional | pe_action_clear, __FUNCTION__, __LINE__);
256 
257  } else if(safe_str_eq(RSC_START, op->task)) {
258  update_action_flags(op, pe_action_runnable | pe_action_clear, __FUNCTION__, __LINE__);
259  /* set_bit(rsc->flags, pe_rsc_block); */
260 
261  } else if (interval_ms_s && safe_str_neq(interval_ms_s, "0")) {
262  if(safe_str_eq(rc_inactive, g_hash_table_lookup(op->meta, XML_ATTR_TE_TARGET_RC))) {
263  /* This is a recurring monitor for the stopped state, leave it alone */
264 
265  } else {
266  /* Normal monitor operation, cancel it */
267  update_action_flags(op, pe_action_runnable | pe_action_clear, __FUNCTION__, __LINE__);
268  }
269  }
270  }
271 
272  free(rc_inactive);
273  return FALSE;
274  }
275 
276  crm_debug("Assigning %s to %s", chosen->details->uname, rsc->id);
277  rsc->allocated_to = node_copy(chosen);
278 
279  chosen->details->allocated_rsc = g_list_prepend(chosen->details->allocated_rsc, rsc);
280  chosen->details->num_resources++;
281  chosen->count++;
282  calculate_utilization(chosen->details->utilization, rsc->utilization, FALSE);
283  dump_rsc_utilization(show_utilization ? 0 : utilization_log_level, __FUNCTION__, rsc, chosen);
284 
285  return TRUE;
286 }
287 
288 void
289 log_action(unsigned int log_level, const char *pre_text, action_t * action, gboolean details)
290 {
291  const char *node_uname = NULL;
292  const char *node_uuid = NULL;
293 
294  if (action == NULL) {
295  crm_trace("%s%s: <NULL>", pre_text == NULL ? "" : pre_text, pre_text == NULL ? "" : ": ");
296  return;
297  }
298 
299  if (is_set(action->flags, pe_action_pseudo)) {
300  node_uname = NULL;
301  node_uuid = NULL;
302 
303  } else if (action->node != NULL) {
304  node_uname = action->node->details->uname;
305  node_uuid = action->node->details->id;
306  } else {
307  node_uname = "<none>";
308  node_uuid = NULL;
309  }
310 
311  switch (text2task(action->task)) {
312  case stonith_node:
313  case shutdown_crm:
314  crm_trace("%s%s%sAction %d: %s%s%s%s%s%s",
315  pre_text == NULL ? "" : pre_text,
316  pre_text == NULL ? "" : ": ",
317  is_set(action->flags,
318  pe_action_pseudo) ? "Pseudo " : is_set(action->flags,
320  "Optional " : is_set(action->flags,
321  pe_action_runnable) ? is_set(action->flags,
323  ? "" : "(Provisional) " : "!!Non-Startable!! ", action->id,
324  action->uuid, node_uname ? "\ton " : "",
325  node_uname ? node_uname : "", node_uuid ? "\t\t(" : "",
326  node_uuid ? node_uuid : "", node_uuid ? ")" : "");
327  break;
328  default:
329  crm_trace("%s%s%sAction %d: %s %s%s%s%s%s%s",
330  pre_text == NULL ? "" : pre_text,
331  pre_text == NULL ? "" : ": ",
332  is_set(action->flags,
333  pe_action_optional) ? "Optional " : is_set(action->flags,
335  ? "Pseudo " : is_set(action->flags,
336  pe_action_runnable) ? is_set(action->flags,
338  ? "" : "(Provisional) " : "!!Non-Startable!! ", action->id,
339  action->uuid, action->rsc ? action->rsc->id : "<none>",
340  node_uname ? "\ton " : "", node_uname ? node_uname : "",
341  node_uuid ? "\t\t(" : "", node_uuid ? node_uuid : "", node_uuid ? ")" : "");
342 
343  break;
344  }
345 
346  if (details) {
347  GListPtr gIter = NULL;
348 
349  crm_trace("\t\t====== Preceding Actions");
350 
351  gIter = action->actions_before;
352  for (; gIter != NULL; gIter = gIter->next) {
353  action_wrapper_t *other = (action_wrapper_t *) gIter->data;
354 
355  log_action(log_level + 1, "\t\t", other->action, FALSE);
356  }
357 
358  crm_trace("\t\t====== Subsequent Actions");
359 
360  gIter = action->actions_after;
361  for (; gIter != NULL; gIter = gIter->next) {
362  action_wrapper_t *other = (action_wrapper_t *) gIter->data;
363 
364  log_action(log_level + 1, "\t\t", other->action, FALSE);
365  }
366 
367  crm_trace("\t\t====== End");
368 
369  } else {
370  crm_trace("\t\t(before=%d, after=%d)",
371  g_list_length(action->actions_before), g_list_length(action->actions_after));
372  }
373 }
374 
375 gboolean
376 can_run_any(GHashTable * nodes)
377 {
378  GHashTableIter iter;
379  node_t *node = NULL;
380 
381  if (nodes == NULL) {
382  return FALSE;
383  }
384 
385  g_hash_table_iter_init(&iter, nodes);
386  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
387  if (can_run_resources(node) && node->weight >= 0) {
388  return TRUE;
389  }
390  }
391 
392  return FALSE;
393 }
394 
395 pe_action_t *
396 create_pseudo_resource_op(resource_t * rsc, const char *task, bool optional, bool runnable, pe_working_set_t *data_set)
397 {
398  pe_action_t *action = custom_action(rsc, generate_op_key(rsc->id, task, 0), task, NULL, optional, TRUE, data_set);
399  update_action_flags(action, pe_action_pseudo, __FUNCTION__, __LINE__);
400  update_action_flags(action, pe_action_runnable, __FUNCTION__, __LINE__);
401  if(runnable) {
402  update_action_flags(action, pe_action_runnable, __FUNCTION__, __LINE__);
403  }
404  return action;
405 }
406 
419 pe_action_t *
420 pe_cancel_op(pe_resource_t *rsc, const char *task, guint interval_ms,
421  pe_node_t *node, pe_working_set_t *data_set)
422 {
423  pe_action_t *cancel_op;
424  char *interval_ms_s = crm_strdup_printf("%u", interval_ms);
425 
426  // @TODO dangerous if possible to schedule another action with this key
427  char *key = generate_op_key(rsc->id, task, interval_ms);
428 
429  cancel_op = custom_action(rsc, key, RSC_CANCEL, node, FALSE, TRUE,
430  data_set);
431 
432  free(cancel_op->task);
433  cancel_op->task = strdup(RSC_CANCEL);
434 
435  free(cancel_op->cancel_task);
436  cancel_op->cancel_task = strdup(task);
437 
438  add_hash_param(cancel_op->meta, XML_LRM_ATTR_TASK, task);
439  add_hash_param(cancel_op->meta, XML_LRM_ATTR_INTERVAL_MS, interval_ms_s);
440  free(interval_ms_s);
441 
442  return cancel_op;
443 }
444 
457 pe_action_t *
459 {
460  char *shutdown_id = crm_strdup_printf("%s-%s", CRM_OP_SHUTDOWN,
461  node->details->uname);
462 
463  pe_action_t *shutdown_op = custom_action(NULL, shutdown_id, CRM_OP_SHUTDOWN,
464  node, FALSE, TRUE, data_set);
465 
466  crm_notice("Scheduling shutdown of node %s", node->details->uname);
467  shutdown_constraints(node, shutdown_op, data_set);
469  return shutdown_op;
470 }
pe_action_t * pe_cancel_op(pe_resource_t *rsc, const char *name, guint interval_ms, pe_node_t *node, pe_working_set_t *data_set)
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:156
GListPtr allocated_rsc
Definition: pe_types.h:202
enum rsc_role_e role_filter
Definition: internal.h:30
#define RSC_STOP
Definition: crm.h:177
#define crm_notice(fmt, args...)
Definition: logging.h:242
void dump_rsc_utilization(int level, const char *comment, resource_t *rsc, node_t *node)
Definition: utils.c:370
gboolean safe_str_neq(const char *a, const char *b)
Definition: strings.c:157
#define INFINITY
Definition: crm.h:73
void native_deallocate(resource_t *rsc)
int compare_capacity(const node_t *node1, const node_t *node2)
GList * sort_nodes_by_weight(GList *nodes, pe_node_t *active_node, pe_working_set_t *data_set)
node_t * node_copy(const node_t *this_node)
Definition: utils.c:118
int utilization_log_level
int count
Definition: pe_types.h:212
pe_resource_t * rsc
Definition: pe_types.h:365
enum rsc_role_e next_role
Definition: pe_types.h:334
gboolean exclusive_discover
Definition: pe_types.h:315
char * cancel_task
Definition: pe_types.h:371
pe_action_t * sched_shutdown_op(pe_node_t *node, pe_working_set_t *data_set)
#define XML_LOCATION_ATTR_DISCOVERY
Definition: msg_xml.h:315
enum action_tasks text2task(const char *task)
Definition: common.c:224
#define clear_bit(word, bit)
Definition: crm_internal.h:168
pe_resource_t * rsc_lh
Definition: internal.h:29
#define RSC_START
Definition: crm.h:174
pe_node_t * allocated_to
Definition: pe_types.h:326
pe_action_t * action
Definition: pe_types.h:483
GListPtr actions_before
Definition: pe_types.h:402
gboolean native_assign_node(resource_t *rsc, GListPtr candidates, node_t *chosen, gboolean force)
void calculate_utilization(GHashTable *current_utilization, GHashTable *utilization, gboolean plus)
GListPtr placement_constraints
Definition: pe_types.h:135
#define pe_rsc_provisional
Definition: pe_types.h:227
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:260
pe__location_t * rsc2node_new(const char *id, pe_resource_t *rsc, int weight, const char *discovery_mode, pe_node_t *node, pe_working_set_t *data_set)
int weight
Definition: pe_types.h:210
enum pe_discover_e discover_mode
Definition: internal.h:31
#define set_bit(word, bit)
Definition: crm_internal.h:167
gboolean pe__is_guest_node(pe_node_t *node)
Definition: remote.c:47
#define crm_debug(fmt, args...)
Definition: logging.h:245
void log_action(unsigned int log_level, const char *pre_text, action_t *action, gboolean details)
#define XML_BOOLEAN_TRUE
Definition: msg_xml.h:107
char * task
Definition: pe_types.h:369
#define crm_trace(fmt, args...)
Definition: logging.h:246
GHashTable * meta
Definition: pe_types.h:379
struct pe_node_shared_s * details
Definition: pe_types.h:213
pe_node_t * node
Definition: pe_types.h:366
unsigned long long flags
Definition: pe_types.h:311
const char * uname
Definition: pe_types.h:179
#define XML_ATTR_TE_NOWAIT
Definition: msg_xml.h:359
action_t * custom_action(resource_t *rsc, char *key, const char *task, node_t *on_node, gboolean optional, gboolean foo, pe_working_set_t *data_set)
Definition: utils.c:441
GHashTable * utilization
Definition: pe_types.h:338
gboolean standby
Definition: pe_types.h:184
char * uuid
Definition: pe_types.h:370
enum pe_obj_types variant
Definition: pe_types.h:293
gboolean can_run_resources(const node_t *node)
gboolean can_run_any(GHashTable *nodes)
GListPtr actions
Definition: pe_types.h:322
GListPtr rsc_location
Definition: pe_types.h:321
#define CRM_OP_SHUTDOWN
Definition: crm.h:118
const char * id
Definition: pe_types.h:178
gboolean show_utilization
pe_action_t * create_pseudo_resource_op(resource_t *rsc, const char *task, bool optional, bool runnable, pe_working_set_t *data_set)
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:406
gboolean update_action_flags(action_t *action, enum pe_action_flags flags, const char *source, int line)
#define CRM_ASSERT(expr)
Definition: results.h:42
GListPtr actions_after
Definition: pe_types.h:403
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:258
GHashTable * utilization
Definition: pe_types.h:205
gboolean shutdown
Definition: pe_types.h:189
char data[0]
Definition: internal.h:92
#define crm_str(x)
Definition: logging.h:266
enum pe_action_flags flags
Definition: pe_types.h:374
gboolean maintenance
Definition: pe_types.h:192
#define RSC_CANCEL
Definition: crm.h:169
#define pe_err(fmt...)
Definition: internal.h:20
#define safe_str_eq(a, b)
Definition: util.h:59
gboolean unclean
Definition: pe_types.h:187
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
GList * GListPtr
Definition: crm.h:192
#define crm_info(fmt, args...)
Definition: logging.h:243
char * generate_op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key.
Definition: operations.c:39
gboolean shutdown_constraints(node_t *node, action_t *shutdown_op, pe_working_set_t *data_set)
gboolean online
Definition: pe_types.h:183
#define XML_ATTR_TE_TARGET_RC
Definition: msg_xml.h:360
char * id
Definition: pe_types.h:284