root/lib/pengine/clone.c

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

DEFINITIONS

This source file includes following definitions.
  1. mark_as_orphan
  2. force_non_unique_clone
  3. find_clone_instance
  4. create_child_clone
  5. master_unpack
  6. clone_unpack
  7. clone_active
  8. short_print
  9. configured_role_str
  10. configured_role
  11. clone_print_xml
  12. is_set_recursive
  13. clone_print
  14. clone_free
  15. clone_resource_state

   1 /*
   2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
   3  *
   4  * This library is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Lesser General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2.1 of the License, or (at your option) any later version.
   8  *
   9  * This library 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  * Lesser General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU Lesser 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/pengine/rules.h>
  22 #include <crm/pengine/status.h>
  23 #include <crm/pengine/internal.h>
  24 #include <unpack.h>
  25 #include <crm/msg_xml.h>
  26 
  27 #define VARIANT_CLONE 1
  28 #include "./variant.h"
  29 
  30 void force_non_unique_clone(resource_t * rsc, const char *rid, pe_working_set_t * data_set);
  31 resource_t *create_child_clone(resource_t * rsc, int sub_id, pe_working_set_t * data_set);
  32 
  33 static void
  34 mark_as_orphan(resource_t * rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
  35 {
  36     GListPtr gIter = rsc->children;
  37 
  38     set_bit(rsc->flags, pe_rsc_orphan);
  39 
  40     for (; gIter != NULL; gIter = gIter->next) {
  41         resource_t *child = (resource_t *) gIter->data;
  42 
  43         mark_as_orphan(child);
  44     }
  45 }
  46 
  47 void
  48 force_non_unique_clone(resource_t * rsc, const char *rid, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
  49 {
  50     if (pe_rsc_is_clone(rsc)) {
  51         clone_variant_data_t *clone_data = NULL;
  52 
  53         get_clone_variant_data(clone_data, rsc);
  54 
  55         crm_config_warn("Clones %s contains non-OCF resource %s and so "
  56                         "can only be used as an anonymous clone. "
  57                         "Set the " XML_RSC_ATTR_UNIQUE " meta attribute to false", rsc->id, rid);
  58 
  59         clone_data->clone_node_max = 1;
  60         clone_data->clone_max = g_list_length(data_set->nodes);
  61         clear_bit_recursive(rsc, pe_rsc_unique);
  62     }
  63 }
  64 
  65 resource_t *
  66 find_clone_instance(resource_t * rsc, const char *sub_id, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
  67 {
  68     char *child_id = NULL;
  69     resource_t *child = NULL;
  70     const char *child_base = NULL;
  71     clone_variant_data_t *clone_data = NULL;
  72 
  73     get_clone_variant_data(clone_data, rsc);
  74 
  75     child_base = ID(clone_data->xml_obj_child);
  76     child_id = crm_concat(child_base, sub_id, ':');
  77     child = pe_find_resource(rsc->children, child_id);
  78 
  79     free(child_id);
  80     return child;
  81 }
  82 
  83 resource_t *
  84 create_child_clone(resource_t * rsc, int sub_id, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
  85 {
  86     gboolean as_orphan = FALSE;
  87     char *inc_num = NULL;
  88     char *inc_max = NULL;
  89     resource_t *child_rsc = NULL;
  90     xmlNode *child_copy = NULL;
  91     clone_variant_data_t *clone_data = NULL;
  92 
  93     get_clone_variant_data(clone_data, rsc);
  94 
  95     CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE);
  96 
  97     if (sub_id < 0) {
  98         as_orphan = TRUE;
  99         sub_id = clone_data->total_clones;
 100     }
 101     inc_num = crm_itoa(sub_id);
 102     inc_max = crm_itoa(clone_data->clone_max);
 103 
 104     child_copy = copy_xml(clone_data->xml_obj_child);
 105 
 106     crm_xml_add(child_copy, XML_RSC_ATTR_INCARNATION, inc_num);
 107 
 108     if (common_unpack(child_copy, &child_rsc, rsc, data_set) == FALSE) {
 109         pe_err("Failed unpacking resource %s", crm_element_value(child_copy, XML_ATTR_ID));
 110         child_rsc = NULL;
 111         goto bail;
 112     }
 113 /*  child_rsc->globally_unique = rsc->globally_unique; */
 114 
 115     CRM_ASSERT(child_rsc);
 116     clone_data->total_clones += 1;
 117     pe_rsc_trace(child_rsc, "Setting clone attributes for: %s", child_rsc->id);
 118     rsc->children = g_list_append(rsc->children, child_rsc);
 119     if (as_orphan) {
 120         mark_as_orphan(child_rsc);
 121     }
 122 
 123     add_hash_param(child_rsc->meta, XML_RSC_ATTR_INCARNATION_MAX, inc_max);
 124 
 125     print_resource(LOG_DEBUG_3, "Added ", child_rsc, FALSE);
 126 
 127   bail:
 128     free(inc_num);
 129     free(inc_max);
 130 
 131     return child_rsc;
 132 }
 133 
 134 gboolean
 135 master_unpack(resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 136 {
 137     const char *master_max = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_MASTER_MAX);
 138     const char *master_node_max = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_MASTER_NODEMAX);
 139 
 140     g_hash_table_replace(rsc->meta, strdup("stateful"), strdup(XML_BOOLEAN_TRUE));
 141     if (clone_unpack(rsc, data_set)) {
 142         clone_variant_data_t *clone_data = NULL;
 143 
 144         get_clone_variant_data(clone_data, rsc);
 145         clone_data->master_max = crm_parse_int(master_max, "1");
 146         clone_data->master_node_max = crm_parse_int(master_node_max, "1");
 147         return TRUE;
 148     }
 149     return FALSE;
 150 }
 151 
 152 gboolean
 153 clone_unpack(resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 154 {
 155     int lpc = 0;
 156     xmlNode *a_child = NULL;
 157     xmlNode *xml_obj = rsc->xml;
 158     clone_variant_data_t *clone_data = NULL;
 159 
 160     const char *ordered = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_ORDERED);
 161     const char *interleave = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERLEAVE);
 162     const char *max_clones = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_MAX);
 163     const char *max_clones_node = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_NODEMAX);
 164 
 165     pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
 166 
 167     clone_data = calloc(1, sizeof(clone_variant_data_t));
 168     rsc->variant_opaque = clone_data;
 169 
 170     clone_data->active_clones = 0;
 171     clone_data->xml_obj_child = NULL;
 172     clone_data->clone_node_max = crm_parse_int(max_clones_node, "1");
 173 
 174     if (max_clones) {
 175         clone_data->clone_max = crm_parse_int(max_clones, "1");
 176 
 177     } else if (g_list_length(data_set->nodes) > 0) {
 178         clone_data->clone_max = g_list_length(data_set->nodes);
 179 
 180     } else {
 181         clone_data->clone_max = 1;      /* Handy during crm_verify */
 182     }
 183 
 184     clone_data->interleave = crm_is_true(interleave);
 185     clone_data->ordered = crm_is_true(ordered);
 186 
 187     if ((rsc->flags & pe_rsc_unique) == 0 && clone_data->clone_node_max > 1) {
 188         crm_config_err("Anonymous clones (%s) may only support one copy per node", rsc->id);
 189         clone_data->clone_node_max = 1;
 190     }
 191 
 192     pe_rsc_trace(rsc, "Options for %s", rsc->id);
 193     pe_rsc_trace(rsc, "\tClone max: %d", clone_data->clone_max);
 194     pe_rsc_trace(rsc, "\tClone node max: %d", clone_data->clone_node_max);
 195     pe_rsc_trace(rsc, "\tClone is unique: %s",
 196                  is_set(rsc->flags, pe_rsc_unique) ? "true" : "false");
 197 
 198     // Clones may contain a single group or primitive
 199     for (a_child = __xml_first_child(xml_obj); a_child != NULL;
 200          a_child = __xml_next_element(a_child)) {
 201 
 202         if (crm_str_eq((const char *)a_child->name, XML_CIB_TAG_RESOURCE, TRUE)
 203         || crm_str_eq((const char *)a_child->name, XML_CIB_TAG_GROUP, TRUE)) {
 204             clone_data->xml_obj_child = a_child;
 205             break;
 206         }
 207     }
 208 
 209     if (clone_data->xml_obj_child == NULL) {
 210         crm_config_err("%s has nothing to clone", rsc->id);
 211         return FALSE;
 212     }
 213 
 214     /*
 215      * Make clones ever so slightly sticky by default
 216      *
 217      * This helps ensure clone instances are not shuffled around the cluster
 218      * for no benefit in situations when pre-allocation is not appropriate
 219      */
 220     if (g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_STICKINESS) == NULL) {
 221         add_hash_param(rsc->meta, XML_RSC_ATTR_STICKINESS, "1");
 222     }
 223 
 224     pe_rsc_trace(rsc, "\tClone is unique (fixed): %s",
 225                  is_set(rsc->flags, pe_rsc_unique) ? "true" : "false");
 226     clone_data->notify_confirm = is_set(rsc->flags, pe_rsc_notify);
 227     add_hash_param(rsc->meta, XML_RSC_ATTR_UNIQUE,
 228                    is_set(rsc->flags, pe_rsc_unique) ? XML_BOOLEAN_TRUE : XML_BOOLEAN_FALSE);
 229 
 230     for (lpc = 0; lpc < clone_data->clone_max; lpc++) {
 231         if (create_child_clone(rsc, lpc, data_set) == NULL) {
 232             return FALSE;
 233         }
 234     }
 235 
 236     if (clone_data->clone_max == 0) {
 237         /* create one so that unpack_find_resource() will hook up
 238          * any orphans up to the parent correctly
 239          */
 240         if (create_child_clone(rsc, -1, data_set) == NULL) {
 241             return FALSE;
 242         }
 243     }
 244 
 245     pe_rsc_trace(rsc, "Added %d children to resource %s...", clone_data->clone_max, rsc->id);
 246     return TRUE;
 247 }
 248 
 249 gboolean
 250 clone_active(resource_t * rsc, gboolean all)
     /* [previous][next][first][last][top][bottom][index][help] */
 251 {
 252     GListPtr gIter = rsc->children;
 253 
 254     for (; gIter != NULL; gIter = gIter->next) {
 255         resource_t *child_rsc = (resource_t *) gIter->data;
 256         gboolean child_active = child_rsc->fns->active(child_rsc, all);
 257 
 258         if (all == FALSE && child_active) {
 259             return TRUE;
 260         } else if (all && child_active == FALSE) {
 261             return FALSE;
 262         }
 263     }
 264 
 265     if (all) {
 266         return TRUE;
 267     } else {
 268         return FALSE;
 269     }
 270 }
 271 
 272 static void
 273 short_print(char *list, const char *prefix, const char *type, const char *suffix, long options, void *print_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 274 {
 275     if(suffix == NULL) {
 276         suffix = "";
 277     }
 278 
 279     if (list) {
 280         if (options & pe_print_html) {
 281             status_print("<li>");
 282         }
 283         status_print("%s%s: [%s ]%s", prefix, type, list, suffix);
 284 
 285         if (options & pe_print_html) {
 286             status_print("</li>\n");
 287 
 288         } else if (options & pe_print_suppres_nl) {
 289             /* nothing */
 290         } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) {
 291             status_print("\n");
 292         }
 293 
 294     }
 295 }
 296 
 297 static const char *
 298 configured_role_str(resource_t * rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 299 {
 300     const char *target_role = g_hash_table_lookup(rsc->meta,
 301                                                   XML_RSC_ATTR_TARGET_ROLE);
 302 
 303     if ((target_role == NULL) && rsc->children && rsc->children->data) {
 304         target_role = g_hash_table_lookup(((resource_t*)rsc->children->data)->meta,
 305                                           XML_RSC_ATTR_TARGET_ROLE);
 306     }
 307     return target_role;
 308 }
 309 
 310 static enum rsc_role_e
 311 configured_role(resource_t * rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 312 {
 313     const char *target_role = configured_role_str(rsc);
 314 
 315     if (target_role) {
 316         return text2role(target_role);
 317     }
 318     return RSC_ROLE_UNKNOWN;
 319 }
 320 
 321 static void
 322 clone_print_xml(resource_t * rsc, const char *pre_text, long options, void *print_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 323 {
 324     int is_master_slave = rsc->variant == pe_master ? 1 : 0;
 325     char *child_text = crm_concat(pre_text, "   ", ' ');
 326     const char *target_role = configured_role_str(rsc);
 327     GListPtr gIter = rsc->children;
 328 
 329     status_print("%s<clone ", pre_text);
 330     status_print("id=\"%s\" ", rsc->id);
 331     status_print("multi_state=\"%s\" ", is_master_slave ? "true" : "false");
 332     status_print("unique=\"%s\" ", is_set(rsc->flags, pe_rsc_unique) ? "true" : "false");
 333     status_print("managed=\"%s\" ", is_set(rsc->flags, pe_rsc_managed) ? "true" : "false");
 334     status_print("failed=\"%s\" ", is_set(rsc->flags, pe_rsc_failed) ? "true" : "false");
 335     status_print("failure_ignored=\"%s\" ",
 336                  is_set(rsc->flags, pe_rsc_failure_ignored) ? "true" : "false");
 337     if (target_role) {
 338         status_print("target_role=\"%s\" ", target_role);
 339     }
 340     status_print(">\n");
 341 
 342     for (; gIter != NULL; gIter = gIter->next) {
 343         resource_t *child_rsc = (resource_t *) gIter->data;
 344 
 345         child_rsc->fns->print(child_rsc, child_text, options, print_data);
 346     }
 347 
 348     status_print("%s</clone>\n", pre_text);
 349     free(child_text);
 350 }
 351 
 352 bool is_set_recursive(resource_t * rsc, long long flag, bool any)
     /* [previous][next][first][last][top][bottom][index][help] */
 353 {
 354     GListPtr gIter;
 355     bool all = !any;
 356 
 357     if(is_set(rsc->flags, flag)) {
 358         if(any) {
 359             return TRUE;
 360         }
 361     } else if(all) {
 362         return FALSE;
 363     }
 364 
 365     for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 366         if(is_set_recursive(gIter->data, flag, any)) {
 367             if(any) {
 368                 return TRUE;
 369             }
 370 
 371         } else if(all) {
 372             return FALSE;
 373         }
 374     }
 375 
 376     if(all) {
 377         return TRUE;
 378     }
 379     return FALSE;
 380 }
 381 
 382 void
 383 clone_print(resource_t * rsc, const char *pre_text, long options, void *print_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 384 {
 385     char *list_text = NULL;
 386     char *child_text = NULL;
 387     char *stopped_list = NULL;
 388     const char *type = "Clone";
 389 
 390     GListPtr master_list = NULL;
 391     GListPtr started_list = NULL;
 392     GListPtr gIter = rsc->children;
 393 
 394     clone_variant_data_t *clone_data = NULL;
 395     int active_instances = 0;
 396 
 397     if (pre_text == NULL) {
 398         pre_text = " ";
 399     }
 400 
 401     if (options & pe_print_xml) {
 402         clone_print_xml(rsc, pre_text, options, print_data);
 403         return;
 404     }
 405 
 406     get_clone_variant_data(clone_data, rsc);
 407 
 408     child_text = crm_concat(pre_text, "   ", ' ');
 409 
 410     if (rsc->variant == pe_master) {
 411         type = "Master/Slave";
 412     }
 413 
 414     status_print("%s%s Set: %s [%s]%s%s",
 415                  pre_text ? pre_text : "", type, rsc->id, ID(clone_data->xml_obj_child),
 416                  is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "",
 417                  is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)");
 418 
 419     if (options & pe_print_html) {
 420         status_print("\n<ul>\n");
 421 
 422     } else if ((options & pe_print_log) == 0) {
 423         status_print("\n");
 424     }
 425 
 426     for (; gIter != NULL; gIter = gIter->next) {
 427         gboolean print_full = FALSE;
 428         resource_t *child_rsc = (resource_t *) gIter->data;
 429 
 430         if (options & pe_print_clone_details) {
 431             print_full = TRUE;
 432         }
 433 
 434         if (child_rsc->fns->active(child_rsc, FALSE) == FALSE) {
 435             /* Inactive clone */
 436             if (is_set(child_rsc->flags, pe_rsc_orphan)) {
 437                 continue;
 438 
 439             } else if (is_set(rsc->flags, pe_rsc_unique)) {
 440                 print_full = TRUE;
 441 
 442             } else if (is_not_set(options, pe_print_clone_active)) {
 443                 stopped_list = add_list_element(stopped_list, child_rsc->id);
 444             }
 445 
 446         } else if (is_set_recursive(child_rsc, pe_rsc_unique, TRUE)
 447                    || is_set_recursive(child_rsc, pe_rsc_orphan, TRUE)
 448                    || is_set_recursive(child_rsc, pe_rsc_managed, FALSE) == FALSE
 449                    || is_set_recursive(child_rsc, pe_rsc_failed, TRUE)) {
 450 
 451             /* Unique, unmanaged or failed clone */
 452             print_full = TRUE;
 453 
 454         } else if (is_set(options, pe_print_pending) && child_rsc->pending_task != NULL) {
 455             /* In a pending state */
 456             print_full = TRUE;
 457 
 458         } else if (child_rsc->fns->active(child_rsc, TRUE)) {
 459             /* Fully active anonymous clone */
 460             node_t *location = child_rsc->fns->location(child_rsc, NULL, TRUE);
 461 
 462             if (location) {
 463                 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
 464 
 465                 if (location->details->online == FALSE && location->details->unclean) {
 466                     print_full = TRUE;
 467 
 468                 } else if (a_role > RSC_ROLE_SLAVE) {
 469                     /* And active on a single node as master */
 470                     master_list = g_list_append(master_list, location);
 471 
 472                 } else {
 473                     /* And active on a single node as started/slave */
 474                     started_list = g_list_append(started_list, location);
 475                 }
 476 
 477             } else {
 478                 /* uncolocated group - bleh */
 479                 print_full = TRUE;
 480             }
 481 
 482         } else {
 483             /* Partially active anonymous clone */
 484             print_full = TRUE;
 485         }
 486 
 487         if (print_full) {
 488             if (options & pe_print_html) {
 489                 status_print("<li>\n");
 490             }
 491             child_rsc->fns->print(child_rsc, child_text, options, print_data);
 492             if (options & pe_print_html) {
 493                 status_print("</li>\n");
 494             }
 495         }
 496     }
 497 
 498     /* Masters */
 499     master_list = g_list_sort(master_list, sort_node_uname);
 500     for (gIter = master_list; gIter; gIter = gIter->next) {
 501         node_t *host = gIter->data;
 502 
 503         list_text = add_list_element(list_text, host->details->uname);
 504         active_instances++;
 505     }
 506 
 507     short_print(list_text, child_text, "Masters", NULL, options, print_data);
 508     g_list_free(master_list);
 509     free(list_text);
 510     list_text = NULL;
 511 
 512     /* Started/Slaves */
 513     started_list = g_list_sort(started_list, sort_node_uname);
 514     for (gIter = started_list; gIter; gIter = gIter->next) {
 515         node_t *host = gIter->data;
 516 
 517         list_text = add_list_element(list_text, host->details->uname);
 518         active_instances++;
 519     }
 520 
 521     if(rsc->variant == pe_master) {
 522         enum rsc_role_e role = configured_role(rsc);
 523 
 524         if(role == RSC_ROLE_SLAVE) {
 525             short_print(list_text, child_text, "Slaves (target-role)", NULL, options, print_data);
 526         } else {
 527             short_print(list_text, child_text, "Slaves", NULL, options, print_data);
 528         }
 529 
 530     } else {
 531         short_print(list_text, child_text, "Started", NULL, options, print_data);
 532     }
 533 
 534     g_list_free(started_list);
 535     free(list_text);
 536     list_text = NULL;
 537 
 538     if (is_not_set(options, pe_print_clone_active)) {
 539         const char *state = "Stopped";
 540         enum rsc_role_e role = configured_role(rsc);
 541 
 542         if (role == RSC_ROLE_STOPPED) {
 543             state = "Stopped (disabled)";
 544         }
 545 
 546         if (is_not_set(rsc->flags, pe_rsc_unique)
 547             && (clone_data->clone_max > active_instances)) {
 548 
 549             GListPtr nIter;
 550             GListPtr list = g_hash_table_get_values(rsc->allowed_nodes);
 551 
 552             /* Custom stopped list for non-unique clones */
 553             free(stopped_list); stopped_list = NULL;
 554 
 555             if (g_list_length(list) == 0) {
 556                 /* Clusters with symmetrical=false haven't calculated allowed_nodes yet
 557                  * If we've not probed for them yet, the Stopped list will be empty
 558                  */
 559                 list = g_hash_table_get_values(rsc->known_on);
 560             }
 561 
 562             list = g_list_sort(list, sort_node_uname);
 563             for (nIter = list; nIter != NULL; nIter = nIter->next) {
 564                 node_t *node = (node_t *)nIter->data;
 565 
 566                 if (pe_find_node(rsc->running_on, node->details->uname) == NULL) {
 567                     stopped_list = add_list_element(stopped_list, node->details->uname);
 568                 }
 569             }
 570             g_list_free(list);
 571         }
 572 
 573         short_print(stopped_list, child_text, state, NULL, options, print_data);
 574         free(stopped_list);
 575     }
 576 
 577     if (options & pe_print_html) {
 578         status_print("</ul>\n");
 579     }
 580 
 581     free(child_text);
 582 }
 583 
 584 void
 585 clone_free(resource_t * rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 586 {
 587     GListPtr gIter = rsc->children;
 588     clone_variant_data_t *clone_data = NULL;
 589 
 590     get_clone_variant_data(clone_data, rsc);
 591 
 592     pe_rsc_trace(rsc, "Freeing %s", rsc->id);
 593 
 594     for (; gIter != NULL; gIter = gIter->next) {
 595         resource_t *child_rsc = (resource_t *) gIter->data;
 596 
 597         CRM_ASSERT(child_rsc);
 598         pe_rsc_trace(child_rsc, "Freeing child %s", child_rsc->id);
 599         free_xml(child_rsc->xml);
 600         child_rsc->xml = NULL;
 601         /* There could be a saved unexpanded xml */
 602         free_xml(child_rsc->orig_xml);
 603         child_rsc->orig_xml = NULL;
 604         child_rsc->fns->free(child_rsc);
 605     }
 606 
 607     g_list_free(rsc->children);
 608 
 609     if (clone_data) {
 610         CRM_ASSERT(clone_data->demote_notify == NULL);
 611         CRM_ASSERT(clone_data->stop_notify == NULL);
 612         CRM_ASSERT(clone_data->start_notify == NULL);
 613         CRM_ASSERT(clone_data->promote_notify == NULL);
 614     }
 615 
 616     common_free(rsc);
 617 }
 618 
 619 enum rsc_role_e
 620 clone_resource_state(const resource_t * rsc, gboolean current)
     /* [previous][next][first][last][top][bottom][index][help] */
 621 {
 622     enum rsc_role_e clone_role = RSC_ROLE_UNKNOWN;
 623     GListPtr gIter = rsc->children;
 624 
 625     for (; gIter != NULL; gIter = gIter->next) {
 626         resource_t *child_rsc = (resource_t *) gIter->data;
 627         enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, current);
 628 
 629         if (a_role > clone_role) {
 630             clone_role = a_role;
 631         }
 632     }
 633 
 634     pe_rsc_trace(rsc, "%s role: %s", rsc->id, role2text(clone_role));
 635     return clone_role;
 636 }

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