This source file includes following definitions.
- stop_te_timer
- te_graph_trigger
- trigger_graph_processing
- abort_timer_popped
- abort_after_delay
- abort2text
- update_abort_priority
- abort_transition_graph
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <crm/crm.h>
12 #include <crm/msg_xml.h>
13 #include <crm/common/xml.h>
14
15 #include <pacemaker-controld.h>
16
17 gboolean
18 stop_te_timer(crm_action_timer_t * timer)
19 {
20 if (timer == NULL) {
21 return FALSE;
22 }
23 if (timer->source_id != 0) {
24 crm_trace("Stopping action timer");
25 g_source_remove(timer->source_id);
26 timer->source_id = 0;
27 } else {
28 crm_trace("Action timer was already stopped");
29 return FALSE;
30 }
31 return TRUE;
32 }
33
34 gboolean
35 te_graph_trigger(gpointer user_data)
36 {
37 if (transition_graph == NULL) {
38 crm_debug("Nothing to do");
39 return TRUE;
40 }
41
42 crm_trace("Invoking graph %d in state %s", transition_graph->id, fsa_state2string(fsa_state));
43
44 switch (fsa_state) {
45 case S_STARTING:
46 case S_PENDING:
47 case S_NOT_DC:
48 case S_HALT:
49 case S_ILLEGAL:
50 case S_STOPPING:
51 case S_TERMINATE:
52 return TRUE;
53 default:
54 break;
55 }
56
57 if (transition_graph->complete == FALSE) {
58 enum transition_status graph_rc;
59 int limit = transition_graph->batch_limit;
60
61 transition_graph->batch_limit = throttle_get_total_job_limit(limit);
62 graph_rc = pcmk__execute_graph(transition_graph);
63 transition_graph->batch_limit = limit;
64
65 if (graph_rc == transition_active) {
66 crm_trace("Transition not yet complete");
67 return TRUE;
68
69 } else if (graph_rc == transition_pending) {
70 crm_trace("Transition not yet complete - no actions fired");
71 return TRUE;
72 }
73
74 if (graph_rc != transition_complete) {
75 crm_warn("Transition failed: %s",
76 pcmk__graph_status2text(graph_rc));
77 pcmk__log_graph(LOG_NOTICE, transition_graph);
78 }
79 }
80
81 crm_debug("Transition %d is now complete", transition_graph->id);
82 transition_graph->complete = TRUE;
83 notify_crmd(transition_graph);
84
85 return TRUE;
86 }
87
88 void
89 trigger_graph_processing(const char *fn, int line)
90 {
91 crm_trace("%s:%d - Triggered graph processing", fn, line);
92 mainloop_set_trigger(transition_trigger);
93 }
94
95 static struct abort_timer_s {
96 bool aborted;
97 guint id;
98 int priority;
99 enum transition_action action;
100 const char *text;
101 } abort_timer = { 0, };
102
103 static gboolean
104 abort_timer_popped(gpointer data)
105 {
106 if (AM_I_DC && (abort_timer.aborted == FALSE)) {
107 abort_transition(abort_timer.priority, abort_timer.action,
108 abort_timer.text, NULL);
109 }
110 abort_timer.id = 0;
111 return FALSE;
112 }
113
114
115
116
117
118
119
120 void
121 abort_after_delay(int abort_priority, enum transition_action abort_action,
122 const char *abort_text, guint delay_ms)
123 {
124 if (abort_timer.id) {
125
126 g_source_remove(abort_timer.id);
127 }
128 abort_timer.aborted = FALSE;
129 abort_timer.priority = abort_priority;
130 abort_timer.action = abort_action;
131 abort_timer.text = abort_text;
132 abort_timer.id = g_timeout_add(delay_ms, abort_timer_popped, NULL);
133 }
134
135 static const char *
136 abort2text(enum transition_action abort_action)
137 {
138 switch (abort_action) {
139 case tg_done:
140 return "done";
141 case tg_stop:
142 return "stop";
143 case tg_restart:
144 return "restart";
145 case tg_shutdown:
146 return "shutdown";
147 }
148 return "unknown";
149 }
150
151 static bool
152 update_abort_priority(crm_graph_t *graph, int priority,
153 enum transition_action action, const char *abort_reason)
154 {
155 bool change = FALSE;
156
157 if (graph == NULL) {
158 return change;
159 }
160
161 if (graph->abort_priority < priority) {
162 crm_debug("Abort priority upgraded from %d to %d", graph->abort_priority, priority);
163 graph->abort_priority = priority;
164 if (graph->abort_reason != NULL) {
165 crm_debug("'%s' abort superseded by %s", graph->abort_reason, abort_reason);
166 }
167 graph->abort_reason = abort_reason;
168 change = TRUE;
169 }
170
171 if (graph->completion_action < action) {
172 crm_debug("Abort action %s superseded by %s: %s",
173 abort2text(graph->completion_action), abort2text(action), abort_reason);
174 graph->completion_action = action;
175 change = TRUE;
176 }
177
178 return change;
179 }
180
181 void
182 abort_transition_graph(int abort_priority, enum transition_action abort_action,
183 const char *abort_text, xmlNode * reason, const char *fn, int line)
184 {
185 int add[] = { 0, 0, 0 };
186 int del[] = { 0, 0, 0 };
187 int level = LOG_INFO;
188 xmlNode *diff = NULL;
189 xmlNode *change = NULL;
190
191 CRM_CHECK(transition_graph != NULL, return);
192
193 switch (fsa_state) {
194 case S_STARTING:
195 case S_PENDING:
196 case S_NOT_DC:
197 case S_HALT:
198 case S_ILLEGAL:
199 case S_STOPPING:
200 case S_TERMINATE:
201 crm_info("Abort %s suppressed: state=%s (complete=%d)",
202 abort_text, fsa_state2string(fsa_state), transition_graph->complete);
203 return;
204 default:
205 break;
206 }
207
208 abort_timer.aborted = TRUE;
209 controld_expect_sched_reply(NULL);
210
211 if (transition_graph->complete == FALSE) {
212 if(update_abort_priority(transition_graph, abort_priority, abort_action, abort_text)) {
213 level = LOG_NOTICE;
214 }
215 }
216
217 if(reason) {
218 xmlNode *search = NULL;
219
220 for(search = reason; search; search = search->parent) {
221 if (pcmk__str_eq(XML_TAG_DIFF, TYPE(search), pcmk__str_casei)) {
222 diff = search;
223 break;
224 }
225 }
226
227 if(diff) {
228 xml_patch_versions(diff, add, del);
229 for(search = reason; search; search = search->parent) {
230 if (pcmk__str_eq(XML_DIFF_CHANGE, TYPE(search), pcmk__str_casei)) {
231 change = search;
232 break;
233 }
234 }
235 }
236 }
237
238 if(reason == NULL) {
239 do_crm_log(level, "Transition %d aborted: %s "CRM_XS" source=%s:%d complete=%s",
240 transition_graph->id, abort_text, fn, line,
241 pcmk__btoa(transition_graph->complete));
242
243 } else if(change == NULL) {
244 char *local_path = xml_get_path(reason);
245
246 do_crm_log(level, "Transition %d aborted by %s.%s: %s "
247 CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
248 transition_graph->id, TYPE(reason), ID(reason), abort_text,
249 add[0], add[1], add[2], fn, line, local_path,
250 pcmk__btoa(transition_graph->complete));
251 free(local_path);
252
253 } else {
254 const char *kind = NULL;
255 const char *op = crm_element_value(change, XML_DIFF_OP);
256 const char *path = crm_element_value(change, XML_DIFF_PATH);
257
258 if(change == reason) {
259 if(strcmp(op, "create") == 0) {
260 reason = reason->children;
261
262 } else if(strcmp(op, "modify") == 0) {
263 reason = first_named_child(reason, XML_DIFF_RESULT);
264 if(reason) {
265 reason = reason->children;
266 }
267 }
268 }
269
270 kind = TYPE(reason);
271 if(strcmp(op, "delete") == 0) {
272 const char *shortpath = strrchr(path, '/');
273
274 do_crm_log(level, "Transition %d aborted by deletion of %s: %s "
275 CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
276 transition_graph->id,
277 (shortpath? (shortpath + 1) : path), abort_text,
278 add[0], add[1], add[2], fn, line, path,
279 pcmk__btoa(transition_graph->complete));
280
281 } else if (pcmk__str_eq(XML_CIB_TAG_NVPAIR, kind, pcmk__str_casei)) {
282 do_crm_log(level, "Transition %d aborted by %s doing %s %s=%s: %s "
283 CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
284 transition_graph->id,
285 crm_element_value(reason, XML_ATTR_ID), op,
286 crm_element_value(reason, XML_NVPAIR_ATTR_NAME),
287 crm_element_value(reason, XML_NVPAIR_ATTR_VALUE),
288 abort_text, add[0], add[1], add[2], fn, line, path,
289 pcmk__btoa(transition_graph->complete));
290
291 } else if (pcmk__str_eq(XML_LRM_TAG_RSC_OP, kind, pcmk__str_casei)) {
292 const char *magic = crm_element_value(reason, XML_ATTR_TRANSITION_MAGIC);
293
294 do_crm_log(level, "Transition %d aborted by operation %s '%s' on %s: %s "
295 CRM_XS " magic=%s cib=%d.%d.%d source=%s:%d complete=%s",
296 transition_graph->id,
297 crm_element_value(reason, XML_LRM_ATTR_TASK_KEY), op,
298 crm_element_value(reason, XML_LRM_ATTR_TARGET), abort_text,
299 magic, add[0], add[1], add[2], fn, line,
300 pcmk__btoa(transition_graph->complete));
301
302 } else if (pcmk__strcase_any_of(kind, XML_CIB_TAG_STATE, XML_CIB_TAG_NODE, NULL)) {
303 const char *uname = crm_peer_uname(ID(reason));
304
305 do_crm_log(level, "Transition %d aborted by %s '%s' on %s: %s "
306 CRM_XS " cib=%d.%d.%d source=%s:%d complete=%s",
307 transition_graph->id,
308 kind, op, (uname? uname : ID(reason)), abort_text,
309 add[0], add[1], add[2], fn, line,
310 pcmk__btoa(transition_graph->complete));
311
312 } else {
313 const char *id = ID(reason);
314
315 do_crm_log(level, "Transition %d aborted by %s.%s '%s': %s "
316 CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
317 transition_graph->id,
318 TYPE(reason), (id? id : ""), (op? op : "change"),
319 abort_text, add[0], add[1], add[2], fn, line, path,
320 pcmk__btoa(transition_graph->complete));
321 }
322 }
323
324 if (transition_graph->complete) {
325 if (transition_timer->period_ms > 0) {
326 controld_stop_timer(transition_timer);
327 controld_start_timer(transition_timer);
328 } else {
329 register_fsa_input(C_FSA_INTERNAL, I_PE_CALC, NULL);
330 }
331 return;
332 }
333
334 mainloop_set_trigger(transition_trigger);
335 }