This source file includes following definitions.
- add_node_to_xml_by_id
 
- add_node_to_xml
 
- add_maintenance_nodes
 
- add_maintenance_update
 
- add_downed_nodes
 
- clone_op_key
 
- add_node_details
 
- add_resource_details
 
- add_action_attributes
 
- create_graph_action
 
- should_add_action_to_graph
 
- ordering_can_change_actions
 
- should_add_input_to_graph
 
- pcmk__graph_has_loop
 
- create_graph_synapse
 
- add_action_to_graph
 
- pcmk__log_transition_summary
 
- pcmk__add_rsc_actions_to_graph
 
- pcmk__create_graph
 
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <sys/param.h>
  13 #include <crm/crm.h>
  14 #include <crm/cib.h>
  15 #include <crm/common/xml.h>
  16 
  17 #include <glib.h>
  18 
  19 #include <pacemaker-internal.h>
  20 
  21 #include "libpacemaker_private.h"
  22 
  23 
  24 
  25 #define action_type_str(flags) \
  26     (pcmk_is_set((flags), pcmk_action_pseudo)? "pseudo-action" : "action")
  27 
  28 #define action_optional_str(flags) \
  29     (pcmk_is_set((flags), pcmk_action_optional)? "optional" : "required")
  30 
  31 #define action_runnable_str(flags) \
  32     (pcmk_is_set((flags), pcmk_action_runnable)? "runnable" : "unrunnable")
  33 
  34 #define action_node_str(a) \
  35     (((a)->node == NULL)? "no node" : (a)->node->details->uname)
  36 
  37 
  38 
  39 
  40 
  41 
  42 
  43 
  44 static xmlNode*
  45 add_node_to_xml_by_id(const char *id, xmlNode *xml)
     
  46 {
  47     xmlNode *node_xml;
  48 
  49     node_xml = pcmk__xe_create(xml, PCMK_XE_NODE);
  50     crm_xml_add(node_xml, PCMK_XA_ID, id);
  51 
  52     return node_xml;
  53 }
  54 
  55 
  56 
  57 
  58 
  59 
  60 
  61 
  62 static void
  63 add_node_to_xml(const pcmk_node_t *node, void *xml)
     
  64 {
  65     add_node_to_xml_by_id(node->details->id, (xmlNode *) xml);
  66 }
  67 
  68 
  69 
  70 
  71 
  72 
  73 
  74 
  75 
  76 
  77 
  78 static int
  79 add_maintenance_nodes(xmlNode *xml, const pcmk_scheduler_t *scheduler)
     
  80 {
  81     xmlNode *maintenance = NULL;
  82     int count = 0;
  83 
  84     if (xml != NULL) {
  85         maintenance = pcmk__xe_create(xml, PCMK__XE_MAINTENANCE);
  86     }
  87     for (const GList *iter = scheduler->nodes;
  88          iter != NULL; iter = iter->next) {
  89         const pcmk_node_t *node = iter->data;
  90 
  91         if (pcmk__is_pacemaker_remote_node(node) &&
  92             (node->details->maintenance != node->details->remote_maintenance)) {
  93 
  94             if (maintenance != NULL) {
  95                 crm_xml_add(add_node_to_xml_by_id(node->details->id,
  96                                                   maintenance),
  97                             PCMK__XA_NODE_IN_MAINTENANCE,
  98                             (node->details->maintenance? "1" : "0"));
  99             }
 100             count++;
 101         }
 102     }
 103     crm_trace("%s %d nodes in need of maintenance mode update in state",
 104               ((maintenance == NULL)? "Counted" : "Added"), count);
 105     return count;
 106 }
 107 
 108 
 109 
 110 
 111 
 112 
 113 
 114 static void
 115 add_maintenance_update(pcmk_scheduler_t *scheduler)
     
 116 {
 117     pcmk_action_t *action = NULL;
 118 
 119     if (add_maintenance_nodes(NULL, scheduler) != 0) {
 120         action = get_pseudo_op(PCMK_ACTION_MAINTENANCE_NODES, scheduler);
 121         pcmk__set_action_flags(action, pcmk_action_always_in_graph);
 122     }
 123 }
 124 
 125 
 126 
 127 
 128 
 129 
 130 
 131 
 132 
 133 
 134 
 135 
 136 static void
 137 add_downed_nodes(xmlNode *xml, const pcmk_action_t *action)
     
 138 {
 139     CRM_CHECK((xml != NULL) && (action != NULL) && (action->node != NULL),
 140               return);
 141 
 142     if (pcmk__str_eq(action->task, PCMK_ACTION_DO_SHUTDOWN, pcmk__str_none)) {
 143 
 144         
 145         xmlNode *downed = pcmk__xe_create(xml, PCMK__XE_DOWNED);
 146         add_node_to_xml_by_id(action->node->details->id, downed);
 147 
 148     } else if (pcmk__str_eq(action->task, PCMK_ACTION_STONITH,
 149                             pcmk__str_none)) {
 150 
 151         
 152         const char *fence = g_hash_table_lookup(action->meta,
 153                                                 PCMK__META_STONITH_ACTION);
 154 
 155         if (pcmk__is_fencing_action(fence)) {
 156             xmlNode *downed = pcmk__xe_create(xml, PCMK__XE_DOWNED);
 157             add_node_to_xml_by_id(action->node->details->id, downed);
 158             pe_foreach_guest_node(action->node->details->data_set,
 159                                   action->node, add_node_to_xml, downed);
 160         }
 161 
 162     } else if (action->rsc && action->rsc->is_remote_node
 163                && pcmk__str_eq(action->task, PCMK_ACTION_STOP,
 164                                pcmk__str_none)) {
 165 
 166         
 167 
 168 
 169         GList *iter;
 170         pcmk_action_t *input;
 171         bool migrating = false;
 172 
 173         for (iter = action->actions_before; iter != NULL; iter = iter->next) {
 174             input = ((pcmk__related_action_t *) iter->data)->action;
 175             if ((input->rsc != NULL)
 176                 && pcmk__str_eq(action->rsc->id, input->rsc->id, pcmk__str_none)
 177                 && pcmk__str_eq(input->task, PCMK_ACTION_MIGRATE_FROM,
 178                                 pcmk__str_none)) {
 179                 migrating = true;
 180                 break;
 181             }
 182         }
 183         if (!migrating) {
 184             xmlNode *downed = pcmk__xe_create(xml, PCMK__XE_DOWNED);
 185             add_node_to_xml_by_id(action->rsc->id, downed);
 186         }
 187     }
 188 }
 189 
 190 
 191 
 192 
 193 
 194 
 195 
 196 
 197 
 198 
 199 static char *
 200 clone_op_key(const pcmk_action_t *action, guint interval_ms)
     
 201 {
 202     if (pcmk__str_eq(action->task, PCMK_ACTION_NOTIFY, pcmk__str_none)) {
 203         const char *n_type = g_hash_table_lookup(action->meta, "notify_type");
 204         const char *n_task = g_hash_table_lookup(action->meta,
 205                                                  "notify_operation");
 206 
 207         CRM_LOG_ASSERT((n_type != NULL) && (n_task != NULL));
 208         return pcmk__notify_key(action->rsc->clone_name, n_type, n_task);
 209 
 210     } else if (action->cancel_task != NULL) {
 211         return pcmk__op_key(action->rsc->clone_name, action->cancel_task,
 212                             interval_ms);
 213     } else {
 214         return pcmk__op_key(action->rsc->clone_name, action->task, interval_ms);
 215     }
 216 }
 217 
 218 
 219 
 220 
 221 
 222 
 223 
 224 
 225 static void
 226 add_node_details(const pcmk_action_t *action, xmlNode *xml)
     
 227 {
 228     pcmk_node_t *router_node = pcmk__connection_host_for_action(action);
 229 
 230     crm_xml_add(xml, PCMK__META_ON_NODE, action->node->details->uname);
 231     crm_xml_add(xml, PCMK__META_ON_NODE_UUID, action->node->details->id);
 232     if (router_node != NULL) {
 233         crm_xml_add(xml, PCMK__XA_ROUTER_NODE, router_node->details->uname);
 234     }
 235 }
 236 
 237 
 238 
 239 
 240 
 241 
 242 
 243 
 244 static void
 245 add_resource_details(const pcmk_action_t *action, xmlNode *action_xml)
     
 246 {
 247     xmlNode *rsc_xml = NULL;
 248     const char *attr_list[] = {
 249         PCMK_XA_CLASS,
 250         PCMK_XA_PROVIDER,
 251         PCMK_XA_TYPE,
 252     };
 253 
 254     
 255 
 256 
 257 
 258     if (pcmk__action_locks_rsc_to_node(action)) {
 259         crm_xml_add_ll(action_xml, PCMK_OPT_SHUTDOWN_LOCK,
 260                        (long long) action->rsc->lock_time);
 261     }
 262 
 263     
 264 
 265     rsc_xml = pcmk__xe_create(action_xml,
 266                               (const char *) action->rsc->xml->name);
 267     if (pcmk_is_set(action->rsc->flags, pcmk_rsc_removed)
 268         && (action->rsc->clone_name != NULL)) {
 269         
 270 
 271 
 272 
 273 
 274 
 275 
 276 
 277         crm_debug("Using orphan clone name %s instead of %s",
 278                   action->rsc->id, action->rsc->clone_name);
 279         crm_xml_add(rsc_xml, PCMK_XA_ID, action->rsc->clone_name);
 280         crm_xml_add(rsc_xml, PCMK__XA_LONG_ID, action->rsc->id);
 281 
 282     } else if (!pcmk_is_set(action->rsc->flags, pcmk_rsc_unique)) {
 283         const char *xml_id = pcmk__xe_id(action->rsc->xml);
 284 
 285         crm_debug("Using anonymous clone name %s for %s (aka %s)",
 286                   xml_id, action->rsc->id, action->rsc->clone_name);
 287 
 288         
 289 
 290 
 291 
 292 
 293 
 294 
 295 
 296 
 297 
 298 
 299 
 300 
 301         crm_xml_add(rsc_xml, PCMK_XA_ID, xml_id);
 302         if ((action->rsc->clone_name != NULL)
 303             && !pcmk__str_eq(xml_id, action->rsc->clone_name,
 304                              pcmk__str_none)) {
 305             crm_xml_add(rsc_xml, PCMK__XA_LONG_ID, action->rsc->clone_name);
 306         } else {
 307             crm_xml_add(rsc_xml, PCMK__XA_LONG_ID, action->rsc->id);
 308         }
 309 
 310     } else {
 311         CRM_ASSERT(action->rsc->clone_name == NULL);
 312         crm_xml_add(rsc_xml, PCMK_XA_ID, action->rsc->id);
 313     }
 314 
 315     for (int lpc = 0; lpc < PCMK__NELEM(attr_list); lpc++) {
 316         crm_xml_add(rsc_xml, attr_list[lpc],
 317                     g_hash_table_lookup(action->rsc->meta, attr_list[lpc]));
 318     }
 319 }
 320 
 321 
 322 
 323 
 324 
 325 
 326 
 327 
 328 static void
 329 add_action_attributes(pcmk_action_t *action, xmlNode *action_xml)
     
 330 {
 331     xmlNode *args_xml = NULL;
 332 
 333     
 334 
 335 
 336 
 337     args_xml = pcmk__xe_create(NULL, PCMK__XE_ATTRIBUTES);
 338 
 339     crm_xml_add(args_xml, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET);
 340     g_hash_table_foreach(action->extra, hash2field, args_xml);
 341 
 342     if ((action->rsc != NULL) && (action->node != NULL)) {
 343         
 344         GHashTable *params = pe_rsc_params(action->rsc, action->node,
 345                                            action->rsc->cluster);
 346 
 347         pcmk__substitute_remote_addr(action->rsc, params);
 348 
 349         g_hash_table_foreach(params, hash2smartfield, args_xml);
 350 
 351     } else if ((action->rsc != NULL)
 352                && (action->rsc->variant <= pcmk_rsc_variant_primitive)) {
 353         GHashTable *params = pe_rsc_params(action->rsc, NULL,
 354                                            action->rsc->cluster);
 355 
 356         g_hash_table_foreach(params, hash2smartfield, args_xml);
 357     }
 358 
 359     g_hash_table_foreach(action->meta, hash2metafield, args_xml);
 360     if (action->rsc != NULL) {
 361         pcmk_resource_t *parent = action->rsc;
 362 
 363         while (parent != NULL) {
 364             parent->cmds->add_graph_meta(parent, args_xml);
 365             parent = parent->parent;
 366         }
 367 
 368         pcmk__add_guest_meta_to_xml(args_xml, action);
 369 
 370     } else if (pcmk__str_eq(action->task, PCMK_ACTION_STONITH, pcmk__str_none)
 371                && (action->node != NULL)) {
 372         
 373 
 374 
 375 
 376 
 377 
 378         g_hash_table_foreach(action->node->details->attrs, hash2metafield,
 379                              args_xml);
 380     }
 381 
 382     sorted_xml(args_xml, action_xml, FALSE);
 383     free_xml(args_xml);
 384 }
 385 
 386 
 387 
 388 
 389 
 390 
 391 
 392 
 393 
 394 
 395 static void
 396 create_graph_action(xmlNode *parent, pcmk_action_t *action, bool skip_details,
     
 397                     const pcmk_scheduler_t *scheduler)
 398 {
 399     bool needs_node_info = true;
 400     bool needs_maintenance_info = false;
 401     xmlNode *action_xml = NULL;
 402 
 403     if ((action == NULL) || (scheduler == NULL)) {
 404         return;
 405     }
 406 
 407     
 408 
 409     if (pcmk__str_eq(action->task, PCMK_ACTION_STONITH, pcmk__str_none)) {
 410         
 411         if (pcmk_is_set(action->flags, pcmk_action_pseudo)) {
 412             action_xml = pcmk__xe_create(parent, PCMK__XE_PSEUDO_EVENT);
 413         } else {
 414             action_xml = pcmk__xe_create(parent, PCMK__XE_CRM_EVENT);
 415         }
 416 
 417     } else if (pcmk__str_any_of(action->task,
 418                                 PCMK_ACTION_DO_SHUTDOWN,
 419                                 PCMK_ACTION_CLEAR_FAILCOUNT, NULL)) {
 420         action_xml = pcmk__xe_create(parent, PCMK__XE_CRM_EVENT);
 421 
 422     } else if (pcmk__str_eq(action->task, PCMK_ACTION_LRM_DELETE,
 423                             pcmk__str_none)) {
 424         
 425         action_xml = pcmk__xe_create(parent, PCMK__XE_CRM_EVENT);
 426         crm_xml_add(action_xml, PCMK__XA_MODE, PCMK__VALUE_CIB);
 427 
 428     } else if (pcmk_is_set(action->flags, pcmk_action_pseudo)) {
 429         if (pcmk__str_eq(action->task, PCMK_ACTION_MAINTENANCE_NODES,
 430                          pcmk__str_none)) {
 431             needs_maintenance_info = true;
 432         }
 433         action_xml = pcmk__xe_create(parent, PCMK__XE_PSEUDO_EVENT);
 434         needs_node_info = false;
 435 
 436     } else {
 437         action_xml = pcmk__xe_create(parent, PCMK__XE_RSC_OP);
 438     }
 439 
 440     crm_xml_add_int(action_xml, PCMK_XA_ID, action->id);
 441     crm_xml_add(action_xml, PCMK_XA_OPERATION, action->task);
 442 
 443     if ((action->rsc != NULL) && (action->rsc->clone_name != NULL)) {
 444         char *clone_key = NULL;
 445         guint interval_ms;
 446 
 447         if (pcmk__guint_from_hash(action->meta, PCMK_META_INTERVAL, 0,
 448                                   &interval_ms) != pcmk_rc_ok) {
 449             interval_ms = 0;
 450         }
 451         clone_key = clone_op_key(action, interval_ms);
 452         crm_xml_add(action_xml, PCMK__XA_OPERATION_KEY, clone_key);
 453         crm_xml_add(action_xml, "internal_" PCMK__XA_OPERATION_KEY,
 454                     action->uuid);
 455         free(clone_key);
 456     } else {
 457         crm_xml_add(action_xml, PCMK__XA_OPERATION_KEY, action->uuid);
 458     }
 459 
 460     if (needs_node_info && (action->node != NULL)) {
 461         add_node_details(action, action_xml);
 462         pcmk__insert_dup(action->meta, PCMK__META_ON_NODE,
 463                          action->node->details->uname);
 464         pcmk__insert_dup(action->meta, PCMK__META_ON_NODE_UUID,
 465                          action->node->details->id);
 466     }
 467 
 468     if (skip_details) {
 469         return;
 470     }
 471 
 472     if ((action->rsc != NULL)
 473         && !pcmk_is_set(action->flags, pcmk_action_pseudo)) {
 474 
 475         
 476         add_resource_details(action, action_xml);
 477     }
 478 
 479     
 480     add_action_attributes(action, action_xml);
 481 
 482     
 483     if (needs_node_info && (action->node != NULL)) {
 484         add_downed_nodes(action_xml, action);
 485     }
 486 
 487     if (needs_maintenance_info) {
 488         add_maintenance_nodes(action_xml, scheduler);
 489     }
 490 }
 491 
 492 
 493 
 494 
 495 
 496 
 497 
 498 
 499 
 500 static bool
 501 should_add_action_to_graph(const pcmk_action_t *action)
     
 502 {
 503     if (!pcmk_is_set(action->flags, pcmk_action_runnable)) {
 504         crm_trace("Ignoring action %s (%d): unrunnable",
 505                   action->uuid, action->id);
 506         return false;
 507     }
 508 
 509     if (pcmk_is_set(action->flags, pcmk_action_optional)
 510         && !pcmk_is_set(action->flags, pcmk_action_always_in_graph)) {
 511         crm_trace("Ignoring action %s (%d): optional",
 512                   action->uuid, action->id);
 513         return false;
 514     }
 515 
 516     
 517 
 518 
 519     if ((action->rsc != NULL)
 520         && !pcmk_is_set(action->rsc->flags, pcmk_rsc_managed)
 521         && !pcmk__str_eq(action->task, PCMK_ACTION_MONITOR, pcmk__str_none)) {
 522 
 523         const char *interval_ms_s;
 524 
 525         
 526 
 527 
 528 
 529 
 530         interval_ms_s = g_hash_table_lookup(action->meta, PCMK_META_INTERVAL);
 531         if (pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches)) {
 532             crm_trace("Ignoring action %s (%d): for unmanaged resource (%s)",
 533                       action->uuid, action->id, action->rsc->id);
 534             return false;
 535         }
 536     }
 537 
 538     
 539 
 540 
 541     if (pcmk_is_set(action->flags, pcmk_action_pseudo)
 542         || pcmk__strcase_any_of(action->task, PCMK_ACTION_STONITH,
 543                                 PCMK_ACTION_DO_SHUTDOWN, NULL)) {
 544         return true;
 545     }
 546 
 547     if (action->node == NULL) {
 548         pcmk__sched_err("Skipping action %s (%d) "
 549                         "because it was not assigned to a node (bug?)",
 550                         action->uuid, action->id);
 551         pcmk__log_action("Unassigned", action, false);
 552         return false;
 553     }
 554 
 555     if (pcmk_is_set(action->flags, pcmk_action_on_dc)) {
 556         crm_trace("Action %s (%d) should be dumped: "
 557                   "can run on DC instead of %s",
 558                   action->uuid, action->id, pcmk__node_name(action->node));
 559 
 560     } else if (pcmk__is_guest_or_bundle_node(action->node)
 561                && !action->node->details->remote_requires_reset) {
 562         crm_trace("Action %s (%d) should be dumped: "
 563                   "assuming will be runnable on guest %s",
 564                   action->uuid, action->id, pcmk__node_name(action->node));
 565 
 566     } else if (!action->node->details->online) {
 567         pcmk__sched_err("Skipping action %s (%d) "
 568                         "because it was scheduled for offline node (bug?)",
 569                         action->uuid, action->id);
 570         pcmk__log_action("Offline node", action, false);
 571         return false;
 572 
 573     } else if (action->node->details->unclean) {
 574         pcmk__sched_err("Skipping action %s (%d) "
 575                         "because it was scheduled for unclean node (bug?)",
 576                         action->uuid, action->id);
 577         pcmk__log_action("Unclean node", action, false);
 578         return false;
 579     }
 580     return true;
 581 }
 582 
 583 
 584 
 585 
 586 
 587 
 588 
 589 
 590 
 591 static bool
 592 ordering_can_change_actions(const pcmk__related_action_t *ordering)
     
 593 {
 594     return pcmk_any_flags_set(ordering->type,
 595                               ~(pcmk__ar_then_implies_first_graphed
 596                                 |pcmk__ar_first_implies_then_graphed
 597                                 |pcmk__ar_ordered));
 598 }
 599 
 600 
 601 
 602 
 603 
 604 
 605 
 606 
 607 
 608 
 609 
 610 
 611 static bool
 612 should_add_input_to_graph(const pcmk_action_t *action,
     
 613                           pcmk__related_action_t *input)
 614 {
 615     if (input->state == pe_link_dumped) {
 616         return true;
 617     }
 618 
 619     if ((uint32_t) input->type == pcmk__ar_none) {
 620         crm_trace("Ignoring %s (%d) input %s (%d): "
 621                   "ordering disabled",
 622                   action->uuid, action->id,
 623                   input->action->uuid, input->action->id);
 624         return false;
 625 
 626     } else if (!pcmk_is_set(input->action->flags, pcmk_action_runnable)
 627                && !ordering_can_change_actions(input)) {
 628         crm_trace("Ignoring %s (%d) input %s (%d): "
 629                   "optional and input unrunnable",
 630                   action->uuid, action->id,
 631                   input->action->uuid, input->action->id);
 632         return false;
 633 
 634     } else if (!pcmk_is_set(input->action->flags, pcmk_action_runnable)
 635                && pcmk_is_set(input->type, pcmk__ar_min_runnable)) {
 636         crm_trace("Ignoring %s (%d) input %s (%d): "
 637                   "minimum number of instances required but input unrunnable",
 638                   action->uuid, action->id,
 639                   input->action->uuid, input->action->id);
 640         return false;
 641 
 642     } else if (pcmk_is_set(input->type, pcmk__ar_unmigratable_then_blocks)
 643                && !pcmk_is_set(input->action->flags, pcmk_action_runnable)) {
 644         crm_trace("Ignoring %s (%d) input %s (%d): "
 645                   "input blocked if 'then' unmigratable",
 646                   action->uuid, action->id,
 647                   input->action->uuid, input->action->id);
 648         return false;
 649 
 650     } else if (pcmk_is_set(input->type, pcmk__ar_if_first_unmigratable)
 651                && pcmk_is_set(input->action->flags, pcmk_action_migratable)) {
 652         crm_trace("Ignoring %s (%d) input %s (%d): ordering applies "
 653                   "only if input is unmigratable, but it is migratable",
 654                   action->uuid, action->id,
 655                   input->action->uuid, input->action->id);
 656         return false;
 657 
 658     } else if (((uint32_t) input->type == pcmk__ar_ordered)
 659                && pcmk_is_set(input->action->flags, pcmk_action_migratable)
 660                && pcmk__ends_with(input->action->uuid, "_stop_0")) {
 661         crm_trace("Ignoring %s (%d) input %s (%d): "
 662                   "optional but stop in migration",
 663                   action->uuid, action->id,
 664                   input->action->uuid, input->action->id);
 665         return false;
 666 
 667     } else if ((uint32_t) input->type == pcmk__ar_if_on_same_node_or_target) {
 668         pcmk_node_t *input_node = input->action->node;
 669 
 670         if ((action->rsc != NULL)
 671             && pcmk__str_eq(action->task, PCMK_ACTION_MIGRATE_TO,
 672                             pcmk__str_none)) {
 673 
 674             pcmk_node_t *assigned = action->rsc->allocated_to;
 675 
 676             
 677 
 678 
 679 
 680             if (!pcmk__same_node(input_node, assigned)) {
 681                 crm_trace("Ignoring %s (%d) input %s (%d): "
 682                           "migration target %s is not same as input node %s",
 683                           action->uuid, action->id,
 684                           input->action->uuid, input->action->id,
 685                           (assigned? assigned->details->uname : "<none>"),
 686                           (input_node? input_node->details->uname : "<none>"));
 687                 input->type = (enum pe_ordering) pcmk__ar_none;
 688                 return false;
 689             }
 690 
 691         } else if (!pcmk__same_node(input_node, action->node)) {
 692             crm_trace("Ignoring %s (%d) input %s (%d): "
 693                       "not on same node (%s vs %s)",
 694                       action->uuid, action->id,
 695                       input->action->uuid, input->action->id,
 696                       (action->node? action->node->details->uname : "<none>"),
 697                       (input_node? input_node->details->uname : "<none>"));
 698             input->type = (enum pe_ordering) pcmk__ar_none;
 699             return false;
 700 
 701         } else if (pcmk_is_set(input->action->flags, pcmk_action_optional)) {
 702             crm_trace("Ignoring %s (%d) input %s (%d): "
 703                       "ordering optional",
 704                       action->uuid, action->id,
 705                       input->action->uuid, input->action->id);
 706             input->type = (enum pe_ordering) pcmk__ar_none;
 707             return false;
 708         }
 709 
 710     } else if ((uint32_t) input->type == pcmk__ar_if_required_on_same_node) {
 711         if (input->action->node && action->node
 712             && !pcmk__same_node(input->action->node, action->node)) {
 713             crm_trace("Ignoring %s (%d) input %s (%d): "
 714                       "not on same node (%s vs %s)",
 715                       action->uuid, action->id,
 716                       input->action->uuid, input->action->id,
 717                       pcmk__node_name(action->node),
 718                       pcmk__node_name(input->action->node));
 719             input->type = (enum pe_ordering) pcmk__ar_none;
 720             return false;
 721 
 722         } else if (pcmk_is_set(input->action->flags, pcmk_action_optional)) {
 723             crm_trace("Ignoring %s (%d) input %s (%d): optional",
 724                       action->uuid, action->id,
 725                       input->action->uuid, input->action->id);
 726             input->type = (enum pe_ordering) pcmk__ar_none;
 727             return false;
 728         }
 729 
 730     } else if (input->action->rsc
 731                && input->action->rsc != action->rsc
 732                && pcmk_is_set(input->action->rsc->flags, pcmk_rsc_failed)
 733                && !pcmk_is_set(input->action->rsc->flags, pcmk_rsc_managed)
 734                && pcmk__ends_with(input->action->uuid, "_stop_0")
 735                && pcmk__is_clone(action->rsc)) {
 736         crm_warn("Ignoring requirement that %s complete before %s:"
 737                  " unmanaged failed resources cannot prevent clone shutdown",
 738                  input->action->uuid, action->uuid);
 739         return false;
 740 
 741     } else if (pcmk_is_set(input->action->flags, pcmk_action_optional)
 742                && !pcmk_any_flags_set(input->action->flags,
 743                                       pcmk_action_always_in_graph
 744                                       |pcmk_action_added_to_graph)
 745                && !should_add_action_to_graph(input->action)) {
 746         crm_trace("Ignoring %s (%d) input %s (%d): "
 747                   "input optional",
 748                   action->uuid, action->id,
 749                   input->action->uuid, input->action->id);
 750         return false;
 751     }
 752 
 753     crm_trace("%s (%d) input %s %s (%d) on %s should be dumped: %s %s %#.6x",
 754               action->uuid, action->id, action_type_str(input->action->flags),
 755               input->action->uuid, input->action->id,
 756               action_node_str(input->action),
 757               action_runnable_str(input->action->flags),
 758               action_optional_str(input->action->flags), input->type);
 759     return true;
 760 }
 761 
 762 
 763 
 764 
 765 
 766 
 767 
 768 
 769 
 770 
 771 
 772 
 773 
 774 bool
 775 pcmk__graph_has_loop(const pcmk_action_t *init_action,
     
 776                      const pcmk_action_t *action, pcmk__related_action_t *input)
 777 {
 778     bool has_loop = false;
 779 
 780     if (pcmk_is_set(input->action->flags, pcmk_action_detect_loop)) {
 781         crm_trace("Breaking tracking loop: %s@%s -> %s@%s (%#.6x)",
 782                   input->action->uuid,
 783                   input->action->node? input->action->node->details->uname : "",
 784                   action->uuid,
 785                   action->node? action->node->details->uname : "",
 786                   input->type);
 787         return false;
 788     }
 789 
 790     
 791     if (!should_add_input_to_graph(action, input)) {
 792         return false;
 793     }
 794 
 795     if (input->action == init_action) {
 796         crm_debug("Input loop found in %s@%s ->...-> %s@%s",
 797                   action->uuid,
 798                   action->node? action->node->details->uname : "",
 799                   init_action->uuid,
 800                   init_action->node? init_action->node->details->uname : "");
 801         return true;
 802     }
 803 
 804     pcmk__set_action_flags(input->action, pcmk_action_detect_loop);
 805 
 806     crm_trace("Checking inputs of action %s@%s input %s@%s (%#.6x)"
 807               "for graph loop with %s@%s ",
 808               action->uuid,
 809               action->node? action->node->details->uname : "",
 810               input->action->uuid,
 811               input->action->node? input->action->node->details->uname : "",
 812               input->type,
 813               init_action->uuid,
 814               init_action->node? init_action->node->details->uname : "");
 815 
 816     
 817     for (GList *iter = input->action->actions_before;
 818          iter != NULL; iter = iter->next) {
 819 
 820         if (pcmk__graph_has_loop(init_action, input->action,
 821                                  (pcmk__related_action_t *) iter->data)) {
 822             
 823             has_loop = true;
 824             break;
 825         }
 826     }
 827 
 828     pcmk__clear_action_flags(input->action, pcmk_action_detect_loop);
 829 
 830     if (!has_loop) {
 831         crm_trace("No input loop found in %s@%s -> %s@%s (%#.6x)",
 832                   input->action->uuid,
 833                   input->action->node? input->action->node->details->uname : "",
 834                   action->uuid,
 835                   action->node? action->node->details->uname : "",
 836                   input->type);
 837     }
 838     return has_loop;
 839 }
 840 
 841 
 842 
 843 
 844 
 845 
 846 
 847 
 848 
 849 
 850 static xmlNode *
 851 create_graph_synapse(const pcmk_action_t *action, pcmk_scheduler_t *scheduler)
     
 852 {
 853     int synapse_priority = 0;
 854     xmlNode *syn = pcmk__xe_create(scheduler->graph, "synapse");
 855 
 856     crm_xml_add_int(syn, PCMK_XA_ID, scheduler->num_synapse);
 857     scheduler->num_synapse++;
 858 
 859     if (action->rsc != NULL) {
 860         synapse_priority = action->rsc->priority;
 861     }
 862     if (action->priority > synapse_priority) {
 863         synapse_priority = action->priority;
 864     }
 865     if (synapse_priority > 0) {
 866         crm_xml_add_int(syn, PCMK__XA_PRIORITY, synapse_priority);
 867     }
 868     return syn;
 869 }
 870 
 871 
 872 
 873 
 874 
 875 
 876 
 877 
 878 
 879 
 880 
 881 
 882 
 883 
 884 
 885 
 886 
 887 static void
 888 add_action_to_graph(gpointer data, gpointer user_data)
     
 889 {
 890     pcmk_action_t *action = (pcmk_action_t *) data;
 891     pcmk_scheduler_t *scheduler = (pcmk_scheduler_t *) user_data;
 892 
 893     xmlNode *syn = NULL;
 894     xmlNode *set = NULL;
 895     xmlNode *in = NULL;
 896 
 897     
 898 
 899 
 900 
 901     if (!pcmk_is_set(action->flags, pcmk_action_inputs_deduplicated)) {
 902         pcmk__deduplicate_action_inputs(action);
 903         pcmk__set_action_flags(action, pcmk_action_inputs_deduplicated);
 904     }
 905 
 906     if (pcmk_is_set(action->flags, pcmk_action_added_to_graph)
 907         || !should_add_action_to_graph(action)) {
 908         return; 
 909     }
 910     pcmk__set_action_flags(action, pcmk_action_added_to_graph);
 911 
 912     crm_trace("Adding action %d (%s%s%s) to graph",
 913               action->id, action->uuid,
 914               ((action->node == NULL)? "" : " on "),
 915               ((action->node == NULL)? "" : action->node->details->uname));
 916 
 917     syn = create_graph_synapse(action, scheduler);
 918     set = pcmk__xe_create(syn, "action_set");
 919     in = pcmk__xe_create(syn, "inputs");
 920 
 921     create_graph_action(set, action, false, scheduler);
 922 
 923     for (GList *lpc = action->actions_before; lpc != NULL; lpc = lpc->next) {
 924         pcmk__related_action_t *input = lpc->data;
 925 
 926         if (should_add_input_to_graph(action, input)) {
 927             xmlNode *input_xml = pcmk__xe_create(in, "trigger");
 928 
 929             input->state = pe_link_dumped;
 930             create_graph_action(input_xml, input->action, true, scheduler);
 931         }
 932     }
 933 }
 934 
 935 static int transition_id = -1;
 936 
 937 
 938 
 939 
 940 
 941 
 942 
 943 void
 944 pcmk__log_transition_summary(const char *filename)
     
 945 {
 946     if (was_processing_error || crm_config_error) {
 947         crm_err("Calculated transition %d (with errors)%s%s",
 948                 transition_id,
 949                 (filename == NULL)? "" : ", saving inputs in ",
 950                 (filename == NULL)? "" : filename);
 951 
 952     } else if (was_processing_warning || crm_config_warning) {
 953         crm_warn("Calculated transition %d (with warnings)%s%s",
 954                  transition_id,
 955                  (filename == NULL)? "" : ", saving inputs in ",
 956                  (filename == NULL)? "" : filename);
 957 
 958     } else {
 959         crm_notice("Calculated transition %d%s%s",
 960                    transition_id,
 961                    (filename == NULL)? "" : ", saving inputs in ",
 962                    (filename == NULL)? "" : filename);
 963     }
 964     if (crm_config_error) {
 965         crm_notice("Configuration errors found during scheduler processing,"
 966                    "  please run \"crm_verify -L\" to identify issues");
 967     }
 968 }
 969 
 970 
 971 
 972 
 973 
 974 
 975 
 976 void
 977 pcmk__add_rsc_actions_to_graph(pcmk_resource_t *rsc)
     
 978 {
 979     GList *iter = NULL;
 980 
 981     CRM_ASSERT(rsc != NULL);
 982     pcmk__rsc_trace(rsc, "Adding actions for %s to graph", rsc->id);
 983 
 984     
 985     g_list_foreach(rsc->actions, add_action_to_graph, rsc->cluster);
 986 
 987     
 988     for (iter = rsc->children; iter != NULL; iter = iter->next) {
 989         pcmk_resource_t *child_rsc = (pcmk_resource_t *) iter->data;
 990 
 991         child_rsc->cmds->add_actions_to_graph(child_rsc);
 992     }
 993 }
 994 
 995 
 996 
 997 
 998 
 999 
