pacemaker  2.0.4-2deceaa
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pcmk_trans_graph.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2019 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #include <crm/crm.h>
13 #include <crm/msg_xml.h>
14 #include <crm/common/xml.h>
15 #include <pacemaker-internal.h>
16 
18 
19 static gboolean
20 update_synapse_ready(synapse_t * synapse, int action_id)
21 {
22  GListPtr lpc = NULL;
23  gboolean updates = FALSE;
24 
25  CRM_CHECK(synapse->executed == FALSE, return FALSE);
26  CRM_CHECK(synapse->confirmed == FALSE, return FALSE);
27 
28  synapse->ready = TRUE;
29  for (lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
30  crm_action_t *prereq = (crm_action_t *) lpc->data;
31 
32  crm_trace("Processing input %d", prereq->id);
33 
34  if (prereq->id == action_id) {
35  crm_trace("Marking input %d of synapse %d confirmed", action_id, synapse->id);
36  prereq->confirmed = TRUE;
37  updates = TRUE;
38 
39  } else if (prereq->confirmed == FALSE) {
40  synapse->ready = FALSE;
41  }
42 
43  }
44 
45  if (updates) {
46  crm_trace("Updated synapse %d", synapse->id);
47  }
48  return updates;
49 }
50 
51 static gboolean
52 update_synapse_confirmed(synapse_t * synapse, int action_id)
53 {
54  GListPtr lpc = NULL;
55  gboolean updates = FALSE;
56  gboolean is_confirmed = TRUE;
57 
58  CRM_CHECK(synapse->executed, return FALSE);
59  CRM_CHECK(synapse->confirmed == FALSE, return TRUE);
60 
61  is_confirmed = TRUE;
62  for (lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
63  crm_action_t *action = (crm_action_t *) lpc->data;
64 
65  crm_trace("Processing action %d", action->id);
66 
67  if (action->id == action_id) {
68  crm_trace("Confirmed: Action %d of Synapse %d", action_id, synapse->id);
69  action->confirmed = TRUE;
70  updates = TRUE;
71 
72  } else if (action->confirmed == FALSE) {
73  is_confirmed = FALSE;
74  crm_trace("Synapse %d still not confirmed after action %d", synapse->id, action_id);
75  }
76  }
77 
78  if (is_confirmed && synapse->confirmed == FALSE) {
79  crm_trace("Confirmed: Synapse %d", synapse->id);
80  synapse->confirmed = TRUE;
81  updates = TRUE;
82  }
83 
84  if (updates) {
85  crm_trace("Updated synapse %d", synapse->id);
86  }
87  return updates;
88 }
89 
90 gboolean
92 {
93  gboolean rc = FALSE;
94  gboolean updates = FALSE;
95  GListPtr lpc = NULL;
96 
97  for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
98  synapse_t *synapse = (synapse_t *) lpc->data;
99 
100  if (synapse->confirmed || synapse->failed) {
101  crm_trace("Synapse complete");
102 
103  } else if (synapse->executed) {
104  crm_trace("Synapse executed");
105  rc = update_synapse_confirmed(synapse, action->id);
106 
107  } else if (action->failed == FALSE || synapse->priority == INFINITY) {
108  rc = update_synapse_ready(synapse, action->id);
109  }
110  updates = updates || rc;
111  }
112 
113  if (updates) {
114  crm_trace("Updated graph with completed action %d", action->id);
115  }
116  return updates;
117 }
118 
119 static gboolean
120 should_fire_synapse(crm_graph_t * graph, synapse_t * synapse)
121 {
122  GListPtr lpc = NULL;
123 
124  CRM_CHECK(synapse->executed == FALSE, return FALSE);
125  CRM_CHECK(synapse->confirmed == FALSE, return FALSE);
126 
127  crm_trace("Checking pre-reqs for synapse %d", synapse->id);
128  /* lookup prereqs */
129  synapse->ready = TRUE;
130  for (lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
131  crm_action_t *prereq = (crm_action_t *) lpc->data;
132 
133  crm_trace("Processing input %d", prereq->id);
134  if (prereq->confirmed == FALSE) {
135  crm_trace("Input %d for synapse %d not satisfied: not confirmed", prereq->id, synapse->id);
136  synapse->ready = FALSE;
137  break;
138  } else if(prereq->failed && prereq->can_fail == FALSE) {
139  crm_trace("Input %d for synapse %d not satisfied: failed", prereq->id, synapse->id);
140  synapse->ready = FALSE;
141  break;
142  }
143  }
144 
145  for (lpc = synapse->actions; synapse->ready && lpc != NULL; lpc = lpc->next) {
146  crm_action_t *a = (crm_action_t *) lpc->data;
147 
148  if (a->type == action_type_pseudo) {
149  /* None of the below applies to pseudo ops */
150 
151  } else if (synapse->priority < graph->abort_priority) {
152  crm_trace("Skipping synapse %d: abort level %d", synapse->id, graph->abort_priority);
153  graph->skipped++;
154  return FALSE;
155 
156  } else if(graph_fns->allowed && graph_fns->allowed(graph, a) == FALSE) {
157  crm_trace("Deferring synapse %d: allowed", synapse->id);
158  return FALSE;
159  }
160  }
161 
162  return synapse->ready;
163 }
164 
165 static gboolean
166 initiate_action(crm_graph_t * graph, crm_action_t * action)
167 {
168  const char *id = NULL;
169 
170  CRM_CHECK(action->executed == FALSE, return FALSE);
171 
172  id = ID(action->xml);
173  CRM_CHECK(id != NULL, return FALSE);
174 
175  action->executed = TRUE;
176  if (action->type == action_type_pseudo) {
177  crm_trace("Executing pseudo-event: %s (%d)", id, action->id);
178  return graph_fns->pseudo(graph, action);
179 
180  } else if (action->type == action_type_rsc) {
181  crm_trace("Executing rsc-event: %s (%d)", id, action->id);
182  return graph_fns->rsc(graph, action);
183 
184  } else if (action->type == action_type_crm) {
185  const char *task = NULL;
186 
187  task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
188  CRM_CHECK(task != NULL, return FALSE);
189 
190  if (safe_str_eq(task, CRM_OP_FENCE)) {
191  crm_trace("Executing STONITH-event: %s (%d)", id, action->id);
192  return graph_fns->stonith(graph, action);
193  }
194 
195  crm_trace("Executing crm-event: %s (%d)", id, action->id);
196  return graph_fns->crmd(graph, action);
197  }
198 
199  crm_err("Failed on unsupported command type: %s (id=%s)", crm_element_name(action->xml), id);
200  return FALSE;
201 }
202 
203 static gboolean
204 fire_synapse(crm_graph_t * graph, synapse_t * synapse)
205 {
206  GListPtr lpc = NULL;
207 
208  CRM_CHECK(synapse != NULL, return FALSE);
209  CRM_CHECK(synapse->ready, return FALSE);
210  CRM_CHECK(synapse->confirmed == FALSE, return TRUE);
211 
212  crm_trace("Synapse %d fired", synapse->id);
213  synapse->executed = TRUE;
214  for (lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
215  crm_action_t *action = (crm_action_t *) lpc->data;
216 
217  /* allow some leeway */
218  gboolean passed = FALSE;
219 
220  /* Invoke the action and start the timer */
221  passed = initiate_action(graph, action);
222  if (passed == FALSE) {
223  crm_err("Failed initiating <%s id=%d> in synapse %d",
224  crm_element_name(action->xml), action->id, synapse->id);
225  synapse->confirmed = TRUE;
226  action->confirmed = TRUE;
227  action->failed = TRUE;
228  return FALSE;
229  }
230  }
231 
232  return TRUE;
233 }
234 
235 int
237 {
238  GListPtr lpc = NULL;
239  int stat_log_level = LOG_DEBUG;
240  int pass_result = transition_active;
241 
242  const char *status = "In-progress";
243 
244  if (graph_fns == NULL) {
246  }
247  if (graph == NULL) {
248  return transition_complete;
249  }
250 
251  graph->fired = 0;
252  graph->pending = 0;
253  graph->skipped = 0;
254  graph->completed = 0;
255  graph->incomplete = 0;
256  crm_trace("Entering graph %d callback", graph->id);
257 
258  /* Pre-calculate the number of completed and in-flight operations */
259  for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
260  synapse_t *synapse = (synapse_t *) lpc->data;
261 
262  if (synapse->confirmed) {
263  crm_trace("Synapse %d complete", synapse->id);
264  graph->completed++;
265 
266  } else if (synapse->failed == FALSE && synapse->executed) {
267  crm_trace("Synapse %d: confirmation pending", synapse->id);
268  graph->pending++;
269  }
270  }
271 
272  /* Now check if there is work to do */
273  for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
274  synapse_t *synapse = (synapse_t *) lpc->data;
275 
276  if (graph->batch_limit > 0 && graph->pending >= graph->batch_limit) {
277  crm_debug("Throttling output: batch limit (%d) reached", graph->batch_limit);
278  break;
279  } else if (synapse->failed) {
280  graph->skipped++;
281  continue;
282 
283  } else if (synapse->confirmed || synapse->executed) {
284  /* Already handled */
285  continue;
286  }
287 
288  if (should_fire_synapse(graph, synapse)) {
289  crm_trace("Synapse %d fired", synapse->id);
290  graph->fired++;
291  if(fire_synapse(graph, synapse) == FALSE) {
292  crm_err("Synapse %d failed to fire", synapse->id);
293  stat_log_level = LOG_ERR;
294  graph->abort_priority = INFINITY;
295  graph->incomplete++;
296  graph->fired--;
297  }
298 
299  if (synapse->confirmed == FALSE) {
300  graph->pending++;
301  }
302 
303  } else {
304  crm_trace("Synapse %d cannot fire", synapse->id);
305  graph->incomplete++;
306  }
307  }
308 
309  if (graph->pending == 0 && graph->fired == 0) {
310  graph->complete = TRUE;
311  stat_log_level = LOG_NOTICE;
312  pass_result = transition_complete;
313  status = "Complete";
314 
315  if (graph->incomplete != 0 && graph->abort_priority <= 0) {
316  stat_log_level = LOG_WARNING;
317  pass_result = transition_terminated;
318  status = "Terminated";
319 
320  } else if (graph->skipped != 0) {
321  status = "Stopped";
322  }
323 
324  } else if (graph->fired == 0) {
325  pass_result = transition_pending;
326  }
327 
328  do_crm_log(stat_log_level,
329  "Transition %d (Complete=%d, Pending=%d,"
330  " Fired=%d, Skipped=%d, Incomplete=%d, Source=%s): %s",
331  graph->id, graph->completed, graph->pending, graph->fired,
332  graph->skipped, graph->incomplete, graph->source, status);
333 
334  return pass_result;
335 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:233
gboolean(* pseudo)(crm_graph_t *graph, crm_action_t *action)
GListPtr actions
gboolean confirmed
A dumping ground.
action_type_e type
#define INFINITY
Definition: crm.h:95
#define CRM_OP_FENCE
Definition: crm.h:141
gboolean can_fail
gboolean(* rsc)(crm_graph_t *graph, crm_action_t *action)
gboolean(* allowed)(crm_graph_t *graph, crm_action_t *action)
gboolean ready
const char * action
Definition: pcmk_fence.c:29
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:260
int rc
Definition: pcmk_fence.c:34
#define crm_debug(fmt, args...)
Definition: logging.h:368
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:522
#define crm_trace(fmt, args...)
Definition: logging.h:369
#define do_crm_log(level, fmt, args...)
Log a message.
Definition: logging.h:150
void set_default_graph_functions(void)
gboolean executed
Wrappers for and extensions to libxml2.
gboolean(* crmd)(crm_graph_t *graph, crm_action_t *action)
gboolean update_graph(crm_graph_t *graph, crm_action_t *action)
GListPtr synapses
gboolean complete
GListPtr inputs
gboolean failed
#define crm_err(fmt, args...)
Definition: logging.h:363
gboolean(* stonith)(crm_graph_t *graph, crm_action_t *action)
int run_graph(crm_graph_t *graph)
gboolean confirmed
#define ID(x)
Definition: msg_xml.h:418
#define safe_str_eq(a, b)
Definition: util.h:65
gboolean executed
GList * GListPtr
Definition: crm.h:214
crm_graph_functions_t * graph_fns