This source file includes following definitions.
- rsc2node_new
- can_run_resources
- pcmk__copy_node_table
- pcmk__copy_node_list
- sort_node_weight
- sort_nodes_by_weight
- native_deallocate
- native_assign_node
- log_action
- can_run_any
- create_pseudo_resource_op
- pe_cancel_op
- sched_shutdown_op
- generate_transition_magic
- append_digest
- pcmk__create_history_xml
- pcmk__new_logger
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <crm/msg_xml.h>
12 #include <crm/lrmd.h>
13 #include <crm/common/xml_internal.h>
14 #include <pacemaker-internal.h>
15
16 pe__location_t *
17 rsc2node_new(const char *id, pe_resource_t *rsc,
18 int node_weight, const char *discover_mode,
19 pe_node_t *foo_node, pe_working_set_t *data_set)
20 {
21 pe__location_t *new_con = NULL;
22
23 if (rsc == NULL || id == NULL) {
24 pe_err("Invalid constraint %s for rsc=%p", crm_str(id), rsc);
25 return NULL;
26
27 } else if (foo_node == NULL) {
28 CRM_CHECK(node_weight == 0, return NULL);
29 }
30
31 new_con = calloc(1, sizeof(pe__location_t));
32 if (new_con != NULL) {
33 new_con->id = strdup(id);
34 new_con->rsc_lh = rsc;
35 new_con->node_list_rh = NULL;
36 new_con->role_filter = RSC_ROLE_UNKNOWN;
37
38
39 if (pcmk__str_eq(discover_mode, "always", pcmk__str_null_matches | pcmk__str_casei)) {
40 new_con->discover_mode = pe_discover_always;
41 } else if (pcmk__str_eq(discover_mode, "never", pcmk__str_casei)) {
42 new_con->discover_mode = pe_discover_never;
43 } else if (pcmk__str_eq(discover_mode, "exclusive", pcmk__str_casei)) {
44 new_con->discover_mode = pe_discover_exclusive;
45 rsc->exclusive_discover = TRUE;
46 } else {
47 pe_err("Invalid %s value %s in location constraint", XML_LOCATION_ATTR_DISCOVERY, discover_mode);
48 }
49
50 if (foo_node != NULL) {
51 pe_node_t *copy = pe__copy_node(foo_node);
52
53 copy->weight = node_weight;
54 new_con->node_list_rh = g_list_prepend(NULL, copy);
55 }
56
57 data_set->placement_constraints = g_list_prepend(data_set->placement_constraints, new_con);
58 rsc->rsc_location = g_list_prepend(rsc->rsc_location, new_con);
59 }
60
61 return new_con;
62 }
63
64 gboolean
65 can_run_resources(const pe_node_t * node)
66 {
67 if (node == NULL) {
68 return FALSE;
69 }
70 #if 0
71 if (node->weight < 0) {
72 return FALSE;
73 }
74 #endif
75
76 if (node->details->online == FALSE
77 || node->details->shutdown || node->details->unclean
78 || node->details->standby || node->details->maintenance) {
79 crm_trace("%s: online=%d, unclean=%d, standby=%d, maintenance=%d",
80 node->details->uname, node->details->online,
81 node->details->unclean, node->details->standby, node->details->maintenance);
82 return FALSE;
83 }
84 return TRUE;
85 }
86
87
88
89
90
91
92
93
94
95 GHashTable *
96 pcmk__copy_node_table(GHashTable *nodes)
97 {
98 GHashTable *new_table = NULL;
99 GHashTableIter iter;
100 pe_node_t *node = NULL;
101
102 if (nodes == NULL) {
103 return NULL;
104 }
105 new_table = pcmk__strkey_table(NULL, free);
106 g_hash_table_iter_init(&iter, nodes);
107 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
108 pe_node_t *new_node = pe__copy_node(node);
109
110 g_hash_table_insert(new_table, (gpointer) new_node->details->id,
111 new_node);
112 }
113 return new_table;
114 }
115
116
117
118
119
120
121
122
123
124
125 GList *
126 pcmk__copy_node_list(const GList *list, bool reset)
127 {
128 GList *result = NULL;
129
130 for (const GList *gIter = list; gIter != NULL; gIter = gIter->next) {
131 pe_node_t *new_node = NULL;
132 pe_node_t *this_node = (pe_node_t *) gIter->data;
133
134 new_node = pe__copy_node(this_node);
135 if (reset) {
136 new_node->weight = 0;
137 }
138 result = g_list_prepend(result, new_node);
139 }
140 return result;
141 }
142
143 struct node_weight_s {
144 pe_node_t *active;
145 pe_working_set_t *data_set;
146 };
147
148
149
150
151
152 static gint
153 sort_node_weight(gconstpointer a, gconstpointer b, gpointer data)
154 {
155 const pe_node_t *node1 = (const pe_node_t *)a;
156 const pe_node_t *node2 = (const pe_node_t *)b;
157 struct node_weight_s *nw = data;
158
159 int node1_weight = 0;
160 int node2_weight = 0;
161
162 int result = 0;
163
164 if (a == NULL) {
165 return 1;
166 }
167 if (b == NULL) {
168 return -1;
169 }
170
171 node1_weight = node1->weight;
172 node2_weight = node2->weight;
173
174 if (can_run_resources(node1) == FALSE) {
175 node1_weight = -INFINITY;
176 }
177 if (can_run_resources(node2) == FALSE) {
178 node2_weight = -INFINITY;
179 }
180
181 if (node1_weight > node2_weight) {
182 crm_trace("%s (%d) > %s (%d) : weight",
183 node1->details->uname, node1_weight, node2->details->uname, node2_weight);
184 return -1;
185 }
186
187 if (node1_weight < node2_weight) {
188 crm_trace("%s (%d) < %s (%d) : weight",
189 node1->details->uname, node1_weight, node2->details->uname, node2_weight);
190 return 1;
191 }
192
193 crm_trace("%s (%d) == %s (%d) : weight",
194 node1->details->uname, node1_weight, node2->details->uname, node2_weight);
195
196 if (pcmk__str_eq(nw->data_set->placement_strategy, "minimal", pcmk__str_casei)) {
197 goto equal;
198 }
199
200 if (pcmk__str_eq(nw->data_set->placement_strategy, "balanced", pcmk__str_casei)) {
201 result = compare_capacity(node1, node2);
202 if (result < 0) {
203 crm_trace("%s > %s : capacity (%d)",
204 node1->details->uname, node2->details->uname, result);
205 return -1;
206 } else if (result > 0) {
207 crm_trace("%s < %s : capacity (%d)",
208 node1->details->uname, node2->details->uname, result);
209 return 1;
210 }
211 }
212
213
214 if (node1->details->num_resources < node2->details->num_resources) {
215 crm_trace("%s (%d) > %s (%d) : resources",
216 node1->details->uname, node1->details->num_resources,
217 node2->details->uname, node2->details->num_resources);
218 return -1;
219
220 } else if (node1->details->num_resources > node2->details->num_resources) {
221 crm_trace("%s (%d) < %s (%d) : resources",
222 node1->details->uname, node1->details->num_resources,
223 node2->details->uname, node2->details->num_resources);
224 return 1;
225 }
226
227 if (nw->active && nw->active->details == node1->details) {
228 crm_trace("%s (%d) > %s (%d) : active",
229 node1->details->uname, node1->details->num_resources,
230 node2->details->uname, node2->details->num_resources);
231 return -1;
232 } else if (nw->active && nw->active->details == node2->details) {
233 crm_trace("%s (%d) < %s (%d) : active",
234 node1->details->uname, node1->details->num_resources,
235 node2->details->uname, node2->details->num_resources);
236 return 1;
237 }
238 equal:
239 crm_trace("%s = %s", node1->details->uname, node2->details->uname);
240 return strcmp(node1->details->uname, node2->details->uname);
241 }
242
243 GList *
244 sort_nodes_by_weight(GList *nodes, pe_node_t *active_node,
245 pe_working_set_t *data_set)
246 {
247 struct node_weight_s nw = { active_node, data_set };
248
249 return g_list_sort_with_data(nodes, sort_node_weight, &nw);
250 }
251
252 void
253 native_deallocate(pe_resource_t * rsc)
254 {
255 if (rsc->allocated_to) {
256 pe_node_t *old = rsc->allocated_to;
257
258 crm_info("Deallocating %s from %s", rsc->id, old->details->uname);
259 pe__set_resource_flags(rsc, pe_rsc_provisional);
260 rsc->allocated_to = NULL;
261
262 old->details->allocated_rsc = g_list_remove(old->details->allocated_rsc, rsc);
263 old->details->num_resources--;
264
265 calculate_utilization(old->details->utilization, rsc->utilization, TRUE);
266 free(old);
267 }
268 }
269
270 gboolean
271 native_assign_node(pe_resource_t *rsc, pe_node_t *chosen, gboolean force)
272 {
273 pcmk__output_t *out = rsc->cluster->priv;
274
275 CRM_ASSERT(rsc->variant == pe_native);
276
277 if (force == FALSE && chosen != NULL) {
278 bool unset = FALSE;
279
280 if(chosen->weight < 0) {
281 unset = TRUE;
282
283
284 } else if (!can_run_resources(chosen) && !pe__is_guest_node(chosen)) {
285 unset = TRUE;
286 }
287
288 if(unset) {
289 crm_debug("All nodes for resource %s are unavailable"
290 ", unclean or shutting down (%s: %d, %d)",
291 rsc->id, chosen->details->uname, can_run_resources(chosen), chosen->weight);
292 pe__set_next_role(rsc, RSC_ROLE_STOPPED, "node availability");
293 chosen = NULL;
294 }
295 }
296
297
298
299
300
301 native_deallocate(rsc);
302 pe__clear_resource_flags(rsc, pe_rsc_provisional);
303
304 if (chosen == NULL) {
305 GList *gIter = NULL;
306 char *rc_inactive = pcmk__itoa(PCMK_OCF_NOT_RUNNING);
307
308 crm_debug("Could not allocate a node for %s", rsc->id);
309 pe__set_next_role(rsc, RSC_ROLE_STOPPED, "unable to allocate");
310
311 for (gIter = rsc->actions; gIter != NULL; gIter = gIter->next) {
312 pe_action_t *op = (pe_action_t *) gIter->data;
313 const char *interval_ms_s = g_hash_table_lookup(op->meta, XML_LRM_ATTR_INTERVAL_MS);
314
315 crm_debug("Processing %s", op->uuid);
316 if(pcmk__str_eq(RSC_STOP, op->task, pcmk__str_casei)) {
317 update_action_flags(op, pe_action_optional | pe_action_clear,
318 __func__, __LINE__);
319
320 } else if(pcmk__str_eq(RSC_START, op->task, pcmk__str_casei)) {
321 update_action_flags(op, pe_action_runnable | pe_action_clear,
322 __func__, __LINE__);
323
324
325 } else if (interval_ms_s && !pcmk__str_eq(interval_ms_s, "0", pcmk__str_casei)) {
326 if(pcmk__str_eq(rc_inactive, g_hash_table_lookup(op->meta, XML_ATTR_TE_TARGET_RC), pcmk__str_casei)) {
327
328
329 } else {
330
331 update_action_flags(op, pe_action_runnable | pe_action_clear,
332 __func__, __LINE__);
333 }
334 }
335 }
336
337 free(rc_inactive);
338 return FALSE;
339 }
340
341 crm_debug("Assigning %s to %s", chosen->details->uname, rsc->id);
342 rsc->allocated_to = pe__copy_node(chosen);
343
344 chosen->details->allocated_rsc = g_list_prepend(chosen->details->allocated_rsc, rsc);
345 chosen->details->num_resources++;
346 chosen->count++;
347 calculate_utilization(chosen->details->utilization, rsc->utilization, FALSE);
348
349 if (pcmk_is_set(rsc->cluster->flags, pe_flag_show_utilization)) {
350 out->message(out, "resource-util", rsc, chosen, __func__);
351 }
352
353 return TRUE;
354 }
355
356 void
357 log_action(unsigned int log_level, const char *pre_text, pe_action_t * action, gboolean details)
358 {
359 const char *node_uname = NULL;
360 const char *node_uuid = NULL;
361 const char *desc = NULL;
362
363 if (action == NULL) {
364 crm_trace("%s%s: <NULL>", pre_text == NULL ? "" : pre_text, pre_text == NULL ? "" : ": ");
365 return;
366 }
367
368 if (pcmk_is_set(action->flags, pe_action_pseudo)) {
369 node_uname = NULL;
370 node_uuid = NULL;
371
372 } else if (action->node != NULL) {
373 node_uname = action->node->details->uname;
374 node_uuid = action->node->details->id;
375 } else {
376 node_uname = "<none>";
377 node_uuid = NULL;
378 }
379
380 switch (text2task(action->task)) {
381 case stonith_node:
382 case shutdown_crm:
383 if (pcmk_is_set(action->flags, pe_action_pseudo)) {
384 desc = "Pseudo ";
385 } else if (pcmk_is_set(action->flags, pe_action_optional)) {
386 desc = "Optional ";
387 } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
388 desc = "!!Non-Startable!! ";
389 } else if (pcmk_is_set(action->flags, pe_action_processed)) {
390 desc = "";
391 } else {
392 desc = "(Provisional) ";
393 }
394 crm_trace("%s%s%sAction %d: %s%s%s%s%s%s",
395 ((pre_text == NULL)? "" : pre_text),
396 ((pre_text == NULL)? "" : ": "),
397 desc, action->id, action->uuid,
398 (node_uname? "\ton " : ""), (node_uname? node_uname : ""),
399 (node_uuid? "\t\t(" : ""), (node_uuid? node_uuid : ""),
400 (node_uuid? ")" : ""));
401 break;
402 default:
403 if (pcmk_is_set(action->flags, pe_action_optional)) {
404 desc = "Optional ";
405 } else if (pcmk_is_set(action->flags, pe_action_pseudo)) {
406 desc = "Pseudo ";
407 } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
408 desc = "!!Non-Startable!! ";
409 } else if (pcmk_is_set(action->flags, pe_action_processed)) {
410 desc = "";
411 } else {
412 desc = "(Provisional) ";
413 }
414 crm_trace("%s%s%sAction %d: %s %s%s%s%s%s%s",
415 ((pre_text == NULL)? "" : pre_text),
416 ((pre_text == NULL)? "" : ": "),
417 desc, action->id, action->uuid,
418 (action->rsc? action->rsc->id : "<none>"),
419 (node_uname? "\ton " : ""), (node_uname? node_uname : ""),
420 (node_uuid? "\t\t(" : ""), (node_uuid? node_uuid : ""),
421 (node_uuid? ")" : ""));
422 break;
423 }
424
425 if (details) {
426 GList *gIter = NULL;
427
428 crm_trace("\t\t====== Preceding Actions");
429
430 gIter = action->actions_before;
431 for (; gIter != NULL; gIter = gIter->next) {
432 pe_action_wrapper_t *other = (pe_action_wrapper_t *) gIter->data;
433
434 log_action(log_level + 1, "\t\t", other->action, FALSE);
435 }
436
437 crm_trace("\t\t====== Subsequent Actions");
438
439 gIter = action->actions_after;
440 for (; gIter != NULL; gIter = gIter->next) {
441 pe_action_wrapper_t *other = (pe_action_wrapper_t *) gIter->data;
442
443 log_action(log_level + 1, "\t\t", other->action, FALSE);
444 }
445
446 crm_trace("\t\t====== End");
447
448 } else {
449 crm_trace("\t\t(before=%d, after=%d)",
450 g_list_length(action->actions_before), g_list_length(action->actions_after));
451 }
452 }
453
454 gboolean
455 can_run_any(GHashTable * nodes)
456 {
457 GHashTableIter iter;
458 pe_node_t *node = NULL;
459
460 if (nodes == NULL) {
461 return FALSE;
462 }
463
464 g_hash_table_iter_init(&iter, nodes);
465 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
466 if (can_run_resources(node) && node->weight >= 0) {
467 return TRUE;
468 }
469 }
470
471 return FALSE;
472 }
473
474 pe_action_t *
475 create_pseudo_resource_op(pe_resource_t * rsc, const char *task, bool optional, bool runnable, pe_working_set_t *data_set)
476 {
477 pe_action_t *action = custom_action(rsc, pcmk__op_key(rsc->id, task, 0),
478 task, NULL, optional, TRUE, data_set);
479 update_action_flags(action, pe_action_pseudo, __func__, __LINE__);
480 update_action_flags(action, pe_action_runnable, __func__, __LINE__);
481 if(runnable) {
482 update_action_flags(action, pe_action_runnable, __func__, __LINE__);
483 }
484 return action;
485 }
486
487
488
489
490
491
492
493
494
495
496
497
498
499 pe_action_t *
500 pe_cancel_op(pe_resource_t *rsc, const char *task, guint interval_ms,
501 pe_node_t *node, pe_working_set_t *data_set)
502 {
503 pe_action_t *cancel_op;
504 char *interval_ms_s = crm_strdup_printf("%u", interval_ms);
505
506
507 char *key = pcmk__op_key(rsc->id, task, interval_ms);
508
509 cancel_op = custom_action(rsc, key, RSC_CANCEL, node, FALSE, TRUE,
510 data_set);
511
512 free(cancel_op->task);
513 cancel_op->task = strdup(RSC_CANCEL);
514
515 free(cancel_op->cancel_task);
516 cancel_op->cancel_task = strdup(task);
517
518 add_hash_param(cancel_op->meta, XML_LRM_ATTR_TASK, task);
519 add_hash_param(cancel_op->meta, XML_LRM_ATTR_INTERVAL_MS, interval_ms_s);
520 free(interval_ms_s);
521
522 return cancel_op;
523 }
524
525
526
527
528
529
530
531
532
533
534 pe_action_t *
535 sched_shutdown_op(pe_node_t *node, pe_working_set_t *data_set)
536 {
537 char *shutdown_id = crm_strdup_printf("%s-%s", CRM_OP_SHUTDOWN,
538 node->details->uname);
539
540 pe_action_t *shutdown_op = custom_action(NULL, shutdown_id, CRM_OP_SHUTDOWN,
541 node, FALSE, TRUE, data_set);
542
543 crm_notice("Scheduling shutdown of node %s", node->details->uname);
544 shutdown_constraints(node, shutdown_op, data_set);
545 add_hash_param(shutdown_op->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE);
546 return shutdown_op;
547 }
548
549 static char *
550 generate_transition_magic(const char *transition_key, int op_status, int op_rc)
551 {
552 CRM_CHECK(transition_key != NULL, return NULL);
553 return crm_strdup_printf("%d:%d;%s", op_status, op_rc, transition_key);
554 }
555
556 static void
557 append_digest(lrmd_event_data_t *op, xmlNode *update, const char *version,
558 const char *magic, int level)
559 {
560
561
562
563
564 char *digest = NULL;
565 xmlNode *args_xml = NULL;
566
567 if (op->params == NULL) {
568 return;
569 }
570
571 args_xml = create_xml_node(NULL, XML_TAG_PARAMS);
572 g_hash_table_foreach(op->params, hash2field, args_xml);
573 pcmk__filter_op_for_digest(args_xml);
574 digest = calculate_operation_digest(args_xml, version);
575
576 #if 0
577 if (level < get_crm_log_level()
578 && op->interval_ms == 0 && pcmk__str_eq(op->op_type, CRMD_ACTION_START, pcmk__str_none)) {
579 char *digest_source = dump_xml_unformatted(args_xml);
580
581 do_crm_log(level, "Calculated digest %s for %s (%s). Source: %s\n",
582 digest, ID(update), magic, digest_source);
583 free(digest_source);
584 }
585 #endif
586 crm_xml_add(update, XML_LRM_ATTR_OP_DIGEST, digest);
587
588 free_xml(args_xml);
589 free(digest);
590 }
591
592 #define FAKE_TE_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608 xmlNode *
609 pcmk__create_history_xml(xmlNode *parent, lrmd_event_data_t *op,
610 const char *caller_version, int target_rc,
611 const char *node, const char *origin, int level)
612 {
613 char *key = NULL;
614 char *magic = NULL;
615 char *op_id = NULL;
616 char *op_id_additional = NULL;
617 char *local_user_data = NULL;
618 const char *exit_reason = NULL;
619
620 xmlNode *xml_op = NULL;
621 const char *task = NULL;
622
623 CRM_CHECK(op != NULL, return NULL);
624 do_crm_log(level, "%s: Updating resource %s after %s op %s (interval=%u)",
625 origin, op->rsc_id, op->op_type, services_lrm_status_str(op->op_status),
626 op->interval_ms);
627
628 crm_trace("DC version: %s", caller_version);
629
630 task = op->op_type;
631
632
633
634
635
636
637
638
639
640
641 if (pcmk__str_any_of(task, CRMD_ACTION_RELOAD, CRMD_ACTION_RELOAD_AGENT,
642 NULL)) {
643 if (op->op_status == PCMK_LRM_OP_DONE) {
644 task = CRMD_ACTION_START;
645 } else {
646 task = CRMD_ACTION_STATUS;
647 }
648 }
649
650 key = pcmk__op_key(op->rsc_id, task, op->interval_ms);
651 if (pcmk__str_eq(task, CRMD_ACTION_NOTIFY, pcmk__str_none)) {
652 const char *n_type = crm_meta_value(op->params, "notify_type");
653 const char *n_task = crm_meta_value(op->params, "notify_operation");
654
655 CRM_LOG_ASSERT(n_type != NULL);
656 CRM_LOG_ASSERT(n_task != NULL);
657 op_id = pcmk__notify_key(op->rsc_id, n_type, n_task);
658
659 if (op->op_status != PCMK_LRM_OP_PENDING) {
660
661
662
663
664
665 op->op_status = PCMK_LRM_OP_DONE;
666 op->rc = 0;
667 }
668
669 } else if (did_rsc_op_fail(op, target_rc)) {
670 op_id = pcmk__op_key(op->rsc_id, "last_failure", 0);
671 if (op->interval_ms == 0) {
672
673 op_id_additional = pcmk__op_key(op->rsc_id, "last", 0);
674 }
675 exit_reason = op->exit_reason;
676
677 } else if (op->interval_ms > 0) {
678 op_id = strdup(key);
679
680 } else {
681 op_id = pcmk__op_key(op->rsc_id, "last", 0);
682 }
683
684 again:
685 xml_op = pcmk__xe_match(parent, XML_LRM_TAG_RSC_OP, XML_ATTR_ID, op_id);
686 if (xml_op == NULL) {
687 xml_op = create_xml_node(parent, XML_LRM_TAG_RSC_OP);
688 }
689
690 if (op->user_data == NULL) {
691 crm_debug("Generating fake transition key for: " PCMK__OP_FMT
692 " %d from %s", op->rsc_id, op->op_type, op->interval_ms,
693 op->call_id, origin);
694 local_user_data = pcmk__transition_key(-1, op->call_id, target_rc,
695 FAKE_TE_ID);
696 op->user_data = local_user_data;
697 }
698
699 if(magic == NULL) {
700 magic = generate_transition_magic(op->user_data, op->op_status, op->rc);
701 }
702
703 crm_xml_add(xml_op, XML_ATTR_ID, op_id);
704 crm_xml_add(xml_op, XML_LRM_ATTR_TASK_KEY, key);
705 crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task);
706 crm_xml_add(xml_op, XML_ATTR_ORIGIN, origin);
707 crm_xml_add(xml_op, XML_ATTR_CRM_VERSION, caller_version);
708 crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, op->user_data);
709 crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, magic);
710 crm_xml_add(xml_op, XML_LRM_ATTR_EXIT_REASON, exit_reason == NULL ? "" : exit_reason);
711 crm_xml_add(xml_op, XML_LRM_ATTR_TARGET, node);
712
713 crm_xml_add_int(xml_op, XML_LRM_ATTR_CALLID, op->call_id);
714 crm_xml_add_int(xml_op, XML_LRM_ATTR_RC, op->rc);
715 crm_xml_add_int(xml_op, XML_LRM_ATTR_OPSTATUS, op->op_status);
716 crm_xml_add_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, op->interval_ms);
717
718 if (compare_version("2.1", caller_version) <= 0) {
719 if (op->t_run || op->t_rcchange || op->exec_time || op->queue_time) {
720 crm_trace("Timing data (" PCMK__OP_FMT
721 "): last=%u change=%u exec=%u queue=%u",
722 op->rsc_id, op->op_type, op->interval_ms,
723 op->t_run, op->t_rcchange, op->exec_time, op->queue_time);
724
725 if ((op->interval_ms != 0) && (op->t_rcchange != 0)) {
726
727 crm_xml_add_ll(xml_op, XML_RSC_OP_LAST_CHANGE,
728 (long long) op->t_rcchange);
729 } else {
730 crm_xml_add_ll(xml_op, XML_RSC_OP_LAST_CHANGE,
731 (long long) op->t_run);
732 }
733
734 crm_xml_add_int(xml_op, XML_RSC_OP_T_EXEC, op->exec_time);
735 crm_xml_add_int(xml_op, XML_RSC_OP_T_QUEUE, op->queue_time);
736 }
737 }
738
739 if (pcmk__str_any_of(op->op_type, CRMD_ACTION_MIGRATE, CRMD_ACTION_MIGRATED, NULL)) {
740
741
742
743 const char *name = XML_LRM_ATTR_MIGRATE_SOURCE;
744
745 crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
746
747 name = XML_LRM_ATTR_MIGRATE_TARGET;
748 crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
749 }
750
751 append_digest(op, xml_op, caller_version, magic, LOG_DEBUG);
752
753 if (op_id_additional) {
754 free(op_id);
755 op_id = op_id_additional;
756 op_id_additional = NULL;
757 goto again;
758 }
759
760 if (local_user_data) {
761 free(local_user_data);
762 op->user_data = NULL;
763 }
764 free(magic);
765 free(op_id);
766 free(key);
767 return xml_op;
768 }
769
770 pcmk__output_t *
771 pcmk__new_logger(void)
772 {
773 int rc = pcmk_rc_ok;
774 pcmk__output_t *out = NULL;
775 const char* argv[] = { "", NULL };
776 pcmk__supported_format_t formats[] = {
777 PCMK__SUPPORTED_FORMAT_LOG,
778 { NULL, NULL, NULL }
779 };
780
781 pcmk__register_formats(NULL, formats);
782 rc = pcmk__output_new(&out, "log", NULL, (char**)argv);
783 if ((rc != pcmk_rc_ok) || (out == NULL)) {
784 crm_err("Can't log resource details due to internal error: %s\n",
785 pcmk_rc_str(rc));
786 return NULL;
787 }
788
789 pe__register_messages(out);
790 pcmk__register_lib_messages(out);
791 return out;
792 }