root/pengine/clone.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sort_rsc_id
  2. parent_node_instance
  3. did_fail
  4. sort_clone_instance
  5. can_run_instance
  6. color_instance
  7. append_parent_colocation
  8. distribute_children
  9. clone_color
  10. clone_update_pseudo_status
  11. find_rsc_action
  12. child_ordering_constraints
  13. clone_create_actions
  14. clone_create_pseudo_actions
  15. clone_internal_constraints
  16. assign_node
  17. is_child_compatible
  18. find_compatible_child
  19. clone_rsc_colocation_lh
  20. clone_rsc_colocation_rh
  21. clone_child_action
  22. summary_action_flags
  23. clone_action_flags
  24. clone_rsc_location
  25. clone_expand
  26. rsc_known_on
  27. find_instance_on
  28. clone_create_probe
  29. clone_append_meta
  30. clone_merge_weights

   1 /* 
   2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
   3  * 
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) any later version.
   8  * 
   9  * This software 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  * General Public License for more details.
  13  * 
  14  * You should have received a copy of the GNU 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/msg_xml.h>
  22 #include <allocate.h>
  23 #include <notif.h>
  24 #include <utils.h>
  25 #include <allocate.h>
  26 
  27 #define VARIANT_CLONE 1
  28 #include <lib/pengine/variant.h>
  29 
  30 gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set);
  31 static void append_parent_colocation(resource_t * rsc, resource_t * child, gboolean all);
  32 
  33 static gint
  34 sort_rsc_id(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
  35 {
  36     const resource_t *resource1 = (const resource_t *)a;
  37     const resource_t *resource2 = (const resource_t *)b;
  38 
  39     CRM_ASSERT(resource1 != NULL);
  40     CRM_ASSERT(resource2 != NULL);
  41 
  42     return strcmp(resource1->id, resource2->id);
  43 }
  44 
  45 static node_t *
  46 parent_node_instance(const resource_t * rsc, node_t * node)
     /* [previous][next][first][last][top][bottom][index][help] */
  47 {
  48     node_t *ret = NULL;
  49 
  50     if (node != NULL && rsc->parent) {
  51         ret = pe_hash_table_lookup(rsc->parent->allowed_nodes, node->details->id);
  52     } else if(node != NULL) {
  53         ret = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
  54     }
  55     return ret;
  56 }
  57 
  58 static gboolean
  59 did_fail(const resource_t * rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61     GListPtr gIter = rsc->children;
  62 
  63     if (is_set(rsc->flags, pe_rsc_failed)) {
  64         return TRUE;
  65     }
  66 
  67     for (; gIter != NULL; gIter = gIter->next) {
  68         resource_t *child_rsc = (resource_t *) gIter->data;
  69 
  70         if (did_fail(child_rsc)) {
  71             return TRUE;
  72         }
  73     }
  74     return FALSE;
  75 }
  76 
  77 gint
  78 sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
  79 {
  80     int rc = 0;
  81     node_t *node1 = NULL;
  82     node_t *node2 = NULL;
  83 
  84     gboolean can1 = TRUE;
  85     gboolean can2 = TRUE;
  86 
  87     const resource_t *resource1 = (const resource_t *)a;
  88     const resource_t *resource2 = (const resource_t *)b;
  89 
  90     CRM_ASSERT(resource1 != NULL);
  91     CRM_ASSERT(resource2 != NULL);
  92 
  93     /* allocation order:
  94      *  - active instances
  95      *  - instances running on nodes with the least copies
  96      *  - active instances on nodes that can't support them or are to be fenced
  97      *  - failed instances
  98      *  - inactive instances
  99      */
 100 
 101     if (resource1->running_on && resource2->running_on) {
 102         if (g_list_length(resource1->running_on) < g_list_length(resource2->running_on)) {
 103             crm_trace("%s < %s: running_on", resource1->id, resource2->id);
 104             return -1;
 105 
 106         } else if (g_list_length(resource1->running_on) > g_list_length(resource2->running_on)) {
 107             crm_trace("%s > %s: running_on", resource1->id, resource2->id);
 108             return 1;
 109         }
 110     }
 111 
 112     if (resource1->running_on) {
 113         node1 = resource1->running_on->data;
 114     }
 115     if (resource2->running_on) {
 116         node2 = resource2->running_on->data;
 117     }
 118 
 119     if (node1) {
 120         node_t *match = pe_hash_table_lookup(resource1->allowed_nodes, node1->details->id);
 121 
 122         if (match == NULL || match->weight < 0) {
 123             crm_trace("%s: current location is unavailable", resource1->id);
 124             node1 = NULL;
 125             can1 = FALSE;
 126         }
 127     }
 128 
 129     if (node2) {
 130         node_t *match = pe_hash_table_lookup(resource2->allowed_nodes, node2->details->id);
 131 
 132         if (match == NULL || match->weight < 0) {
 133             crm_trace("%s: current location is unavailable", resource2->id);
 134             node2 = NULL;
 135             can2 = FALSE;
 136         }
 137     }
 138 
 139     if (can1 != can2) {
 140         if (can1) {
 141             crm_trace("%s < %s: availability of current location", resource1->id, resource2->id);
 142             return -1;
 143         }
 144         crm_trace("%s > %s: availability of current location", resource1->id, resource2->id);
 145         return 1;
 146     }
 147 
 148     if (resource1->priority < resource2->priority) {
 149         crm_trace("%s < %s: priority", resource1->id, resource2->id);
 150         return 1;
 151 
 152     } else if (resource1->priority > resource2->priority) {
 153         crm_trace("%s > %s: priority", resource1->id, resource2->id);
 154         return -1;
 155     }
 156 
 157     if (node1 == NULL && node2 == NULL) {
 158         crm_trace("%s == %s: not active", resource1->id, resource2->id);
 159         return 0;
 160     }
 161 
 162     if (node1 != node2) {
 163         if (node1 == NULL) {
 164             crm_trace("%s > %s: active", resource1->id, resource2->id);
 165             return 1;
 166         } else if (node2 == NULL) {
 167             crm_trace("%s < %s: active", resource1->id, resource2->id);
 168             return -1;
 169         }
 170     }
 171 
 172     can1 = can_run_resources(node1);
 173     can2 = can_run_resources(node2);
 174     if (can1 != can2) {
 175         if (can1) {
 176             crm_trace("%s < %s: can", resource1->id, resource2->id);
 177             return -1;
 178         }
 179         crm_trace("%s > %s: can", resource1->id, resource2->id);
 180         return 1;
 181     }
 182 
 183     node1 = parent_node_instance(resource1, node1);
 184     node2 = parent_node_instance(resource2, node2);
 185     if (node1 != NULL && node2 == NULL) {
 186         crm_trace("%s < %s: not allowed", resource1->id, resource2->id);
 187         return -1;
 188     } else if (node1 == NULL && node2 != NULL) {
 189         crm_trace("%s > %s: not allowed", resource1->id, resource2->id);
 190         return 1;
 191     }
 192 
 193     if (node1 == NULL || node2 == NULL) {
 194         crm_trace("%s == %s: not allowed", resource1->id, resource2->id);
 195         return 0;
 196     }
 197 
 198     if (node1->count < node2->count) {
 199         crm_trace("%s < %s: count", resource1->id, resource2->id);
 200         return -1;
 201 
 202     } else if (node1->count > node2->count) {
 203         crm_trace("%s > %s: count", resource1->id, resource2->id);
 204         return 1;
 205     }
 206 
 207     can1 = did_fail(resource1);
 208     can2 = did_fail(resource2);
 209     if (can1 != can2) {
 210         if (can1) {
 211             crm_trace("%s > %s: failed", resource1->id, resource2->id);
 212             return 1;
 213         }
 214         crm_trace("%s < %s: failed", resource1->id, resource2->id);
 215         return -1;
 216     }
 217 
 218     if (node1 && node2) {
 219         int lpc = 0;
 220         int max = 0;
 221         node_t *n = NULL;
 222         GListPtr gIter = NULL;
 223         GListPtr list1 = NULL;
 224         GListPtr list2 = NULL;
 225         GHashTable *hash1 =
 226             g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, g_hash_destroy_str);
 227         GHashTable *hash2 =
 228             g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, g_hash_destroy_str);
 229 
 230         n = node_copy(resource1->running_on->data);
 231         g_hash_table_insert(hash1, (gpointer) n->details->id, n);
 232 
 233         n = node_copy(resource2->running_on->data);
 234         g_hash_table_insert(hash2, (gpointer) n->details->id, n);
 235 
 236         if(resource1->parent) {
 237             for (gIter = resource1->parent->rsc_cons; gIter; gIter = gIter->next) {
 238                 rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
 239 
 240                 crm_trace("Applying %s to %s", constraint->id, resource1->id);
 241 
 242                 hash1 = native_merge_weights(constraint->rsc_rh, resource1->id, hash1,
 243                                              constraint->node_attribute,
 244                                              (float)constraint->score / INFINITY, 0);
 245             }
 246 
 247             for (gIter = resource1->parent->rsc_cons_lhs; gIter; gIter = gIter->next) {
 248                 rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
 249 
 250                 crm_trace("Applying %s to %s", constraint->id, resource1->id);
 251 
 252                 hash1 = native_merge_weights(constraint->rsc_lh, resource1->id, hash1,
 253                                              constraint->node_attribute,
 254                                              (float)constraint->score / INFINITY, pe_weights_positive);
 255             }
 256         }
 257 
 258         if(resource2->parent) {
 259             for (gIter = resource2->parent->rsc_cons; gIter; gIter = gIter->next) {
 260                 rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
 261 
 262                 crm_trace("Applying %s to %s", constraint->id, resource2->id);
 263 
 264                 hash2 = native_merge_weights(constraint->rsc_rh, resource2->id, hash2,
 265                                              constraint->node_attribute,
 266                                              (float)constraint->score / INFINITY, 0);
 267             }
 268 
 269             for (gIter = resource2->parent->rsc_cons_lhs; gIter; gIter = gIter->next) {
 270                 rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
 271 
 272                 crm_trace("Applying %s to %s", constraint->id, resource2->id);
 273 
 274                 hash2 = native_merge_weights(constraint->rsc_lh, resource2->id, hash2,
 275                                              constraint->node_attribute,
 276                                              (float)constraint->score / INFINITY, pe_weights_positive);
 277             }
 278         }
 279 
 280         /* Current location score */
 281         node1 = g_list_nth_data(resource1->running_on, 0);
 282         node1 = g_hash_table_lookup(hash1, node1->details->id);
 283 
 284         node2 = g_list_nth_data(resource2->running_on, 0);
 285         node2 = g_hash_table_lookup(hash2, node2->details->id);
 286 
 287         if (node1->weight < node2->weight) {
 288             if (node1->weight < 0) {
 289                 crm_trace("%s > %s: current score: %d %d", resource1->id, resource2->id, node1->weight, node2->weight);
 290                 rc = -1;
 291                 goto out;
 292 
 293             } else {
 294                 crm_trace("%s < %s: current score: %d %d", resource1->id, resource2->id, node1->weight, node2->weight);
 295                 rc = 1;
 296                 goto out;
 297             }
 298 
 299         } else if (node1->weight > node2->weight) {
 300             crm_trace("%s > %s: current score: %d %d", resource1->id, resource2->id, node1->weight, node2->weight);
 301             rc = -1;
 302             goto out;
 303         }
 304 
 305         /* All location scores */
 306         list1 = g_hash_table_get_values(hash1);
 307         list2 = g_hash_table_get_values(hash2);
 308 
 309         list1 =
 310             g_list_sort_with_data(list1, sort_node_weight,
 311                                   g_list_nth_data(resource1->running_on, 0));
 312         list2 =
 313             g_list_sort_with_data(list2, sort_node_weight,
 314                                   g_list_nth_data(resource2->running_on, 0));
 315         max = g_list_length(list1);
 316         if (max < g_list_length(list2)) {
 317             max = g_list_length(list2);
 318         }
 319 
 320         for (; lpc < max; lpc++) {
 321             node1 = g_list_nth_data(list1, lpc);
 322             node2 = g_list_nth_data(list2, lpc);
 323             if (node1 == NULL) {
 324                 crm_trace("%s < %s: colocated score NULL", resource1->id, resource2->id);
 325                 rc = 1;
 326                 break;
 327 
 328             } else if (node2 == NULL) {
 329                 crm_trace("%s > %s: colocated score NULL", resource1->id, resource2->id);
 330                 rc = -1;
 331                 break;
 332             }
 333 
 334             if (node1->weight < node2->weight) {
 335                 crm_trace("%s < %s: colocated score", resource1->id, resource2->id);
 336                 rc = 1;
 337                 break;
 338 
 339             } else if (node1->weight > node2->weight) {
 340                 crm_trace("%s > %s: colocated score", resource1->id, resource2->id);
 341                 rc = -1;
 342                 break;
 343             }
 344         }
 345 
 346         /* Order by reverse uname - same as sort_node_weight() does? */
 347   out:
 348         g_hash_table_destroy(hash1);    /* Free mem */
 349         g_hash_table_destroy(hash2);    /* Free mem */
 350         g_list_free(list1);
 351         g_list_free(list2);
 352 
 353         if (rc != 0) {
 354             return rc;
 355         }
 356     }
 357 
 358     rc = strcmp(resource1->id, resource2->id);
 359     crm_trace("%s %c %s: default", resource1->id, rc < 0 ? '<' : '>', resource2->id);
 360     return rc;
 361 }
 362 
 363 static node_t *
 364 can_run_instance(resource_t * rsc, node_t * node, int limit)
     /* [previous][next][first][last][top][bottom][index][help] */
 365 {
 366     node_t *local_node = NULL;
 367 
 368     if (node == NULL && rsc->allowed_nodes) {
 369         GHashTableIter iter;
 370         g_hash_table_iter_init(&iter, rsc->allowed_nodes);
 371         while (g_hash_table_iter_next(&iter, NULL, (void **)&local_node)) {
 372             can_run_instance(rsc, local_node, limit);
 373         }
 374         return NULL;
 375     }
 376 
 377     if (can_run_resources(node) == FALSE) {
 378         goto bail;
 379 
 380     } else if (is_set(rsc->flags, pe_rsc_orphan)) {
 381         goto bail;
 382     }
 383 
 384     local_node = parent_node_instance(rsc, node);
 385 
 386     if (local_node == NULL) {
 387         crm_warn("%s cannot run on %s: node not allowed", rsc->id, node->details->uname);
 388         goto bail;
 389 
 390     } else if (local_node->weight < 0) {
 391         common_update_score(rsc, node->details->id, local_node->weight);
 392         pe_rsc_trace(rsc, "%s cannot run on %s: Parent node weight doesn't allow it.",
 393                      rsc->id, node->details->uname);
 394 
 395     } else if (local_node->count < limit) {
 396         pe_rsc_trace(rsc, "%s can run on %s (already running %d)",
 397                      rsc->id, node->details->uname, local_node->count);
 398         return local_node;
 399 
 400     } else {
 401         pe_rsc_trace(rsc, "%s cannot run on %s: node full (%d >= %d)",
 402                      rsc->id, node->details->uname, local_node->count, limit);
 403     }
 404 
 405   bail:
 406     if (node) {
 407         common_update_score(rsc, node->details->id, -INFINITY);
 408     }
 409     return NULL;
 410 }
 411 
 412 static node_t *
 413 color_instance(resource_t * rsc, node_t * prefer, gboolean all_coloc, int limit, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 414 {
 415     node_t *chosen = NULL;
 416     GHashTable *backup = NULL;
 417 
 418     CRM_ASSERT(rsc);
 419     pe_rsc_trace(rsc, "Checking allocation of %s (preferring %s, using %s parent colocations)",
 420                  rsc->id, (prefer? prefer->details->uname: "none"),
 421                  (all_coloc? "all" : "some"));
 422 
 423     if (is_not_set(rsc->flags, pe_rsc_provisional)) {
 424         return rsc->fns->location(rsc, NULL, FALSE);
 425 
 426     } else if (is_set(rsc->flags, pe_rsc_allocating)) {
 427         pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
 428         return NULL;
 429     }
 430 
 431     /* Only include positive colocation preferences of dependent resources
 432      * if not every node will get a copy of the clone
 433      */
 434     append_parent_colocation(rsc->parent, rsc, all_coloc);
 435 
 436     if (prefer) {
 437         node_t *local_prefer = g_hash_table_lookup(rsc->allowed_nodes, prefer->details->id);
 438 
 439         if (local_prefer == NULL || local_prefer->weight < 0) {
 440             pe_rsc_trace(rsc, "Not pre-allocating %s to %s - unavailable", rsc->id,
 441                          prefer->details->uname);
 442             return NULL;
 443         }
 444     }
 445 
 446     can_run_instance(rsc, NULL, limit);
 447 
 448     backup = node_hash_dup(rsc->allowed_nodes);
 449     chosen = rsc->cmds->allocate(rsc, prefer, data_set);
 450     if (chosen) {
 451         node_t *local_node = parent_node_instance(rsc, chosen);
 452         if (prefer && chosen && chosen->details != prefer->details) {
 453             crm_notice("Pre-allocation failed: got %s instead of %s",
 454                        chosen->details->uname, prefer->details->uname);
 455             g_hash_table_destroy(rsc->allowed_nodes);
 456             rsc->allowed_nodes = backup;
 457             native_deallocate(rsc);
 458             chosen = NULL;
 459             backup = NULL;
 460 
 461         } else if (local_node) {
 462             local_node->count++;
 463 
 464         } else if (is_set(rsc->flags, pe_rsc_managed)) {
 465             /* what to do? we can't enforce per-node limits in this case */
 466             crm_config_err("%s not found in %s (list=%d)",
 467                            chosen->details->id, rsc->parent->id,
 468                            g_hash_table_size(rsc->parent->allowed_nodes));
 469         }
 470     }
 471 
 472     if(backup) {
 473         g_hash_table_destroy(backup);
 474     }
 475     return chosen;
 476 }
 477 
 478 static void
 479 append_parent_colocation(resource_t * rsc, resource_t * child, gboolean all)
     /* [previous][next][first][last][top][bottom][index][help] */
 480 {
 481 
 482     GListPtr gIter = NULL;
 483 
 484     gIter = rsc->rsc_cons;
 485     for (; gIter != NULL; gIter = gIter->next) {
 486         rsc_colocation_t *cons = (rsc_colocation_t *) gIter->data;
 487 
 488         if (all || cons->score < 0 || cons->score == INFINITY) {
 489             child->rsc_cons = g_list_prepend(child->rsc_cons, cons);
 490         }
 491     }
 492 
 493     gIter = rsc->rsc_cons_lhs;
 494     for (; gIter != NULL; gIter = gIter->next) {
 495         rsc_colocation_t *cons = (rsc_colocation_t *) gIter->data;
 496 
 497         if (all || cons->score < 0) {
 498             child->rsc_cons_lhs = g_list_prepend(child->rsc_cons_lhs, cons);
 499         }
 500     }
 501 }
 502 
 503 
 504 void
 505 distribute_children(resource_t *rsc, GListPtr children, GListPtr nodes,
 506                     int max, int per_host_max, pe_working_set_t * data_set);
 507 
 508 void
 509 distribute_children(resource_t *rsc, GListPtr children, GListPtr nodes,
     /* [previous][next][first][last][top][bottom][index][help] */
 510                     int max, int per_host_max, pe_working_set_t * data_set) 
 511 {
 512     int loop_max = 0;
 513     int allocated = 0;
 514     int available_nodes = 0;
 515 
 516     /* count now tracks the number of clones currently allocated */
 517     for(GListPtr nIter = nodes; nIter != NULL; nIter = nIter->next) {
 518         pe_node_t *node = nIter->data;
 519 
 520         node->count = 0;
 521         if (can_run_resources(node)) {
 522             available_nodes++;
 523         }
 524     }
 525 
 526     if(available_nodes) {
 527         loop_max = max / available_nodes;
 528     }
 529     if (loop_max < 1) {
 530         loop_max = 1;
 531     }
 532 
 533     pe_rsc_debug(rsc, "Allocating up to %d %s instances to a possible %d nodes (at most %d per host, %d optimal)",
 534                  max, rsc->id, available_nodes, per_host_max, loop_max);
 535 
 536     /* Pre-allocate as many instances as we can to their current location */
 537     for (GListPtr gIter = children; gIter != NULL && allocated < max; gIter = gIter->next) {
 538         resource_t *child = (resource_t *) gIter->data;
 539 
 540         if (child->running_on && is_set(child->flags, pe_rsc_provisional)
 541             && is_not_set(child->flags, pe_rsc_failed)) {
 542             node_t *child_node = child->running_on->data;
 543             node_t *local_node = parent_node_instance(child, child->running_on->data);
 544 
 545             pe_rsc_trace(rsc, "Checking pre-allocation of %s to %s (%d remaining of %d)",
 546                          child->id, child_node->details->uname, max - allocated, max);
 547 
 548             if (can_run_resources(child_node) == FALSE || child_node->weight < 0) {
 549                 pe_rsc_trace(rsc, "Not pre-allocating because %s can not run %s",
 550                              child_node->details->uname, child->id);
 551 
 552             } else if(local_node && local_node->count >= loop_max) {
 553                 pe_rsc_trace(rsc,
 554                              "Not pre-allocating because %s already allocated optimal instances",
 555                              child_node->details->uname);
 556 
 557             } else if (color_instance(child, child_node, max < available_nodes, per_host_max, data_set)) {
 558                 pe_rsc_trace(rsc, "Pre-allocated %s to %s", child->id,
 559                              child_node->details->uname);
 560                 allocated++;
 561             }
 562         }
 563     }
 564 
 565     pe_rsc_trace(rsc, "Done pre-allocating (%d of %d)", allocated, max);
 566 
 567     for (GListPtr gIter = children; gIter != NULL; gIter = gIter->next) {
 568         resource_t *child = (resource_t *) gIter->data;
 569 
 570         if (g_list_length(child->running_on) > 0) {
 571             node_t *child_node = child->running_on->data;
 572             node_t *local_node = parent_node_instance(child, child->running_on->data);
 573 
 574             if (local_node == NULL) {
 575                 crm_err("%s is running on %s which isn't allowed",
 576                         child->id, child_node->details->uname);
 577             }
 578         }
 579 
 580         if (is_not_set(child->flags, pe_rsc_provisional)) {
 581         } else if (allocated >= max) {
 582             pe_rsc_debug(rsc, "Child %s not allocated - limit reached %d %d", child->id, allocated, max);
 583             resource_location(child, NULL, -INFINITY, "clone_color:limit_reached", data_set);
 584         } else {
 585             if (color_instance(child, NULL, max < available_nodes, per_host_max, data_set)) {
 586                 allocated++;
 587             }
 588         }
 589     }
 590 
 591     pe_rsc_debug(rsc, "Allocated %d %s instances of a possible %d",
 592                  allocated, rsc->id, max);
 593 }
 594 
 595 
 596 node_t *
 597 clone_color(resource_t * rsc, node_t * prefer, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 598 {
 599     GListPtr nodes = NULL;
 600 
 601     clone_variant_data_t *clone_data = NULL;
 602 
 603     get_clone_variant_data(clone_data, rsc);
 604 
 605     if (is_not_set(rsc->flags, pe_rsc_provisional)) {
 606         return NULL;
 607 
 608     } else if (is_set(rsc->flags, pe_rsc_allocating)) {
 609         pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
 610         return NULL;
 611     }
 612 
 613     set_bit(rsc->flags, pe_rsc_allocating);
 614     pe_rsc_trace(rsc, "Processing %s", rsc->id);
 615 
 616     /* this information is used by sort_clone_instance() when deciding in which 
 617      * order to allocate clone instances
 618      */
 619     for (GListPtr gIter = rsc->rsc_cons; gIter != NULL; gIter = gIter->next) {
 620         rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
 621 
 622         pe_rsc_trace(rsc, "%s: Coloring %s first", rsc->id, constraint->rsc_rh->id);
 623         constraint->rsc_rh->cmds->allocate(constraint->rsc_rh, prefer, data_set);
 624     }
 625 
 626     for (GListPtr gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) {
 627         rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
 628 
 629         rsc->allowed_nodes =
 630             constraint->rsc_lh->cmds->merge_weights(constraint->rsc_lh, rsc->id, rsc->allowed_nodes,
 631                                                     constraint->node_attribute,
 632                                                     (float)constraint->score / INFINITY,
 633                                                     (pe_weights_rollback | pe_weights_positive));
 634     }
 635 
 636     dump_node_scores(show_scores ? 0 : scores_log_level, rsc, __FUNCTION__, rsc->allowed_nodes);
 637 
 638     nodes = g_hash_table_get_values(rsc->allowed_nodes);
 639     nodes = g_list_sort_with_data(nodes, sort_node_weight, NULL);
 640     rsc->children = g_list_sort_with_data(rsc->children, sort_clone_instance, data_set);
 641     distribute_children(rsc, rsc->children, nodes, clone_data->clone_max, clone_data->clone_node_max, data_set);
 642     g_list_free(nodes);
 643 
 644     clear_bit(rsc->flags, pe_rsc_provisional);
 645     clear_bit(rsc->flags, pe_rsc_allocating);
 646 
 647     pe_rsc_trace(rsc, "Done allocating %s", rsc->id);
 648     return NULL;
 649 }
 650 
 651 static void
 652 clone_update_pseudo_status(resource_t * rsc, gboolean * stopping, gboolean * starting,
     /* [previous][next][first][last][top][bottom][index][help] */
 653                            gboolean * active)
 654 {
 655     GListPtr gIter = NULL;
 656 
 657     if (rsc->children) {
 658 
 659         gIter = rsc->children;
 660         for (; gIter != NULL; gIter = gIter->next) {
 661             resource_t *child = (resource_t *) gIter->data;
 662 
 663             clone_update_pseudo_status(child, stopping, starting, active);
 664         }
 665 
 666         return;
 667     }
 668 
 669     CRM_ASSERT(active != NULL);
 670     CRM_ASSERT(starting != NULL);
 671     CRM_ASSERT(stopping != NULL);
 672 
 673     if (rsc->running_on) {
 674         *active = TRUE;
 675     }
 676 
 677     gIter = rsc->actions;
 678     for (; gIter != NULL; gIter = gIter->next) {
 679         action_t *action = (action_t *) gIter->data;
 680 
 681         if (*starting && *stopping) {
 682             return;
 683 
 684         } else if (is_set(action->flags, pe_action_optional)) {
 685             pe_rsc_trace(rsc, "Skipping optional: %s", action->uuid);
 686             continue;
 687 
 688         } else if (is_set(action->flags, pe_action_pseudo) == FALSE
 689                    && is_set(action->flags, pe_action_runnable) == FALSE) {
 690             pe_rsc_trace(rsc, "Skipping unrunnable: %s", action->uuid);
 691             continue;
 692 
 693         } else if (safe_str_eq(RSC_STOP, action->task)) {
 694             pe_rsc_trace(rsc, "Stopping due to: %s", action->uuid);
 695             *stopping = TRUE;
 696 
 697         } else if (safe_str_eq(RSC_START, action->task)) {
 698             if (is_set(action->flags, pe_action_runnable) == FALSE) {
 699                 pe_rsc_trace(rsc, "Skipping pseudo-op: %s run=%d, pseudo=%d",
 700                              action->uuid, is_set(action->flags, pe_action_runnable),
 701                              is_set(action->flags, pe_action_pseudo));
 702             } else {
 703                 pe_rsc_trace(rsc, "Starting due to: %s", action->uuid);
 704                 pe_rsc_trace(rsc, "%s run=%d, pseudo=%d",
 705                              action->uuid, is_set(action->flags, pe_action_runnable),
 706                              is_set(action->flags, pe_action_pseudo));
 707                 *starting = TRUE;
 708             }
 709         }
 710     }
 711 }
 712 
 713 static action_t *
 714 find_rsc_action(resource_t * rsc, const char *key, gboolean active_only, GListPtr * list)
     /* [previous][next][first][last][top][bottom][index][help] */
 715 {
 716     action_t *match = NULL;
 717     GListPtr possible = NULL;
 718     GListPtr active = NULL;
 719 
 720     possible = find_actions(rsc->actions, key, NULL);
 721 
 722     if (active_only) {
 723         GListPtr gIter = possible;
 724 
 725         for (; gIter != NULL; gIter = gIter->next) {
 726             action_t *op = (action_t *) gIter->data;
 727 
 728             if (is_set(op->flags, pe_action_optional) == FALSE) {
 729                 active = g_list_prepend(active, op);
 730             }
 731         }
 732 
 733         if (active && g_list_length(active) == 1) {
 734             match = g_list_nth_data(active, 0);
 735         }
 736 
 737         if (list) {
 738             *list = active;
 739             active = NULL;
 740         }
 741 
 742     } else if (possible && g_list_length(possible) == 1) {
 743         match = g_list_nth_data(possible, 0);
 744 
 745     }
 746     if (list) {
 747         *list = possible;
 748         possible = NULL;
 749     }
 750 
 751     if (possible) {
 752         g_list_free(possible);
 753     }
 754     if (active) {
 755         g_list_free(active);
 756     }
 757 
 758     return match;
 759 }
 760 
 761 static void
 762 child_ordering_constraints(resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 763 {
 764     char *key = NULL;
 765     action_t *stop = NULL;
 766     action_t *start = NULL;
 767     action_t *last_stop = NULL;
 768     action_t *last_start = NULL;
 769     GListPtr gIter = NULL;
 770     gboolean active_only = TRUE;        /* change to false to get the old behavior */
 771     clone_variant_data_t *clone_data = NULL;
 772 
 773     get_clone_variant_data(clone_data, rsc);
 774 
 775     if (clone_data->ordered == FALSE) {
 776         return;
 777     }
 778     /* we have to maintain a consistent sorted child list when building order constraints */
 779     rsc->children = g_list_sort(rsc->children, sort_rsc_id);
 780 
 781     for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 782         resource_t *child = (resource_t *) gIter->data;
 783 
 784         key = stop_key(child);
 785         stop = find_rsc_action(child, key, active_only, NULL);
 786         free(key);
 787 
 788         key = start_key(child);
 789         start = find_rsc_action(child, key, active_only, NULL);
 790         free(key);
 791 
 792         if (stop) {
 793             if (last_stop) {
 794                 /* child/child relative stop */
 795                 order_actions(stop, last_stop, pe_order_optional);
 796             }
 797             last_stop = stop;
 798         }
 799 
 800         if (start) {
 801             if (last_start) {
 802                 /* child/child relative start */
 803                 order_actions(last_start, start, pe_order_optional);
 804             }
 805             last_start = start;
 806         }
 807     }
 808 }
 809 
 810 void
 811 clone_create_actions(resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 812 {
 813     clone_variant_data_t *clone_data = NULL;
 814 
 815     get_clone_variant_data(clone_data, rsc);
 816     clone_create_pseudo_actions(rsc, rsc->children, &clone_data->start_notify, &clone_data->stop_notify,data_set);
 817     child_ordering_constraints(rsc, data_set);
 818 }
 819 
 820 void
 821 clone_create_pseudo_actions(
     /* [previous][next][first][last][top][bottom][index][help] */
 822     resource_t * rsc, GListPtr children, notify_data_t **start_notify, notify_data_t **stop_notify,  pe_working_set_t * data_set)
 823 {
 824     gboolean child_active = FALSE;
 825     gboolean child_starting = FALSE;
 826     gboolean child_stopping = FALSE;
 827     gboolean allow_dependent_migrations = TRUE;
 828 
 829     action_t *stop = NULL;
 830     action_t *stopped = NULL;
 831 
 832     action_t *start = NULL;
 833     action_t *started = NULL;
 834 
 835     pe_rsc_trace(rsc, "Creating actions for %s", rsc->id);
 836 
 837     for (GListPtr gIter = children; gIter != NULL; gIter = gIter->next) {
 838         resource_t *child_rsc = (resource_t *) gIter->data;
 839         gboolean starting = FALSE;
 840         gboolean stopping = FALSE;
 841 
 842         child_rsc->cmds->create_actions(child_rsc, data_set);
 843         clone_update_pseudo_status(child_rsc, &stopping, &starting, &child_active);
 844         if (stopping && starting) {
 845             allow_dependent_migrations = FALSE;
 846         }
 847 
 848         child_stopping |= stopping;
 849         child_starting |= starting;
 850     }
 851 
 852     /* start */
 853     start = create_pseudo_resource_op(rsc, RSC_START, !child_starting, TRUE, data_set);
 854     started = create_pseudo_resource_op(rsc, RSC_STARTED, !child_starting, FALSE, data_set);
 855     started->priority = INFINITY;
 856 
 857     if (child_active || child_starting) {
 858         update_action_flags(started, pe_action_runnable, __FUNCTION__, __LINE__);
 859     }
 860 
 861     if (start_notify != NULL && *start_notify == NULL) {
 862         *start_notify = create_notification_boundaries(rsc, RSC_START, start, started, data_set);
 863     }
 864 
 865     /* stop */
 866     stop = create_pseudo_resource_op(rsc, RSC_STOP, !child_stopping, TRUE, data_set);
 867     stopped = create_pseudo_resource_op(rsc, RSC_STOPPED, !child_stopping, TRUE, data_set);
 868     stopped->priority = INFINITY;
 869     if (allow_dependent_migrations) {
 870         update_action_flags(stop, pe_action_migrate_runnable, __FUNCTION__, __LINE__);
 871     }
 872 
 873     if (stop_notify != NULL && *stop_notify == NULL) {
 874         *stop_notify = create_notification_boundaries(rsc, RSC_STOP, stop, stopped, data_set);
 875 
 876         if (start_notify && *start_notify && *stop_notify) {
 877             order_actions((*stop_notify)->post_done, (*start_notify)->pre, pe_order_optional);
 878         }
 879     }
 880 }
 881 
 882 void
 883 clone_internal_constraints(resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 884 {
 885     resource_t *last_rsc = NULL;
 886     GListPtr gIter;
 887     clone_variant_data_t *clone_data = NULL;
 888 
 889     get_clone_variant_data(clone_data, rsc);
 890 
 891     pe_rsc_trace(rsc, "Internal constraints for %s", rsc->id);
 892     new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set);
 893     new_rsc_order(rsc, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set);
 894     new_rsc_order(rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left, data_set);
 895 
 896     if (rsc->variant == pe_master) {
 897         new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_STOP, pe_order_optional, data_set);
 898         new_rsc_order(rsc, RSC_STARTED, rsc, RSC_PROMOTE, pe_order_runnable_left, data_set);
 899     }
 900 
 901     if (clone_data->ordered) {
 902         /* we have to maintain a consistent sorted child list when building order constraints */
 903         rsc->children = g_list_sort(rsc->children, sort_rsc_id);
 904     }
 905     for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 906         resource_t *child_rsc = (resource_t *) gIter->data;
 907 
 908         child_rsc->cmds->internal_constraints(child_rsc, data_set);
 909 
 910         order_start_start(rsc, child_rsc, pe_order_runnable_left | pe_order_implies_first_printed);
 911         new_rsc_order(child_rsc, RSC_START, rsc, RSC_STARTED, pe_order_implies_then_printed,
 912                       data_set);
 913         if (clone_data->ordered && last_rsc) {
 914             order_start_start(last_rsc, child_rsc, pe_order_optional);
 915         }
 916 
 917         order_stop_stop(rsc, child_rsc, pe_order_implies_first_printed);
 918         new_rsc_order(child_rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_implies_then_printed,
 919                       data_set);
 920         if (clone_data->ordered && last_rsc) {
 921             order_stop_stop(child_rsc, last_rsc, pe_order_optional);
 922         }
 923 
 924         last_rsc = child_rsc;
 925     }
 926 }
 927 
 928 bool
 929 assign_node(resource_t * rsc, node_t * node, gboolean force)
     /* [previous][next][first][last][top][bottom][index][help] */
 930 {
 931     bool changed = FALSE;
 932 
 933     if (rsc->children) {
 934 
 935         for (GListPtr gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 936             resource_t *child_rsc = (resource_t *) gIter->data;
 937 
 938             changed |= assign_node(child_rsc, node, force);
 939         }
 940 
 941         return changed;
 942     }
 943 
 944     if (rsc->allocated_to != NULL) {
 945         changed = true;
 946     }
 947 
 948     native_assign_node(rsc, NULL, node, force);
 949     return changed;
 950 }
 951 
 952 gboolean
 953 is_child_compatible(resource_t *child_rsc, node_t * local_node, enum rsc_role_e filter, gboolean current) 
     /* [previous][next][first][last][top][bottom][index][help] */
 954 {
 955     node_t *node = NULL;
 956     enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, current);
 957 
 958     if (is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
 959         /* We only want instances that haven't failed */
 960         node = child_rsc->fns->location(child_rsc, NULL, current);
 961     }
 962 
 963     if (filter != RSC_ROLE_UNKNOWN && next_role != filter) {
 964         crm_trace("Filtered %s", child_rsc->id);
 965         return FALSE;
 966     }
 967 
 968     if (node && local_node && node->details == local_node->details) {
 969         return TRUE;
 970 
 971     } else if (node) {
 972         crm_trace("%s - %s vs %s", child_rsc->id, node->details->uname,
 973                   local_node->details->uname);
 974 
 975     } else {
 976         crm_trace("%s - not allocated %d", child_rsc->id, current);
 977     }
 978     return FALSE;
 979 }
 980 
 981 resource_t *
 982 find_compatible_child(resource_t * local_child, resource_t * rsc, enum rsc_role_e filter, gboolean current)
     /* [previous][next][first][last][top][bottom][index][help] */
 983 {
 984     resource_t *pair = NULL;
 985     GListPtr gIter = NULL;
 986     GListPtr scratch = NULL;
 987     node_t *local_node = NULL;
 988 
 989     local_node = local_child->fns->location(local_child, NULL, current);
 990     if (local_node) {
 991         return find_compatible_child_by_node(local_child, local_node, rsc, filter, current);
 992     }
 993 
 994     scratch = g_hash_table_get_values(local_child->allowed_nodes);
 995     scratch = g_list_sort_with_data(scratch, sort_node_weight, NULL);
 996 
 997     gIter = scratch;
 998     for (; gIter != NULL; gIter = gIter->next) {
 999         node_t *node = (node_t *) gIter->data;
1000 
1001         pair = find_compatible_child_by_node(local_child, node, rsc, filter, current);
1002         if (pair) {
1003             goto done;
1004         }
1005     }
1006 
1007     pe_rsc_debug(rsc, "Can't pair %s with %s", local_child->id, rsc->id);
1008   done:
1009     g_list_free(scratch);
1010     return pair;
1011 }
1012 
1013 void
1014 clone_rsc_colocation_lh(resource_t * rsc_lh, resource_t * rsc_rh, rsc_colocation_t * constraint)
     /* [previous][next][first][last][top][bottom][index][help] */