1000 
1001 void
1002 pcmk__create_graph(pcmk_scheduler_t *scheduler)
     
1003 {
1004     GList *iter = NULL;
1005     const char *value = NULL;
1006     long long limit = 0LL;
1007     GHashTable *config_hash = scheduler->config_hash;
1008 
1009     transition_id++;
1010     crm_trace("Creating transition graph %d", transition_id);
1011 
1012     scheduler->graph = pcmk__xe_create(NULL, PCMK__XE_TRANSITION_GRAPH);
1013 
1014     value = pcmk__cluster_option(config_hash, PCMK_OPT_CLUSTER_DELAY);
1015     crm_xml_add(scheduler->graph, PCMK_OPT_CLUSTER_DELAY, value);
1016 
1017     value = pcmk__cluster_option(config_hash, PCMK_OPT_STONITH_TIMEOUT);
1018     crm_xml_add(scheduler->graph, PCMK_OPT_STONITH_TIMEOUT, value);
1019 
1020     crm_xml_add(scheduler->graph, "failed-stop-offset", "INFINITY");
1021 
1022     if (pcmk_is_set(scheduler->flags, pcmk_sched_start_failure_fatal)) {
1023         crm_xml_add(scheduler->graph, "failed-start-offset", "INFINITY");
1024     } else {
1025         crm_xml_add(scheduler->graph, "failed-start-offset", "1");
1026     }
1027 
1028     value = pcmk__cluster_option(config_hash, PCMK_OPT_BATCH_LIMIT);
1029     crm_xml_add(scheduler->graph, PCMK_OPT_BATCH_LIMIT, value);
1030 
1031     crm_xml_add_int(scheduler->graph, "transition_id", transition_id);
1032 
1033     value = pcmk__cluster_option(config_hash, PCMK_OPT_MIGRATION_LIMIT);
1034     if ((pcmk__scan_ll(value, &limit, 0LL) == pcmk_rc_ok) && (limit > 0)) {
1035         crm_xml_add(scheduler->graph, PCMK_OPT_MIGRATION_LIMIT, value);
1036     }
1037 
1038     if (scheduler->recheck_by > 0) {
1039         char *recheck_epoch = NULL;
1040 
1041         recheck_epoch = crm_strdup_printf("%llu",
1042                                           (long long) scheduler->recheck_by);
1043         crm_xml_add(scheduler->graph, "recheck-by", recheck_epoch);
1044         free(recheck_epoch);
1045     }
1046 
1047     
1048 
1049 
1050 
1051 
1052     
1053     for (iter = scheduler->resources; iter != NULL; iter = iter->next) {
1054         pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
1055 
1056         pcmk__rsc_trace(rsc, "Processing actions for %s", rsc->id);
1057         rsc->cmds->add_actions_to_graph(rsc);
1058     }
1059 
1060     
1061     add_maintenance_update(scheduler);
1062 
1063     
1064     for (iter = scheduler->actions; iter != NULL; iter = iter->next) {
1065         pcmk_action_t *action = (pcmk_action_t *) iter->data;
1066 
1067         if ((action->rsc != NULL)
1068             && (action->node != NULL)
1069             && action->node->details->shutdown
1070             && !pcmk_is_set(action->rsc->flags, pcmk_rsc_maintenance)
1071             && !pcmk_any_flags_set(action->flags,
1072                                    pcmk_action_optional|pcmk_action_runnable)
1073             && pcmk__str_eq(action->task, PCMK_ACTION_STOP, pcmk__str_none)) {
1074             
1075 
1076 
1077 
1078             if (pcmk_is_set(scheduler->flags, pcmk_sched_quorate)
1079                 || (scheduler->no_quorum_policy == pcmk_no_quorum_ignore)) {
1080                 const bool managed = pcmk_is_set(action->rsc->flags,
1081                                                  pcmk_rsc_managed);
1082                 const bool failed = pcmk_is_set(action->rsc->flags,
1083                                                 pcmk_rsc_failed);
1084 
1085                 crm_crit("Cannot %s %s because of %s:%s%s (%s)",
1086                          action->node->details->unclean? "fence" : "shut down",
1087                          pcmk__node_name(action->node), action->rsc->id,
1088                          (managed? " blocked" : " unmanaged"),
1089                          (failed? " failed" : ""), action->uuid);
1090             }
1091         }
1092 
1093         add_action_to_graph((gpointer) action, (gpointer) scheduler);
1094     }
1095 
1096     crm_log_xml_trace(scheduler->graph, "graph");
1097 }