This source file includes following definitions.
- generate_op_key
- parse_op_key
- generate_notify_key
- generate_transition_magic_v202
- generate_transition_magic
- decode_transition_magic
- generate_transition_key
- decode_transition_key
- filter_action_parameters
- append_digest
- rsc_op_expected_rc
- did_rsc_op_fail
- crm_create_op_xml
- create_operation_update
- crm_op_needs_metadata
1
2
3
4
5
6
7
8 #include <crm_internal.h>
9
10 #ifndef _GNU_SOURCE
11 # define _GNU_SOURCE
12 #endif
13
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <ctype.h>
18
19 #include <crm/crm.h>
20 #include <crm/lrmd.h>
21 #include <crm/msg_xml.h>
22 #include <crm/common/xml.h>
23 #include <crm/common/util.h>
24
25
26
27
28
29
30
31
32
33
34
35
36 char *
37 generate_op_key(const char *rsc_id, const char *op_type, int interval)
38 {
39 CRM_ASSERT(rsc_id != NULL);
40 CRM_ASSERT(op_type != NULL);
41 CRM_ASSERT(interval >= 0);
42 return crm_strdup_printf("%s_%s_%d", rsc_id, op_type, interval);
43 }
44
45 gboolean
46 parse_op_key(const char *key, char **rsc_id, char **op_type, int *interval)
47 {
48 char *notify = NULL;
49 char *mutable_key = NULL;
50 char *mutable_key_ptr = NULL;
51 int len = 0, offset = 0, ch = 0;
52
53 CRM_CHECK(key != NULL, return FALSE);
54
55 *interval = 0;
56 len = strlen(key);
57 offset = len - 1;
58
59 crm_trace("Source: %s", key);
60
61 while (offset > 0 && isdigit(key[offset])) {
62 int digits = len - offset;
63
64 ch = key[offset] - '0';
65 CRM_CHECK(ch < 10, return FALSE);
66 CRM_CHECK(ch >= 0, return FALSE);
67 while (digits > 1) {
68 digits--;
69 ch = ch * 10;
70 }
71 *interval += ch;
72 offset--;
73 }
74
75 crm_trace(" Interval: %d", *interval);
76 CRM_CHECK(key[offset] == '_', return FALSE);
77
78 mutable_key = strdup(key);
79 mutable_key[offset] = 0;
80 offset--;
81
82 while (offset > 0 && key[offset] != '_') {
83 offset--;
84 }
85
86 CRM_CHECK(key[offset] == '_', free(mutable_key);
87 return FALSE);
88
89 mutable_key_ptr = mutable_key + offset + 1;
90
91 crm_trace(" Action: %s", mutable_key_ptr);
92
93 *op_type = strdup(mutable_key_ptr);
94
95 mutable_key[offset] = 0;
96 offset--;
97
98 CRM_CHECK(mutable_key != mutable_key_ptr, free(mutable_key);
99 return FALSE);
100
101 notify = strstr(mutable_key, "_post_notify");
102 if (notify && safe_str_eq(notify, "_post_notify")) {
103 notify[0] = 0;
104 }
105
106 notify = strstr(mutable_key, "_pre_notify");
107 if (notify && safe_str_eq(notify, "_pre_notify")) {
108 notify[0] = 0;
109 }
110
111 crm_trace(" Resource: %s", mutable_key);
112 *rsc_id = mutable_key;
113
114 return TRUE;
115 }
116
117 char *
118 generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
119 {
120 int len = 12;
121 char *op_id = NULL;
122
123 CRM_CHECK(rsc_id != NULL, return NULL);
124 CRM_CHECK(op_type != NULL, return NULL);
125 CRM_CHECK(notify_type != NULL, return NULL);
126
127 len += strlen(op_type);
128 len += strlen(rsc_id);
129 len += strlen(notify_type);
130 if(len > 0) {
131 op_id = malloc(len);
132 }
133 if (op_id != NULL) {
134 sprintf(op_id, "%s_%s_notify_%s_0", rsc_id, notify_type, op_type);
135 }
136 return op_id;
137 }
138
139 char *
140 generate_transition_magic_v202(const char *transition_key, int op_status)
141 {
142 int len = 80;
143 char *fail_state = NULL;
144
145 CRM_CHECK(transition_key != NULL, return NULL);
146
147 len += strlen(transition_key);
148
149 fail_state = malloc(len);
150 if (fail_state != NULL) {
151 snprintf(fail_state, len, "%d:%s", op_status, transition_key);
152 }
153 return fail_state;
154 }
155
156 char *
157 generate_transition_magic(const char *transition_key, int op_status, int op_rc)
158 {
159 int len = 80;
160 char *fail_state = NULL;
161
162 CRM_CHECK(transition_key != NULL, return NULL);
163
164 len += strlen(transition_key);
165
166 fail_state = malloc(len);
167 if (fail_state != NULL) {
168 snprintf(fail_state, len, "%d:%d;%s", op_status, op_rc, transition_key);
169 }
170 return fail_state;
171 }
172
173 gboolean
174 decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id,
175 int *op_status, int *op_rc, int *target_rc)
176 {
177 int res = 0;
178 char *key = NULL;
179 gboolean result = TRUE;
180
181 CRM_CHECK(magic != NULL, return FALSE);
182 CRM_CHECK(op_rc != NULL, return FALSE);
183 CRM_CHECK(op_status != NULL, return FALSE);
184
185 key = calloc(1, strlen(magic) + 1);
186 res = sscanf(magic, "%d:%d;%s", op_status, op_rc, key);
187 if (res != 3) {
188 crm_warn("Only found %d items in: '%s'", res, magic);
189 free(key);
190 return FALSE;
191 }
192
193 CRM_CHECK(decode_transition_key(key, uuid, transition_id, action_id, target_rc), result = FALSE);
194
195 free(key);
196 return result;
197 }
198
199 char *
200 generate_transition_key(int transition_id, int action_id, int target_rc, const char *node)
201 {
202 int len = 40;
203 char *fail_state = NULL;
204
205 CRM_CHECK(node != NULL, return NULL);
206
207 len += strlen(node);
208
209 fail_state = malloc(len);
210 if (fail_state != NULL) {
211 snprintf(fail_state, len, "%d:%d:%d:%-*s", action_id, transition_id, target_rc, 36, node);
212 }
213 return fail_state;
214 }
215
216 gboolean
217 decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id,
218 int *target_rc)
219 {
220 int res = 0;
221 gboolean done = FALSE;
222
223 CRM_CHECK(uuid != NULL, return FALSE);
224 CRM_CHECK(target_rc != NULL, return FALSE);
225 CRM_CHECK(action_id != NULL, return FALSE);
226 CRM_CHECK(transition_id != NULL, return FALSE);
227
228 *uuid = calloc(1, 37);
229 res = sscanf(key, "%d:%d:%d:%36s", action_id, transition_id, target_rc, *uuid);
230 switch (res) {
231 case 4:
232
233 done = TRUE;
234 break;
235 case 3:
236 case 2:
237
238
239
240 done = TRUE;
241 *target_rc = -1;
242 res = sscanf(key, "%d:%d:%36s", action_id, transition_id, *uuid);
243 if (res == 2) {
244 *action_id = -1;
245 res = sscanf(key, "%d:%36s", transition_id, *uuid);
246 CRM_CHECK(res == 2, done = FALSE);
247
248 } else if (res != 3) {
249 CRM_CHECK(res == 3, done = FALSE);
250 }
251 break;
252
253 case 1:
254
255 done = TRUE;
256 *action_id = -1;
257 *target_rc = -1;
258 res = sscanf(key, "%d:%36s", transition_id, *uuid);
259 CRM_CHECK(res == 2, done = FALSE);
260 break;
261 default:
262 crm_crit("Unhandled sscanf result (%d) for %s", res, key);
263 }
264
265 if (strlen(*uuid) != 36) {
266 crm_warn("Bad UUID (%s) in sscanf result (%d) for %s", *uuid, res, key);
267 }
268
269 if (done == FALSE) {
270 crm_err("Cannot decode '%s' rc=%d", key, res);
271
272 free(*uuid);
273 *uuid = NULL;
274 *target_rc = -1;
275 *action_id = -1;
276 *transition_id = -1;
277 }
278
279 return done;
280 }
281
282 void
283 filter_action_parameters(xmlNode * param_set, const char *version)
284 {
285 char *key = NULL;
286 char *timeout = NULL;
287 char *interval = NULL;
288
289 const char *attr_filter[] = {
290 XML_ATTR_ID,
291 XML_ATTR_CRM_VERSION,
292 XML_LRM_ATTR_OP_DIGEST,
293 XML_LRM_ATTR_TARGET,
294 XML_LRM_ATTR_TARGET_UUID,
295 "pcmk_external_ip"
296 };
297
298 gboolean do_delete = FALSE;
299 int lpc = 0;
300 static int meta_len = 0;
301
302 if (meta_len == 0) {
303 meta_len = strlen(CRM_META);
304 }
305
306 if (param_set == NULL) {
307 return;
308 }
309
310 for (lpc = 0; lpc < DIMOF(attr_filter); lpc++) {
311 xml_remove_prop(param_set, attr_filter[lpc]);
312 }
313
314 key = crm_meta_name(XML_LRM_ATTR_INTERVAL);
315 interval = crm_element_value_copy(param_set, key);
316 free(key);
317
318 key = crm_meta_name(XML_ATTR_TIMEOUT);
319 timeout = crm_element_value_copy(param_set, key);
320
321 if (param_set) {
322 xmlAttrPtr xIter = param_set->properties;
323
324 while (xIter) {
325 const char *prop_name = (const char *)xIter->name;
326
327 xIter = xIter->next;
328 do_delete = FALSE;
329 if (strncasecmp(prop_name, CRM_META, meta_len) == 0) {
330 do_delete = TRUE;
331 }
332
333 if (do_delete) {
334 xml_remove_prop(param_set, prop_name);
335 }
336 }
337 }
338
339 if (crm_get_msec(interval) > 0 && compare_version(version, "1.0.8") > 0) {
340
341 if (timeout != NULL) {
342 crm_xml_add(param_set, key, timeout);
343 }
344 }
345
346 free(interval);
347 free(timeout);
348 free(key);
349 }
350
351 #define FAKE_TE_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
352 static void
353 append_digest(lrmd_event_data_t * op, xmlNode * update, const char *version, const char *magic,
354 int level)
355 {
356
357
358
359
360 char *digest = NULL;
361 xmlNode *args_xml = NULL;
362
363 if (op->params == NULL) {
364 return;
365 }
366
367 args_xml = create_xml_node(NULL, XML_TAG_PARAMS);
368 g_hash_table_foreach(op->params, hash2field, args_xml);
369 filter_action_parameters(args_xml, version);
370 digest = calculate_operation_digest(args_xml, version);
371
372 #if 0
373 if (level < get_crm_log_level()
374 && op->interval == 0 && crm_str_eq(op->op_type, CRMD_ACTION_START, TRUE)) {
375 char *digest_source = dump_xml_unformatted(args_xml);
376
377 do_crm_log(level, "Calculated digest %s for %s (%s). Source: %s\n",
378 digest, ID(update), magic, digest_source);
379 free(digest_source);
380 }
381 #endif
382 crm_xml_add(update, XML_LRM_ATTR_OP_DIGEST, digest);
383
384 free_xml(args_xml);
385 free(digest);
386 }
387
388 int
389 rsc_op_expected_rc(lrmd_event_data_t * op)
390 {
391 int rc = 0;
392
393 if (op && op->user_data) {
394 int dummy = 0;
395 char *uuid = NULL;
396
397 decode_transition_key(op->user_data, &uuid, &dummy, &dummy, &rc);
398 free(uuid);
399 }
400 return rc;
401 }
402
403 gboolean
404 did_rsc_op_fail(lrmd_event_data_t * op, int target_rc)
405 {
406 switch (op->op_status) {
407 case PCMK_LRM_OP_CANCELLED:
408 case PCMK_LRM_OP_PENDING:
409 return FALSE;
410 break;
411
412 case PCMK_LRM_OP_NOTSUPPORTED:
413 case PCMK_LRM_OP_TIMEOUT:
414 case PCMK_LRM_OP_ERROR:
415 return TRUE;
416 break;
417
418 default:
419 if (target_rc != op->rc) {
420 return TRUE;
421 }
422 }
423
424 return FALSE;
425 }
426
427
428
429
430
431
432
433
434
435
436
437
438 xmlNode *
439 crm_create_op_xml(xmlNode *parent, const char *prefix, const char *task,
440 const char *interval, const char *timeout)
441 {
442 xmlNode *xml_op;
443
444 CRM_CHECK(prefix && task && interval, return NULL);
445
446 xml_op = create_xml_node(parent, XML_ATTR_OP);
447 crm_xml_set_id(xml_op, "%s-%s-%s", prefix, task, interval);
448 crm_xml_add(xml_op, XML_LRM_ATTR_INTERVAL, interval);
449 crm_xml_add(xml_op, "name", task);
450 if (timeout) {
451 crm_xml_add(xml_op, XML_ATTR_TIMEOUT, timeout);
452 }
453 return xml_op;
454 }
455
456 xmlNode *
457 create_operation_update(xmlNode * parent, lrmd_event_data_t * op, const char * caller_version,
458 int target_rc, const char * node, const char * origin, int level)
459 {
460 char *key = NULL;
461 char *magic = NULL;
462 char *op_id = NULL;
463 char *op_id_additional = NULL;
464 char *local_user_data = NULL;
465 const char *exit_reason = NULL;
466
467 xmlNode *xml_op = NULL;
468 const char *task = NULL;
469 gboolean dc_munges_migrate_ops = (compare_version(caller_version, "3.0.3") < 0);
470 gboolean dc_needs_unique_ops = (compare_version(caller_version, "3.0.6") < 0);
471
472 CRM_CHECK(op != NULL, return NULL);
473 do_crm_log(level, "%s: Updating resource %s after %s op %s (interval=%d)",
474 origin, op->rsc_id, op->op_type, services_lrm_status_str(op->op_status),
475 op->interval);
476
477 crm_trace("DC version: %s", caller_version);
478
479 task = op->op_type;
480
481
482
483 if (crm_str_eq(task, "reload", TRUE)) {
484 if (op->op_status == PCMK_LRM_OP_DONE) {
485 task = CRMD_ACTION_START;
486 } else {
487 task = CRMD_ACTION_STATUS;
488 }
489
490 } else if (dc_munges_migrate_ops && crm_str_eq(task, CRMD_ACTION_MIGRATE, TRUE)) {
491
492 if (op->op_status == PCMK_LRM_OP_DONE) {
493 task = CRMD_ACTION_STOP;
494 } else {
495 task = CRMD_ACTION_STATUS;
496 }
497
498 } else if (dc_munges_migrate_ops
499 && op->op_status == PCMK_LRM_OP_DONE
500 && crm_str_eq(task, CRMD_ACTION_MIGRATED, TRUE)) {
501 task = CRMD_ACTION_START;
502 }
503
504 key = generate_op_key(op->rsc_id, task, op->interval);
505 if (dc_needs_unique_ops && op->interval > 0) {
506 op_id = strdup(key);
507
508 } else if (crm_str_eq(task, CRMD_ACTION_NOTIFY, TRUE)) {
509 const char *n_type = crm_meta_value(op->params, "notify_type");
510 const char *n_task = crm_meta_value(op->params, "notify_operation");
511
512 CRM_LOG_ASSERT(n_type != NULL);
513 CRM_LOG_ASSERT(n_task != NULL);
514 op_id = generate_notify_key(op->rsc_id, n_type, n_task);
515
516
517 op->op_status = PCMK_LRM_OP_DONE;
518 op->rc = 0;
519
520 } else if (did_rsc_op_fail(op, target_rc)) {
521 op_id = generate_op_key(op->rsc_id, "last_failure", 0);
522 if (op->interval == 0) {
523
524 op_id_additional = generate_op_key(op->rsc_id, "last", 0);
525 }
526 exit_reason = op->exit_reason;
527
528 } else if (op->interval > 0) {
529 op_id = strdup(key);
530
531 } else {
532 op_id = generate_op_key(op->rsc_id, "last", 0);
533 }
534
535 again:
536 xml_op = find_entity(parent, XML_LRM_TAG_RSC_OP, op_id);
537 if (xml_op == NULL) {
538 xml_op = create_xml_node(parent, XML_LRM_TAG_RSC_OP);
539 }
540
541 if (op->user_data == NULL) {
542 crm_debug("Generating fake transition key for:"
543 " %s_%s_%d %d from %s",
544 op->rsc_id, op->op_type, op->interval, op->call_id, origin);
545 local_user_data = generate_transition_key(-1, op->call_id, target_rc, FAKE_TE_ID);
546 op->user_data = local_user_data;
547 }
548
549 if(magic == NULL) {
550 magic = generate_transition_magic(op->user_data, op->op_status, op->rc);
551 }
552
553 crm_xml_add(xml_op, XML_ATTR_ID, op_id);
554 crm_xml_add(xml_op, XML_LRM_ATTR_TASK_KEY, key);
555 crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task);
556 crm_xml_add(xml_op, XML_ATTR_ORIGIN, origin);
557 crm_xml_add(xml_op, XML_ATTR_CRM_VERSION, caller_version);
558 crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, op->user_data);
559 crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, magic);
560 crm_xml_add(xml_op, XML_LRM_ATTR_EXIT_REASON, exit_reason == NULL ? "" : exit_reason);
561 crm_xml_add(xml_op, XML_LRM_ATTR_TARGET, node);
562
563 crm_xml_add_int(xml_op, XML_LRM_ATTR_CALLID, op->call_id);
564 crm_xml_add_int(xml_op, XML_LRM_ATTR_RC, op->rc);
565 crm_xml_add_int(xml_op, XML_LRM_ATTR_OPSTATUS, op->op_status);
566 crm_xml_add_int(xml_op, XML_LRM_ATTR_INTERVAL, op->interval);
567
568 if (compare_version("2.1", caller_version) <= 0) {
569 if (op->t_run || op->t_rcchange || op->exec_time || op->queue_time) {
570 crm_trace("Timing data (%s_%s_%d): last=%u change=%u exec=%u queue=%u",
571 op->rsc_id, op->op_type, op->interval,
572 op->t_run, op->t_rcchange, op->exec_time, op->queue_time);
573
574 if (op->interval == 0) {
575
576 crm_xml_add_int(xml_op, XML_RSC_OP_LAST_RUN, op->t_run);
577 crm_xml_add_int(xml_op, XML_RSC_OP_LAST_CHANGE, op->t_run);
578
579 } else if(op->t_rcchange) {
580
581 crm_xml_add_int(xml_op, XML_RSC_OP_LAST_CHANGE, op->t_rcchange);
582
583 } else {
584
585 crm_xml_add_int(xml_op, XML_RSC_OP_LAST_CHANGE, op->t_run);
586 }
587
588 crm_xml_add_int(xml_op, XML_RSC_OP_T_EXEC, op->exec_time);
589 crm_xml_add_int(xml_op, XML_RSC_OP_T_QUEUE, op->queue_time);
590 }
591 }
592
593 if (crm_str_eq(op->op_type, CRMD_ACTION_MIGRATE, TRUE)
594 || crm_str_eq(op->op_type, CRMD_ACTION_MIGRATED, TRUE)) {
595
596
597
598 const char *name = XML_LRM_ATTR_MIGRATE_SOURCE;
599
600 crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
601
602 name = XML_LRM_ATTR_MIGRATE_TARGET;
603 crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
604 }
605
606 append_digest(op, xml_op, caller_version, magic, LOG_DEBUG);
607
608 if (op_id_additional) {
609 free(op_id);
610 op_id = op_id_additional;
611 op_id_additional = NULL;
612 goto again;
613 }
614
615 if (local_user_data) {
616 free(local_user_data);
617 op->user_data = NULL;
618 }
619 free(magic);
620 free(op_id);
621 free(key);
622 return xml_op;
623 }
624
625
626
627
628
629
630
631
632
633
634 bool
635 crm_op_needs_metadata(const char *rsc_class, const char *op)
636 {
637
638
639
640
641
642 CRM_CHECK(rsc_class || op, return FALSE);
643
644 if (rsc_class
645 && strcmp(rsc_class, PCMK_RESOURCE_CLASS_OCF)
646 && strcmp(rsc_class, PCMK_RESOURCE_CLASS_STONITH)) {
647
648
649 return FALSE;
650 }
651
652
653 if (op
654 && strcmp(op, CRMD_ACTION_START)
655 && strcmp(op, CRMD_ACTION_STATUS)
656 && strcmp(op, CRMD_ACTION_PROMOTE)
657 && strcmp(op, CRMD_ACTION_DEMOTE)
658 && strcmp(op, CRMD_ACTION_RELOAD)
659 && strcmp(op, CRMD_ACTION_MIGRATE)
660 && strcmp(op, CRMD_ACTION_MIGRATED)
661 && strcmp(op, CRMD_ACTION_NOTIFY)) {
662 return FALSE;
663 }
664
665 return TRUE;
666 }