1015 {
1016     /* -- Never called --
1017      *
1018      * Instead we add the colocation constraints to the child and call from there
1019      */
1020     CRM_ASSERT(FALSE);
1021 }
1022 
1023 void
1024 clone_rsc_colocation_rh(resource_t * rsc_lh, resource_t * rsc_rh, rsc_colocation_t * constraint)
     /* [previous][next][first][last][top][bottom][index][help] */
1025 {
1026     GListPtr gIter = NULL;
1027     gboolean do_interleave = FALSE;
1028     const char *interleave_s = NULL;
1029 
1030     CRM_CHECK(constraint != NULL, return);
1031     CRM_CHECK(rsc_lh != NULL, pe_err("rsc_lh was NULL for %s", constraint->id); return);
1032     CRM_CHECK(rsc_rh != NULL, pe_err("rsc_rh was NULL for %s", constraint->id); return);
1033     CRM_CHECK(rsc_lh->variant == pe_native, return);
1034 
1035     pe_rsc_trace(rsc_rh, "Processing constraint %s: %s -> %s %d",
1036                  constraint->id, rsc_lh->id, rsc_rh->id, constraint->score);
1037 
1038     /* only the LHS side needs to be labeled as interleave */
1039     interleave_s = g_hash_table_lookup(constraint->rsc_lh->meta, XML_RSC_ATTR_INTERLEAVE);
1040     if(crm_is_true(interleave_s) && constraint->rsc_lh->variant > pe_group) {
1041         // TODO: Do we actually care about multiple RH copies sharing a LH copy anymore?
1042         if (copies_per_node(constraint->rsc_lh) != copies_per_node(constraint->rsc_rh)) {
1043             crm_config_err("Cannot interleave %s and %s because"
1044                            " they do not support the same number of copies per node",
1045                            constraint->rsc_lh->id, constraint->rsc_rh->id);
1046 
1047         } else {
1048             do_interleave = TRUE;
1049         }
1050     }
1051 
1052     if (is_set(rsc_rh->flags, pe_rsc_provisional)) {
1053         pe_rsc_trace(rsc_rh, "%s is still provisional", rsc_rh->id);
1054         return;
1055 
1056     } else if (do_interleave) {
1057         resource_t *rh_child = NULL;
1058 
1059         rh_child = find_compatible_child(rsc_lh, rsc_rh, RSC_ROLE_UNKNOWN, FALSE);
1060 
1061         if (rh_child) {
1062             pe_rsc_debug(rsc_rh, "Pairing %s with %s", rsc_lh->id, rh_child->id);
1063             rsc_lh->cmds->rsc_colocation_lh(rsc_lh, rh_child, constraint);
1064 
1065         } else if (constraint->score >= INFINITY) {
1066             crm_notice("Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
1067             assign_node(rsc_lh, NULL, TRUE);
1068 
1069         } else {
1070             pe_rsc_debug(rsc_rh, "Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
1071         }
1072 
1073         return;
1074 
1075     } else if (constraint->score >= INFINITY) {
1076         GListPtr rhs = NULL;
1077 
1078         gIter = rsc_rh->children;
1079         for (; gIter != NULL; gIter = gIter->next) {
1080             resource_t *child_rsc = (resource_t *) gIter->data;
1081             node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
1082 
1083             if (chosen != NULL && is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
1084                 pe_rsc_trace(rsc_rh, "Allowing %s: %s %d", constraint->id, chosen->details->uname, chosen->weight);
1085                 rhs = g_list_prepend(rhs, chosen);
1086             }
1087         }
1088 
1089         node_list_exclude(rsc_lh->allowed_nodes, rhs, FALSE);
1090         g_list_free(rhs);
1091         return;
1092     }
1093 
1094     gIter = rsc_rh->children;
1095     for (; gIter != NULL; gIter = gIter->next) {
1096         resource_t *child_rsc = (resource_t *) gIter->data;
1097 
1098         child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint);
1099     }
1100 }
1101 
1102 enum action_tasks
1103 clone_child_action(action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
1104 {
1105     enum action_tasks result = no_action;
1106     resource_t *child = (resource_t *) action->rsc->children->data;
1107 
1108     if (safe_str_eq(action->task, "notify")
1109         || safe_str_eq(action->task, "notified")) {
1110 
1111         /* Find the action we're notifying about instead */
1112 
1113         int stop = 0;
1114         char *key = action->uuid;
1115         int lpc = strlen(key);
1116 
1117         for (; lpc > 0; lpc--) {
1118             if (key[lpc] == '_' && stop == 0) {
1119                 stop = lpc;
1120 
1121             } else if (key[lpc] == '_') {
1122                 char *task_mutable = NULL;
1123 
1124                 lpc++;
1125                 task_mutable = strdup(key + lpc);
1126                 task_mutable[stop - lpc] = 0;
1127 
1128                 crm_trace("Extracted action '%s' from '%s'", task_mutable, key);
1129                 result = get_complex_task(child, task_mutable, TRUE);
1130                 free(task_mutable);
1131                 break;
1132             }
1133         }
1134 
1135     } else {
1136         result = get_complex_task(child, action->task, TRUE);
1137     }
1138     return result;
1139 }
1140 
1141 enum pe_action_flags
1142 summary_action_flags(action_t * action, GListPtr children, node_t * node)
     /* [previous][next][first][last][top][bottom][index][help] */
1143 {
1144     GListPtr gIter = NULL;
1145     gboolean any_runnable = FALSE;
1146     gboolean check_runnable = TRUE;
1147     enum action_tasks task = clone_child_action(action);
1148     enum pe_action_flags flags = (pe_action_optional | pe_action_runnable | pe_action_pseudo);
1149     const char *task_s = task2text(task);
1150 
1151     for (gIter = children; gIter != NULL; gIter = gIter->next) {
1152         action_t *child_action = NULL;
1153         resource_t *child = (resource_t *) gIter->data;
1154 
1155         child_action = find_first_action(child->actions, NULL, task_s, child->children ? NULL : node);
1156         pe_rsc_trace(action->rsc, "Checking for %s in %s on %s (%s)", task_s, child->id,
1157                      node ? node->details->uname : "none", child_action?child_action->uuid:"NA");
1158         if (child_action) {
1159             enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);
1160 
1161             if (is_set(flags, pe_action_optional)
1162                 && is_set(child_flags, pe_action_optional) == FALSE) {
1163                 pe_rsc_trace(child, "%s is mandatory because of %s", action->uuid,
1164                              child_action->uuid);
1165                 flags = crm_clear_bit(__FUNCTION__, __LINE__, action->rsc->id, flags, pe_action_optional);
1166                 pe_clear_action_bit(action, pe_action_optional);
1167             }
1168             if (is_set(child_flags, pe_action_runnable)) {
1169                 any_runnable = TRUE;
1170             }
1171         }
1172     }
1173 
1174     if (check_runnable && any_runnable == FALSE) {
1175         pe_rsc_trace(action->rsc, "%s is not runnable because no children are", action->uuid);
1176         flags = crm_clear_bit(__FUNCTION__, __LINE__, action->rsc->id, flags, pe_action_runnable);
1177         if (node == NULL) {
1178             pe_clear_action_bit(action, pe_action_runnable);
1179         }
1180     }
1181 
1182     return flags;
1183 }
1184 
1185 enum pe_action_flags
1186 clone_action_flags(action_t * action, node_t * node)
     /* [previous][next][first][last][top][bottom][index][help] */
1187 {
1188     return summary_action_flags(action, action->rsc->children, node);
1189 }
1190 
1191 void
1192 clone_rsc_location(resource_t * rsc, rsc_to_node_t * constraint)
     /* [previous][next][first][last][top][bottom][index][help] */
1193 {
1194     GListPtr gIter = rsc->children;
1195 
1196     pe_rsc_trace(rsc, "Processing location constraint %s for %s", constraint->id, rsc->id);
1197 
1198     native_rsc_location(rsc, constraint);
1199 
1200     for (; gIter != NULL; gIter = gIter->next) {
1201         resource_t *child_rsc = (resource_t *) gIter->data;
1202 
1203         child_rsc->cmds->rsc_location(child_rsc, constraint);
1204     }
1205 }
1206 
1207 void
1208 clone_expand(resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
1209 {
1210     GListPtr gIter = NULL;
1211     clone_variant_data_t *clone_data = NULL;
1212 
1213     get_clone_variant_data(clone_data, rsc);
1214 
1215     gIter = rsc->actions;
1216     for (; gIter != NULL; gIter = gIter->next) {
1217         action_t *op = (action_t *) gIter->data;
1218 
1219         rsc->cmds->action_flags(op, NULL);
1220     }
1221 
1222     if (clone_data->start_notify) {
1223         collect_notification_data(rsc, TRUE, TRUE, clone_data->start_notify);
1224         expand_notification_data(rsc, clone_data->start_notify, data_set);
1225         create_notifications(rsc, clone_data->start_notify, data_set);
1226     }
1227 
1228     if (clone_data->stop_notify) {
1229         collect_notification_data(rsc, TRUE, TRUE, clone_data->stop_notify);
1230         expand_notification_data(rsc, clone_data->stop_notify, data_set);
1231         create_notifications(rsc, clone_data->stop_notify, data_set);
1232     }
1233 
1234     if (clone_data->promote_notify) {
1235         collect_notification_data(rsc, TRUE, TRUE, clone_data->promote_notify);
1236         expand_notification_data(rsc, clone_data->promote_notify, data_set);
1237         create_notifications(rsc, clone_data->promote_notify, data_set);
1238     }
1239 
1240     if (clone_data->demote_notify) {
1241         collect_notification_data(rsc, TRUE, TRUE, clone_data->demote_notify);
1242         expand_notification_data(rsc, clone_data->demote_notify, data_set);
1243         create_notifications(rsc, clone_data->demote_notify, data_set);
1244     }
1245 
1246     /* Now that the notifcations have been created we can expand the children */
1247 
1248     gIter = rsc->children;
1249     for (; gIter != NULL; gIter = gIter->next) {
1250         resource_t *child_rsc = (resource_t *) gIter->data;
1251 
1252         child_rsc->cmds->expand(child_rsc, data_set);
1253     }
1254 
1255     native_expand(rsc, data_set);
1256 
1257     /* The notifications are in the graph now, we can destroy the notify_data */
1258     free_notification_data(clone_data->demote_notify);
1259     clone_data->demote_notify = NULL;
1260     free_notification_data(clone_data->stop_notify);
1261     clone_data->stop_notify = NULL;
1262     free_notification_data(clone_data->start_notify);
1263     clone_data->start_notify = NULL;
1264     free_notification_data(clone_data->promote_notify);
1265     clone_data->promote_notify = NULL;
1266 }
1267 
1268 node_t *
1269 rsc_known_on(resource_t * rsc, GListPtr * list)
     /* [previous][next][first][last][top][bottom][index][help] */
1270 {
1271     GListPtr gIter = NULL;
1272     node_t *one = NULL;
1273     GListPtr result = NULL;
1274 
1275     if (rsc->children) {
1276 
1277         gIter = rsc->children;
1278         for (; gIter != NULL; gIter = gIter->next) {
1279             resource_t *child = (resource_t *) gIter->data;
1280 
1281             rsc_known_on(child, &result);
1282         }
1283 
1284     } else if (rsc->known_on) {
1285         result = g_hash_table_get_values(rsc->known_on);
1286     }
1287 
1288     if (result && g_list_length(result) == 1) {
1289         one = g_list_nth_data(result, 0);
1290     }
1291 
1292     if (list) {
1293         GListPtr gIter = NULL;
1294 
1295         gIter = result;
1296         for (; gIter != NULL; gIter = gIter->next) {
1297             node_t *node = (node_t *) gIter->data;
1298 
1299             if (*list == NULL || pe_find_node_id(*list, node->details->id) == NULL) {
1300                 *list = g_list_prepend(*list, node);
1301             }
1302         }
1303     }
1304 
1305     g_list_free(result);
1306     return one;
1307 }
1308 
1309 static resource_t *
1310 find_instance_on(resource_t * rsc, node_t * node)
     /* [previous][next][first][last][top][bottom][index][help] */
1311 {
1312     GListPtr gIter = NULL;
1313 
1314     gIter = rsc->children;
1315     for (; gIter != NULL; gIter = gIter->next) {
1316         GListPtr gIter2 = NULL;
1317         GListPtr known_list = NULL;
1318         resource_t *child = (resource_t *) gIter->data;
1319 
1320         rsc_known_on(child, &known_list);
1321 
1322         gIter2 = known_list;
1323         for (; gIter2 != NULL; gIter2 = gIter2->next) {
1324             node_t *known = (node_t *) gIter2->data;
1325 
1326             if (node->details == known->details) {
1327                 g_list_free(known_list);
1328                 return child;
1329             }
1330         }
1331         g_list_free(known_list);
1332     }
1333 
1334     return NULL;
1335 }
1336 
1337 gboolean
1338 clone_create_probe(resource_t * rsc, node_t * node, action_t * complete,
     /* [previous][next][first][last][top][bottom][index][help] */
1339                    gboolean force, pe_working_set_t * data_set)
1340 {
1341     GListPtr gIter = NULL;
1342     gboolean any_created = FALSE;
1343     clone_variant_data_t *clone_data = NULL;
1344 
1345     CRM_ASSERT(rsc);
1346     get_clone_variant_data(clone_data, rsc);
1347 
1348     rsc->children = g_list_sort(rsc->children, sort_rsc_id);
1349     if (rsc->children == NULL) {
1350         pe_warn("Clone %s has no children", rsc->id);
1351         return FALSE;
1352     }
1353 
1354     if (rsc->exclusive_discover) {
1355         node_t *allowed = g_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1356         if (allowed && allowed->rsc_discover_mode != pe_discover_exclusive) {
1357             /* exclusive discover is enabled and this node is not marked
1358              * as a node this resource should be discovered on
1359              *
1360              * remove the node from allowed_nodes so that the
1361              * notification contains only nodes that we might ever run
1362              * on
1363              */
1364             g_hash_table_remove(rsc->allowed_nodes, node->details->id);
1365 
1366             /* Bit of a shortcut - might as well take it */
1367             return FALSE;
1368         }
1369     }
1370 
1371     if (is_not_set(rsc->flags, pe_rsc_unique)
1372         && clone_data->clone_node_max == 1) {
1373         /* only look for one copy */
1374         resource_t *child = NULL;
1375 
1376         /* Try whoever we probed last time */
1377         child = find_instance_on(rsc, node);
1378         if (child) {
1379             return child->cmds->create_probe(child, node, complete, force, data_set);
1380         }
1381 
1382         /* Try whoever we plan on starting there */
1383         gIter = rsc->children;
1384         for (; gIter != NULL; gIter = gIter->next) {
1385             node_t *local_node = NULL;
1386             resource_t *child_rsc = (resource_t *) gIter->data;
1387 
1388             CRM_ASSERT(child_rsc);
1389             local_node = child_rsc->fns->location(child_rsc, NULL, FALSE);
1390             if (local_node == NULL) {
1391                 continue;
1392             }
1393 
1394             if (local_node->details == node->details) {
1395                 return child_rsc->cmds->create_probe(child_rsc, node, complete, force, data_set);
1396             }
1397         }
1398 
1399         /* Fall back to the first clone instance */
1400         CRM_ASSERT(rsc->children);
1401         child = rsc->children->data;
1402         return child->cmds->create_probe(child, node, complete, force, data_set);
1403     }
1404 
1405     gIter = rsc->children;
1406     for (; gIter != NULL; gIter = gIter->next) {
1407         resource_t *child_rsc = (resource_t *) gIter->data;
1408 
1409         if (child_rsc->cmds->create_probe(child_rsc, node, complete, force, data_set)) {
1410             any_created = TRUE;
1411         }
1412 
1413         if (any_created && is_not_set(rsc->flags, pe_rsc_unique)
1414             && clone_data->clone_node_max == 1) {
1415             /* only look for one copy (clone :0) */
1416             break;
1417         }
1418     }
1419 
1420     return any_created;
1421 }
1422 
1423 void
1424 clone_append_meta(resource_t * rsc, xmlNode * xml)
     /* [previous][next][first][last][top][bottom][index][help] */
1425 {
1426     char *name = NULL;
1427     clone_variant_data_t *clone_data = NULL;
1428 
1429     get_clone_variant_data(clone_data, rsc);
1430 
1431     name = crm_meta_name(XML_RSC_ATTR_UNIQUE);
1432     crm_xml_add(xml, name, is_set(rsc->flags, pe_rsc_unique) ? "true" : "false");
1433     free(name);
1434 
1435     name = crm_meta_name(XML_RSC_ATTR_NOTIFY);
1436     crm_xml_add(xml, name, is_set(rsc->flags, pe_rsc_notify) ? "true" : "false");
1437     free(name);
1438 
1439     name = crm_meta_name(XML_RSC_ATTR_INCARNATION_MAX);
1440     crm_xml_add_int(xml, name, clone_data->clone_max);
1441     free(name);
1442 
1443     name = crm_meta_name(XML_RSC_ATTR_INCARNATION_NODEMAX);
1444     crm_xml_add_int(xml, name, clone_data->clone_node_max);
1445     free(name);
1446 }
1447 
1448 GHashTable *
1449 clone_merge_weights(resource_t * rsc, const char *rhs, GHashTable * nodes, const char *attr,
     /* [previous][next][first][last][top][bottom][index][help] */
1450                     float factor, enum pe_weights flags)
1451 {
1452     return rsc_merge_weights(rsc, rhs, nodes, attr, factor, flags);
1453 }

/* [previous][next][first][last][top][bottom][index][help] */