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