root/tools/crm_resource_runtime.c

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

DEFINITIONS

This source file includes following definitions.
  1. do_find_resource
  2. cli_resource_search
  3. find_resource_attr
  4. find_matching_attr_resources_recursive
  5. find_matching_attr_resources
  6. cli_resource_update_attribute
  7. cli_resource_delete_attribute
  8. send_lrm_rsc_op
  9. rsc_fail_name
  10. clear_rsc_history
  11. clear_rsc_failures
  12. clear_rsc_fail_attrs
  13. cli_resource_delete
  14. cli_cleanup_all
  15. cli_resource_check
  16. cli_resource_fail
  17. generate_resource_params
  18. resource_is_running_on
  19. get_active_resources
  20. dump_list
  21. display_list
  22. update_working_set_xml
  23. update_working_set_from_cib
  24. update_dataset
  25. max_delay_for_resource
  26. max_delay_in
  27. cli_resource_restart
  28. action_is_pending
  29. actions_are_pending
  30. print_pending_actions
  31. wait_till_stable
  32. cli_resource_execute_from_params
  33. cli_resource_execute
  34. cli_resource_move
  35. cli_resource_why_without_rsc_and_host
  36. cli_resource_why_with_rsc_and_host
  37. cli_resource_why_without_rsc_with_host
  38. cli_resource_why_with_rsc_without_host
  39. cli_resource_why

   1 /*
   2  * Copyright 2004-2020 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_resource.h>
  11 #include <crm/common/ipc_controld.h>
  12 #include <crm/common/lists_internal.h>
  13 #include <crm/common/xml_internal.h>
  14 
  15 static int
  16 do_find_resource(const char *rsc, pe_resource_t * the_rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
  17 {
  18     int found = 0;
  19     GListPtr lpc = NULL;
  20 
  21     for (lpc = the_rsc->running_on; lpc != NULL; lpc = lpc->next) {
  22         pe_node_t *node = (pe_node_t *) lpc->data;
  23 
  24         if (BE_QUIET) {
  25             fprintf(stdout, "%s\n", node->details->uname);
  26         } else {
  27             const char *state = "";
  28 
  29             if (!pe_rsc_is_clone(the_rsc) && the_rsc->fns->state(the_rsc, TRUE) == RSC_ROLE_MASTER) {
  30                 state = "Master";
  31             }
  32             fprintf(stdout, "resource %s is running on: %s %s\n", rsc, node->details->uname, state);
  33         }
  34 
  35         found++;
  36     }
  37 
  38     if (BE_QUIET == FALSE && found == 0) {
  39         fprintf(stderr, "resource %s is NOT running\n", rsc);
  40     }
  41 
  42     return found;
  43 }
  44 
  45 int
  46 cli_resource_search(pe_resource_t *rsc, const char *requested_name,
     /* [previous][next][first][last][top][bottom][index][help] */
  47                     pe_working_set_t *data_set)
  48 {
  49     int found = 0;
  50     pe_resource_t *parent = uber_parent(rsc);
  51 
  52     if (pe_rsc_is_clone(rsc)) {
  53         for (GListPtr iter = rsc->children; iter != NULL; iter = iter->next) {
  54             found += do_find_resource(requested_name, iter->data, data_set);
  55         }
  56 
  57     /* The anonymous clone children's common ID is supplied */
  58     } else if (pe_rsc_is_clone(parent)
  59                && !pcmk_is_set(rsc->flags, pe_rsc_unique)
  60                && rsc->clone_name
  61                && pcmk__str_eq(requested_name, rsc->clone_name, pcmk__str_casei)
  62                && !pcmk__str_eq(requested_name, rsc->id, pcmk__str_casei)) {
  63 
  64         for (GListPtr iter = parent->children; iter; iter = iter->next) {
  65             found += do_find_resource(requested_name, iter->data, data_set);
  66         }
  67 
  68     } else {
  69         found += do_find_resource(requested_name, rsc, data_set);
  70     }
  71 
  72     return found;
  73 }
  74 
  75 #define XPATH_MAX 1024
  76 
  77 // \return Standard Pacemaker return code
  78 static int
  79 find_resource_attr(cib_t * the_cib, const char *attr, const char *rsc, const char *attr_set_type,
     /* [previous][next][first][last][top][bottom][index][help] */
  80                    const char *set_name, const char *attr_id, const char *attr_name, char **value)
  81 {
  82     int offset = 0;
  83     int rc = pcmk_rc_ok;
  84     xmlNode *xml_search = NULL;
  85     char *xpath_string = NULL;
  86 
  87     if(value) {
  88         *value = NULL;
  89     }
  90 
  91     if(the_cib == NULL) {
  92         return ENOTCONN;
  93     }
  94 
  95     xpath_string = calloc(1, XPATH_MAX);
  96     offset +=
  97         snprintf(xpath_string + offset, XPATH_MAX - offset, "%s", get_object_path("resources"));
  98 
  99     offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "//*[@id=\"%s\"]", rsc);
 100 
 101     if (attr_set_type) {
 102         offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "/%s", attr_set_type);
 103         if (set_name) {
 104             offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "[@id=\"%s\"]", set_name);
 105         }
 106     }
 107 
 108     offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "//nvpair[");
 109     if (attr_id) {
 110         offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "@id=\"%s\"", attr_id);
 111     }
 112 
 113     if (attr_name) {
 114         if (attr_id) {
 115             offset += snprintf(xpath_string + offset, XPATH_MAX - offset, " and ");
 116         }
 117         offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "@name=\"%s\"", attr_name);
 118     }
 119     offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "]");
 120     CRM_LOG_ASSERT(offset > 0);
 121 
 122     rc = the_cib->cmds->query(the_cib, xpath_string, &xml_search,
 123                               cib_sync_call | cib_scope_local | cib_xpath);
 124     rc = pcmk_legacy2rc(rc);
 125 
 126     if (rc != pcmk_rc_ok) {
 127         goto bail;
 128     }
 129 
 130     crm_log_xml_debug(xml_search, "Match");
 131     if (xml_has_children(xml_search)) {
 132         xmlNode *child = NULL;
 133 
 134         rc = EINVAL;
 135         printf("Multiple attributes match name=%s\n", attr_name);
 136 
 137         for (child = pcmk__xml_first_child(xml_search); child != NULL;
 138              child = pcmk__xml_next(child)) {
 139             printf("  Value: %s \t(id=%s)\n",
 140                    crm_element_value(child, XML_NVPAIR_ATTR_VALUE), ID(child));
 141         }
 142 
 143     } else if(value) {
 144         const char *tmp = crm_element_value(xml_search, attr);
 145 
 146         if (tmp) {
 147             *value = strdup(tmp);
 148         }
 149     }
 150 
 151   bail:
 152     free(xpath_string);
 153     free_xml(xml_search);
 154     return rc;
 155 }
 156 
 157 /* PRIVATE. Use the find_matching_attr_resources instead. */
 158 static void
 159 find_matching_attr_resources_recursive(GList/* <pe_resource_t*> */ ** result, pe_resource_t * rsc, const char * rsc_id, 
     /* [previous][next][first][last][top][bottom][index][help] */
 160                                        const char * attr_set, const char * attr_set_type, const char * attr_id,
 161                                        const char * attr_name, cib_t * cib, const char * cmd, int depth)
 162 {
 163     int rc = pcmk_rc_ok;
 164     char *lookup_id = clone_strip(rsc->id);
 165     char *local_attr_id = NULL;
 166 
 167     /* visit the children */
 168     for(GList *gIter = rsc->children; gIter; gIter = gIter->next) {
 169         find_matching_attr_resources_recursive(result, (pe_resource_t*)gIter->data,
 170                                                rsc_id, attr_set, attr_set_type,
 171                                                attr_id, attr_name, cib, cmd, depth+1);
 172         /* do it only once for clones */
 173         if(pe_clone == rsc->variant) {
 174             break;
 175         }
 176     }
 177 
 178     rc = find_resource_attr(cib, XML_ATTR_ID, lookup_id, attr_set_type, attr_set, attr_id, attr_name, &local_attr_id);
 179     /* Post-order traversal. 
 180      * The root is always on the list and it is the last item. */
 181     if((0 == depth) || (pcmk_rc_ok == rc)) {
 182         /* push the head */
 183         *result = g_list_append(*result, rsc);
 184     }
 185 
 186     free(local_attr_id);
 187     free(lookup_id);
 188 }
 189 
 190 
 191 /* The result is a linearized pre-ordered tree of resources. */
 192 static GList/*<pe_resource_t*>*/ *
 193 find_matching_attr_resources(pe_resource_t * rsc, const char * rsc_id, const char * attr_set,
     /* [previous][next][first][last][top][bottom][index][help] */
 194                              const char * attr_set_type, const char * attr_id,
 195                              const char * attr_name, cib_t * cib, const char * cmd, gboolean force)
 196 {
 197     int rc = pcmk_rc_ok;
 198     char *lookup_id = NULL;
 199     char *local_attr_id = NULL;
 200     GList * result = NULL;
 201     /* If --force is used, update only the requested resource (clone or primitive).
 202      * Otherwise, if the primitive has the attribute, use that.
 203      * Otherwise use the clone. */
 204     if(force == TRUE) {
 205         return g_list_append(result, rsc);
 206     }
 207     if(rsc->parent && pe_clone == rsc->parent->variant) {
 208         int rc = pcmk_rc_ok;
 209         char *local_attr_id = NULL;
 210         rc = find_resource_attr(cib, XML_ATTR_ID, rsc_id, attr_set_type, attr_set, attr_id, attr_name, &local_attr_id);
 211         free(local_attr_id);
 212 
 213         if(rc != pcmk_rc_ok) {
 214             rsc = rsc->parent;
 215             if (BE_QUIET == FALSE) {
 216                 printf("Performing %s of '%s' on '%s', the parent of '%s'\n", cmd, attr_name, rsc->id, rsc_id);
 217             }
 218         }
 219         return g_list_append(result, rsc);
 220     } else if(rsc->parent == NULL && rsc->children && pe_clone == rsc->variant) {
 221         pe_resource_t *child = rsc->children->data;
 222 
 223         if(child->variant == pe_native) {
 224             lookup_id = clone_strip(child->id); /* Could be a cloned group! */
 225             rc = find_resource_attr(cib, XML_ATTR_ID, lookup_id, attr_set_type, attr_set, attr_id, attr_name, &local_attr_id);
 226 
 227             if(rc == pcmk_rc_ok) {
 228                 rsc = child;
 229                 if (BE_QUIET == FALSE) {
 230                     printf("A value for '%s' already exists in child '%s', performing %s on that instead of '%s'\n", attr_name, lookup_id, cmd, rsc_id);
 231                 }
 232             }
 233 
 234             free(local_attr_id);
 235             free(lookup_id);
 236         }
 237         return g_list_append(result, rsc);
 238     }
 239     /* If the resource is a group ==> children inherit the attribute if defined. */
 240     find_matching_attr_resources_recursive(&result, rsc, rsc_id, attr_set,
 241                                            attr_set_type, attr_id, attr_name,
 242                                            cib, cmd, 0);
 243     return result;
 244 }
 245 
 246 // \return Standard Pacemaker return code
 247 int
 248 cli_resource_update_attribute(pe_resource_t *rsc, const char *requested_name,
     /* [previous][next][first][last][top][bottom][index][help] */
 249                               const char *attr_set, const char *attr_set_type,
 250                               const char *attr_id, const char *attr_name,
 251                               const char *attr_value, gboolean recursive, cib_t *cib,
 252                               int cib_options, pe_working_set_t *data_set, gboolean force)
 253 {
 254     int rc = pcmk_rc_ok;
 255     static bool need_init = TRUE;
 256 
 257     char *local_attr_id = NULL;
 258     char *local_attr_set = NULL;
 259 
 260     GList/*<pe_resource_t*>*/ *resources = NULL;
 261     const char *common_attr_id = attr_id;
 262 
 263     if(attr_id == NULL
 264        && force == FALSE
 265        && find_resource_attr(
 266            cib, XML_ATTR_ID, uber_parent(rsc)->id, NULL, NULL, NULL, attr_name, NULL) == EINVAL) {
 267         printf("\n");
 268     }
 269 
 270     if (pcmk__str_eq(attr_set_type, XML_TAG_ATTR_SETS, pcmk__str_casei)) {
 271         if (force == FALSE) {
 272             rc = find_resource_attr(cib, XML_ATTR_ID, uber_parent(rsc)->id,
 273                                     XML_TAG_META_SETS, attr_set, attr_id,
 274                                     attr_name, &local_attr_id);
 275             if (rc == pcmk_rc_ok && BE_QUIET == FALSE) {
 276                 printf("WARNING: There is already a meta attribute for '%s' called '%s' (id=%s)\n",
 277                        uber_parent(rsc)->id, attr_name, local_attr_id);
 278                 printf("         Delete '%s' first or use the force option to override\n",
 279                        local_attr_id);
 280             }
 281             free(local_attr_id);
 282             if (rc == pcmk_rc_ok) {
 283                 return ENOTUNIQ;
 284             }
 285         }
 286         resources = g_list_append(resources, rsc);
 287 
 288     } else {
 289         resources = find_matching_attr_resources(rsc, requested_name, attr_set, attr_set_type,
 290                                                  attr_id, attr_name, cib, "update", force);
 291     }
 292 
 293     /* If either attr_set or attr_id is specified,
 294      * one clearly intends to modify a single resource.
 295      * It is the last item on the resource list.*/
 296     for(GList *gIter = (attr_set||attr_id) ? g_list_last(resources) : resources
 297             ; gIter; gIter = gIter->next) {
 298         char *lookup_id = NULL;
 299 
 300         xmlNode *xml_top = NULL;
 301         xmlNode *xml_obj = NULL;
 302         local_attr_id = NULL;
 303         local_attr_set = NULL;
 304 
 305         rsc = (pe_resource_t*)gIter->data;
 306         attr_id = common_attr_id;
 307 
 308         lookup_id = clone_strip(rsc->id); /* Could be a cloned group! */
 309         rc = find_resource_attr(cib, XML_ATTR_ID, lookup_id, attr_set_type, attr_set, attr_id, attr_name,
 310                                 &local_attr_id);
 311 
 312         if (rc == pcmk_rc_ok) {
 313             crm_debug("Found a match for name=%s: id=%s", attr_name, local_attr_id);
 314             attr_id = local_attr_id;
 315 
 316         } else if (rc != ENXIO) {
 317             free(lookup_id);
 318             free(local_attr_id);
 319             g_list_free(resources);
 320             return rc;
 321 
 322         } else {
 323             const char *tag = crm_element_name(rsc->xml);
 324 
 325             if (attr_set == NULL) {
 326                 local_attr_set = crm_strdup_printf("%s-%s", lookup_id,
 327                                                    attr_set_type);
 328                 attr_set = local_attr_set;
 329             }
 330             if (attr_id == NULL) {
 331                 local_attr_id = crm_strdup_printf("%s-%s", attr_set, attr_name);
 332                 attr_id = local_attr_id;
 333             }
 334 
 335             xml_top = create_xml_node(NULL, tag);
 336             crm_xml_add(xml_top, XML_ATTR_ID, lookup_id);
 337 
 338             xml_obj = create_xml_node(xml_top, attr_set_type);
 339             crm_xml_add(xml_obj, XML_ATTR_ID, attr_set);
 340         }
 341 
 342         xml_obj = crm_create_nvpair_xml(xml_obj, attr_id, attr_name, attr_value);
 343         if (xml_top == NULL) {
 344             xml_top = xml_obj;
 345         }
 346 
 347         crm_log_xml_debug(xml_top, "Update");
 348 
 349         rc = cib->cmds->modify(cib, XML_CIB_TAG_RESOURCES, xml_top, cib_options);
 350         rc = pcmk_legacy2rc(rc);
 351 
 352         if (rc == pcmk_rc_ok && BE_QUIET == FALSE) {
 353             printf("Set '%s' option: id=%s%s%s%s%s value=%s\n", lookup_id, local_attr_id,
 354                    attr_set ? " set=" : "", attr_set ? attr_set : "",
 355                    attr_name ? " name=" : "", attr_name ? attr_name : "", attr_value);
 356         }
 357 
 358         free_xml(xml_top);
 359 
 360         free(lookup_id);
 361         free(local_attr_id);
 362         free(local_attr_set);
 363 
 364         if(recursive && pcmk__str_eq(attr_set_type, XML_TAG_META_SETS, pcmk__str_casei)) {
 365             GListPtr lpc = NULL;
 366 
 367             if(need_init) {
 368                 xmlNode *cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, data_set->input);
 369 
 370                 need_init = FALSE;
 371                 unpack_constraints(cib_constraints, data_set);
 372 
 373                 for (lpc = data_set->resources; lpc != NULL; lpc = lpc->next) {
 374                     pe_resource_t *r = (pe_resource_t *) lpc->data;
 375 
 376                     pe__clear_resource_flags(r, pe_rsc_allocating);
 377                 }
 378             }
 379 
 380             crm_debug("Looking for dependencies %p", rsc->rsc_cons_lhs);
 381             pe__set_resource_flags(rsc, pe_rsc_allocating);
 382             for (lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
 383                 rsc_colocation_t *cons = (rsc_colocation_t *) lpc->data;
 384                 pe_resource_t *peer = cons->rsc_lh;
 385 
 386                 crm_debug("Checking %s %d", cons->id, cons->score);
 387                 if (cons->score > 0 && !pcmk_is_set(peer->flags, pe_rsc_allocating)) {
 388                     /* Don't get into colocation loops */
 389                     crm_debug("Setting %s=%s for dependent resource %s", attr_name, attr_value, peer->id);
 390                     cli_resource_update_attribute(peer, peer->id, NULL, attr_set_type,
 391                                                   NULL, attr_name, attr_value, recursive,
 392                                                   cib, cib_options, data_set, force);
 393                 }
 394             }
 395         }
 396     }
 397     g_list_free(resources);
 398     return rc;
 399 }
 400 
 401 // \return Standard Pacemaker return code
 402 int
 403 cli_resource_delete_attribute(pe_resource_t *rsc, const char *requested_name,
     /* [previous][next][first][last][top][bottom][index][help] */
 404                               const char *attr_set, const char *attr_set_type,
 405                               const char *attr_id, const char *attr_name, cib_t *cib,
 406                               int cib_options, pe_working_set_t *data_set, gboolean force)
 407 {
 408     int rc = pcmk_rc_ok;
 409     GList/*<pe_resource_t*>*/ *resources = NULL;
 410 
 411     if(attr_id == NULL
 412        && force == FALSE
 413        && find_resource_attr(
 414            cib, XML_ATTR_ID, uber_parent(rsc)->id, NULL, NULL, NULL, attr_name, NULL) == EINVAL) {
 415         printf("\n");
 416     }
 417 
 418     if(pcmk__str_eq(attr_set_type, XML_TAG_META_SETS, pcmk__str_casei)) {
 419         resources = find_matching_attr_resources(rsc, requested_name, attr_set, attr_set_type,
 420                                                  attr_id, attr_name, cib, "delete", force);
 421     } else {
 422         resources = g_list_append(resources, rsc);
 423     }
 424 
 425     for(GList *gIter = resources; gIter; gIter = gIter->next) {
 426         char *lookup_id = NULL;
 427         xmlNode *xml_obj = NULL;
 428         char *local_attr_id = NULL;
 429 
 430         rsc = (pe_resource_t*)gIter->data;
 431 
 432         lookup_id = clone_strip(rsc->id);
 433         rc = find_resource_attr(cib, XML_ATTR_ID, lookup_id, attr_set_type, attr_set, attr_id, attr_name,
 434                                 &local_attr_id);
 435 
 436         if (rc == ENXIO) {
 437             free(lookup_id);
 438             rc = pcmk_rc_ok;
 439             continue;
 440 
 441         } else if (rc != pcmk_rc_ok) {
 442             free(lookup_id);
 443             g_list_free(resources);
 444             return rc;
 445         }
 446 
 447         if (attr_id == NULL) {
 448             attr_id = local_attr_id;
 449         }
 450 
 451         xml_obj = crm_create_nvpair_xml(NULL, attr_id, attr_name, NULL);
 452         crm_log_xml_debug(xml_obj, "Delete");
 453 
 454         CRM_ASSERT(cib);
 455         rc = cib->cmds->remove(cib, XML_CIB_TAG_RESOURCES, xml_obj, cib_options);
 456         rc = pcmk_legacy2rc(rc);
 457 
 458         if (rc == pcmk_rc_ok && BE_QUIET == FALSE) {
 459             printf("Deleted '%s' option: id=%s%s%s%s%s\n", lookup_id, local_attr_id,
 460                    attr_set ? " set=" : "", attr_set ? attr_set : "",
 461                    attr_name ? " name=" : "", attr_name ? attr_name : "");
 462         }
 463 
 464         free(lookup_id);
 465         free_xml(xml_obj);
 466         free(local_attr_id);
 467     }
 468     g_list_free(resources);
 469     return rc;
 470 }
 471 
 472 // \return Standard Pacemaker return code
 473 static int
 474 send_lrm_rsc_op(pcmk_ipc_api_t *controld_api, bool do_fail_resource,
     /* [previous][next][first][last][top][bottom][index][help] */
 475                 const char *host_uname, const char *rsc_id,
 476                 pe_working_set_t *data_set)
 477 {
 478     const char *router_node = host_uname;
 479     const char *rsc_api_id = NULL;
 480     const char *rsc_long_id = NULL;
 481     const char *rsc_class = NULL;
 482     const char *rsc_provider = NULL;
 483     const char *rsc_type = NULL;
 484     bool cib_only = false;
 485     pe_resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
 486 
 487     if (rsc == NULL) {
 488         CMD_ERR("Resource %s not found", rsc_id);
 489         return ENXIO;
 490 
 491     } else if (rsc->variant != pe_native) {
 492         CMD_ERR("We can only process primitive resources, not %s", rsc_id);
 493         return EINVAL;
 494     }
 495 
 496     rsc_class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
 497     rsc_provider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER),
 498     rsc_type = crm_element_value(rsc->xml, XML_ATTR_TYPE);
 499     if ((rsc_class == NULL) || (rsc_type == NULL)) {
 500         CMD_ERR("Resource %s does not have a class and type", rsc_id);
 501         return EINVAL;
 502     }
 503 
 504     if (host_uname == NULL) {
 505         CMD_ERR("Please specify a node name");
 506         return EINVAL;
 507 
 508     } else {
 509         pe_node_t *node = pe_find_node(data_set->nodes, host_uname);
 510 
 511         if (node == NULL) {
 512             CMD_ERR("Node %s not found", host_uname);
 513             return pcmk_rc_node_unknown;
 514         }
 515 
 516         if (!(node->details->online)) {
 517             if (do_fail_resource) {
 518                 CMD_ERR("Node %s is not online", host_uname);
 519                 return ENOTCONN;
 520             } else {
 521                 cib_only = true;
 522             }
 523         }
 524         if (!cib_only && pe__is_guest_or_remote_node(node)) {
 525             node = pe__current_node(node->details->remote_rsc);
 526             if (node == NULL) {
 527                 CMD_ERR("No cluster connection to Pacemaker Remote node %s detected",
 528                         host_uname);
 529                 return ENOTCONN;
 530             }
 531             router_node = node->details->uname;
 532         }
 533     }
 534 
 535     if (rsc->clone_name) {
 536         rsc_api_id = rsc->clone_name;
 537         rsc_long_id = rsc->id;
 538     } else {
 539         rsc_api_id = rsc->id;
 540     }
 541     if (do_fail_resource) {
 542         return pcmk_controld_api_fail(controld_api, host_uname, router_node,
 543                                       rsc_api_id, rsc_long_id,
 544                                       rsc_class, rsc_provider, rsc_type);
 545     } else {
 546         return pcmk_controld_api_refresh(controld_api, host_uname, router_node,
 547                                          rsc_api_id, rsc_long_id, rsc_class,
 548                                          rsc_provider, rsc_type, cib_only);
 549     }
 550 }
 551 
 552 /*!
 553  * \internal
 554  * \brief Get resource name as used in failure-related node attributes
 555  *
 556  * \param[in] rsc  Resource to check
 557  *
 558  * \return Newly allocated string containing resource's fail name
 559  * \note The caller is responsible for freeing the result.
 560  */
 561 static inline char *
 562 rsc_fail_name(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 563 {
 564     const char *name = (rsc->clone_name? rsc->clone_name : rsc->id);
 565 
 566     return pcmk_is_set(rsc->flags, pe_rsc_unique)? strdup(name) : clone_strip(name);
 567 }
 568 
 569 // \return Standard Pacemaker return code
 570 static int
 571 clear_rsc_history(pcmk_ipc_api_t *controld_api, const char *host_uname,
     /* [previous][next][first][last][top][bottom][index][help] */
 572                   const char *rsc_id, pe_working_set_t *data_set)
 573 {
 574     int rc = pcmk_rc_ok;
 575 
 576     /* Erase the resource's entire LRM history in the CIB, even if we're only
 577      * clearing a single operation's fail count. If we erased only entries for a
 578      * single operation, we might wind up with a wrong idea of the current
 579      * resource state, and we might not re-probe the resource.
 580      */
 581     rc = send_lrm_rsc_op(controld_api, false, host_uname, rsc_id, data_set);
 582     if (rc != pcmk_rc_ok) {
 583         return rc;
 584     }
 585 
 586     crm_trace("Processing %d mainloop inputs",
 587               pcmk_controld_api_replies_expected(controld_api));
 588     while (g_main_context_iteration(NULL, FALSE)) {
 589         crm_trace("Processed mainloop input, %d still remaining",
 590                   pcmk_controld_api_replies_expected(controld_api));
 591     }
 592     return rc;
 593 }
 594 
 595 // \return Standard Pacemaker return code
 596 static int
 597 clear_rsc_failures(pcmk_ipc_api_t *controld_api, const char *node_name,
     /* [previous][next][first][last][top][bottom][index][help] */
 598                    const char *rsc_id, const char *operation,
 599                    const char *interval_spec, pe_working_set_t *data_set)
 600 {
 601     int rc = pcmk_rc_ok;
 602     const char *failed_value = NULL;
 603     const char *failed_id = NULL;
 604     const char *interval_ms_s = NULL;
 605     GHashTable *rscs = NULL;
 606     GHashTableIter iter;
 607 
 608     /* Create a hash table to use as a set of resources to clean. This lets us
 609      * clean each resource only once (per node) regardless of how many failed
 610      * operations it has.
 611      */
 612     rscs = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, NULL);
 613 
 614     // Normalize interval to milliseconds for comparison to history entry
 615     if (operation) {
 616         interval_ms_s = crm_strdup_printf("%u",
 617                                           crm_parse_interval_spec(interval_spec));
 618     }
 619 
 620     for (xmlNode *xml_op = pcmk__xml_first_child(data_set->failed);
 621          xml_op != NULL;
 622          xml_op = pcmk__xml_next(xml_op)) {
 623 
 624         failed_id = crm_element_value(xml_op, XML_LRM_ATTR_RSCID);
 625         if (failed_id == NULL) {
 626             // Malformed history entry, should never happen
 627             continue;
 628         }
 629 
 630         // No resource specified means all resources match
 631         if (rsc_id) {
 632             pe_resource_t *fail_rsc = pe_find_resource_with_flags(data_set->resources,
 633                                                                   failed_id,
 634                                                                   pe_find_renamed|pe_find_anon);
 635 
 636             if (!fail_rsc || !pcmk__str_eq(rsc_id, fail_rsc->id, pcmk__str_casei)) {
 637                 continue;
 638             }
 639         }
 640 
 641         // Host name should always have been provided by this point
 642         failed_value = crm_element_value(xml_op, XML_ATTR_UNAME);
 643         if (!pcmk__str_eq(node_name, failed_value, pcmk__str_casei)) {
 644             continue;
 645         }
 646 
 647         // No operation specified means all operations match
 648         if (operation) {
 649             failed_value = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
 650             if (!pcmk__str_eq(operation, failed_value, pcmk__str_casei)) {
 651                 continue;
 652             }
 653 
 654             // Interval (if operation was specified) defaults to 0 (not all)
 655             failed_value = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL_MS);
 656             if (!pcmk__str_eq(interval_ms_s, failed_value, pcmk__str_casei)) {
 657                 continue;
 658             }
 659         }
 660 
 661         /* not available until glib 2.32
 662         g_hash_table_add(rscs, (gpointer) failed_id);
 663         */
 664         g_hash_table_insert(rscs, (gpointer) failed_id, (gpointer) failed_id);
 665     }
 666 
 667     g_hash_table_iter_init(&iter, rscs);
 668     while (g_hash_table_iter_next(&iter, (gpointer *) &failed_id, NULL)) {
 669         crm_debug("Erasing failures of %s on %s", failed_id, node_name);
 670         rc = clear_rsc_history(controld_api, node_name, failed_id, data_set);
 671         if (rc != pcmk_rc_ok) {
 672             return rc;
 673         }
 674     }
 675     g_hash_table_destroy(rscs);
 676     return rc;
 677 }
 678 
 679 // \return Standard Pacemaker return code
 680 static int
 681 clear_rsc_fail_attrs(pe_resource_t *rsc, const char *operation,
     /* [previous][next][first][last][top][bottom][index][help] */
 682                      const char *interval_spec, pe_node_t *node)
 683 {
 684     int rc = pcmk_rc_ok;
 685     int attr_options = pcmk__node_attr_none;
 686     char *rsc_name = rsc_fail_name(rsc);
 687 
 688     if (pe__is_guest_or_remote_node(node)) {
 689         attr_options |= pcmk__node_attr_remote;
 690     }
 691     rc = pcmk__node_attr_request_clear(NULL, node->details->uname, rsc_name,
 692                                        operation, interval_spec, NULL,
 693                                        attr_options);
 694     free(rsc_name);
 695     return rc;
 696 }
 697 
 698 // \return Standard Pacemaker return code
 699 int
 700 cli_resource_delete(pcmk_ipc_api_t *controld_api, const char *host_uname,
     /* [previous][next][first][last][top][bottom][index][help] */
 701                     pe_resource_t *rsc, const char *operation,
 702                     const char *interval_spec, bool just_failures,
 703                     pe_working_set_t *data_set, gboolean force)
 704 {
 705     int rc = pcmk_rc_ok;
 706     pe_node_t *node = NULL;
 707 
 708     if (rsc == NULL) {
 709         return ENXIO;
 710 
 711     } else if (rsc->children) {
 712         GListPtr lpc = NULL;
 713 
 714         for (lpc = rsc->children; lpc != NULL; lpc = lpc->next) {
 715             pe_resource_t *child = (pe_resource_t *) lpc->data;
 716 
 717             rc = cli_resource_delete(controld_api, host_uname, child, operation,
 718                                      interval_spec, just_failures, data_set,
 719                                      force);
 720             if (rc != pcmk_rc_ok) {
 721                 return rc;
 722             }
 723         }
 724         return pcmk_rc_ok;
 725 
 726     } else if (host_uname == NULL) {
 727         GListPtr lpc = NULL;
 728         GListPtr nodes = g_hash_table_get_values(rsc->known_on);
 729 
 730         if(nodes == NULL && force) {
 731             nodes = pcmk__copy_node_list(data_set->nodes, false);
 732 
 733         } else if(nodes == NULL && rsc->exclusive_discover) {
 734             GHashTableIter iter;
 735             pe_node_t *node = NULL;
 736 
 737             g_hash_table_iter_init(&iter, rsc->allowed_nodes);
 738             while (g_hash_table_iter_next(&iter, NULL, (void**)&node)) {
 739                 if(node->weight >= 0) {
 740                     nodes = g_list_prepend(nodes, node);
 741                 }
 742             }
 743 
 744         } else if(nodes == NULL) {
 745             nodes = g_hash_table_get_values(rsc->allowed_nodes);
 746         }
 747 
 748         for (lpc = nodes; lpc != NULL; lpc = lpc->next) {
 749             node = (pe_node_t *) lpc->data;
 750 
 751             if (node->details->online) {
 752                 rc = cli_resource_delete(controld_api, node->details->uname,
 753                                          rsc, operation, interval_spec,
 754                                          just_failures, data_set, force);
 755             }
 756             if (rc != pcmk_rc_ok) {
 757                 g_list_free(nodes);
 758                 return rc;
 759             }
 760         }
 761 
 762         g_list_free(nodes);
 763         return pcmk_rc_ok;
 764     }
 765 
 766     node = pe_find_node(data_set->nodes, host_uname);
 767 
 768     if (node == NULL) {
 769         printf("Unable to clean up %s because node %s not found\n",
 770                rsc->id, host_uname);
 771         return ENODEV;
 772     }
 773 
 774     if (!node->details->rsc_discovery_enabled) {
 775         printf("Unable to clean up %s because resource discovery disabled on %s\n",
 776                rsc->id, host_uname);
 777         return EOPNOTSUPP;
 778     }
 779 
 780     if (controld_api == NULL) {
 781         printf("Dry run: skipping clean-up of %s on %s due to CIB_file\n",
 782                rsc->id, host_uname);
 783         return pcmk_rc_ok;
 784     }
 785 
 786     rc = clear_rsc_fail_attrs(rsc, operation, interval_spec, node);
 787     if (rc != pcmk_rc_ok) {
 788         printf("Unable to clean up %s failures on %s: %s\n",
 789                 rsc->id, host_uname, pcmk_rc_str(rc));
 790         return rc;
 791     }
 792 
 793     if (just_failures) {
 794         rc = clear_rsc_failures(controld_api, host_uname, rsc->id, operation,
 795                                 interval_spec, data_set);
 796     } else {
 797         rc = clear_rsc_history(controld_api, host_uname, rsc->id, data_set);
 798     }
 799     if (rc != pcmk_rc_ok) {
 800         printf("Cleaned %s failures on %s, but unable to clean history: %s\n",
 801                rsc->id, host_uname, pcmk_strerror(rc));
 802     } else {
 803         printf("Cleaned up %s on %s\n", rsc->id, host_uname);
 804     }
 805     return rc;
 806 }
 807 
 808 // \return Standard Pacemaker return code
 809 int
 810 cli_cleanup_all(pcmk_ipc_api_t *controld_api, const char *node_name,
     /* [previous][next][first][last][top][bottom][index][help] */
 811                 const char *operation, const char *interval_spec,
 812                 pe_working_set_t *data_set)
 813 {
 814     int rc = pcmk_rc_ok;
 815     int attr_options = pcmk__node_attr_none;
 816     const char *display_name = node_name? node_name : "all nodes";
 817 
 818     if (controld_api == NULL) {
 819         printf("Dry run: skipping clean-up of %s due to CIB_file\n",
 820                display_name);
 821         return rc;
 822     }
 823 
 824     if (node_name) {
 825         pe_node_t *node = pe_find_node(data_set->nodes, node_name);
 826 
 827         if (node == NULL) {
 828             CMD_ERR("Unknown node: %s", node_name);
 829             return ENXIO;
 830         }
 831         if (pe__is_guest_or_remote_node(node)) {
 832             attr_options |= pcmk__node_attr_remote;
 833         }
 834     }
 835 
 836     rc = pcmk__node_attr_request_clear(NULL, node_name, NULL, operation,
 837                                        interval_spec, NULL, attr_options);
 838     if (rc != pcmk_rc_ok) {
 839         printf("Unable to clean up all failures on %s: %s\n",
 840                 display_name, pcmk_rc_str(rc));
 841         return rc;
 842     }
 843 
 844     if (node_name) {
 845         rc = clear_rsc_failures(controld_api, node_name, NULL,
 846                                 operation, interval_spec, data_set);
 847         if (rc != pcmk_rc_ok) {
 848             printf("Cleaned all resource failures on %s, but unable to clean history: %s\n",
 849                    node_name, pcmk_strerror(rc));
 850             return rc;
 851         }
 852     } else {
 853         for (GList *iter = data_set->nodes; iter; iter = iter->next) {
 854             pe_node_t *node = (pe_node_t *) iter->data;
 855 
 856             rc = clear_rsc_failures(controld_api, node->details->uname, NULL,
 857                                     operation, interval_spec, data_set);
 858             if (rc != pcmk_rc_ok) {
 859                 printf("Cleaned all resource failures on all nodes, but unable to clean history: %s\n",
 860                        pcmk_strerror(rc));
 861                 return rc;
 862             }
 863         }
 864     }
 865 
 866     printf("Cleaned up all resources on %s\n", display_name);
 867     return rc;
 868 }
 869 
 870 void
 871 cli_resource_check(cib_t * cib_conn, pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 872 {
 873     bool printed = false;
 874     char *role_s = NULL;
 875     char *managed = NULL;
 876     pe_resource_t *parent = uber_parent(rsc);
 877 
 878     find_resource_attr(cib_conn, XML_NVPAIR_ATTR_VALUE, parent->id,
 879                        NULL, NULL, NULL, XML_RSC_ATTR_MANAGED, &managed);
 880 
 881     find_resource_attr(cib_conn, XML_NVPAIR_ATTR_VALUE, parent->id,
 882                        NULL, NULL, NULL, XML_RSC_ATTR_TARGET_ROLE, &role_s);
 883 
 884     if(role_s) {
 885         enum rsc_role_e role = text2role(role_s);
 886 
 887         free(role_s);
 888         if(role == RSC_ROLE_UNKNOWN) {
 889             // Treated as if unset
 890 
 891         } else if(role == RSC_ROLE_STOPPED) {
 892             printf("\n  * Configuration specifies '%s' should remain stopped\n",
 893                    parent->id);
 894             printed = true;
 895 
 896         } else if (pcmk_is_set(parent->flags, pe_rsc_promotable)
 897                    && (role == RSC_ROLE_SLAVE)) {
 898             printf("\n  * Configuration specifies '%s' should not be promoted\n",
 899                    parent->id);
 900             printed = true;
 901         }
 902     }
 903 
 904     if (managed && !crm_is_true(managed)) {
 905         printf("%s  * Configuration prevents cluster from stopping or starting unmanaged '%s'\n",
 906                (printed? "" : "\n"), parent->id);
 907         printed = true;
 908     }
 909     free(managed);
 910 
 911     if (rsc->lock_node) {
 912         printf("%s  * '%s' is locked to node %s due to shutdown\n",
 913                (printed? "" : "\n"), parent->id, rsc->lock_node->details->uname);
 914     }
 915 
 916     if (printed) {
 917         printf("\n");
 918     }
 919 }
 920 
 921 // \return Standard Pacemaker return code
 922 int
 923 cli_resource_fail(pcmk_ipc_api_t *controld_api, const char *host_uname,
     /* [previous][next][first][last][top][bottom][index][help] */
 924                   const char *rsc_id, pe_working_set_t *data_set)
 925 {
 926     crm_notice("Failing %s on %s", rsc_id, host_uname);
 927     return send_lrm_rsc_op(controld_api, true, host_uname, rsc_id, data_set);
 928 }
 929 
 930 static GHashTable *
 931 generate_resource_params(pe_resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 932 {
 933     GHashTable *params = NULL;
 934     GHashTable *meta = NULL;
 935     GHashTable *combined = NULL;
 936     GHashTableIter iter;
 937 
 938     if (!rsc) {
 939         crm_err("Resource does not exist in config");
 940         return NULL;
 941     }
 942 
 943     params = crm_str_table_new();
 944     meta = crm_str_table_new();
 945     combined = crm_str_table_new();
 946 
 947     get_rsc_attributes(params, rsc, NULL /* TODO: Pass in local node */ , data_set);
 948     get_meta_attributes(meta, rsc, NULL /* TODO: Pass in local node */ , data_set);
 949 
 950     if (params) {
 951         char *key = NULL;
 952         char *value = NULL;
 953 
 954         g_hash_table_iter_init(&iter, params);
 955         while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
 956             g_hash_table_insert(combined, strdup(key), strdup(value));
 957         }
 958         g_hash_table_destroy(params);
 959     }
 960 
 961     if (meta) {
 962         char *key = NULL;
 963         char *value = NULL;
 964 
 965         g_hash_table_iter_init(&iter, meta);
 966         while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
 967             char *crm_name = crm_meta_name(key);
 968 
 969             g_hash_table_insert(combined, crm_name, strdup(value));
 970         }
 971         g_hash_table_destroy(meta);
 972     }
 973 
 974     return combined;
 975 }
 976 
 977 static bool resource_is_running_on(pe_resource_t *rsc, const char *host) 
     /* [previous][next][first][last][top][bottom][index][help] */
 978 {
 979     bool found = TRUE;
 980     GListPtr hIter = NULL;
 981     GListPtr hosts = NULL;
 982 
 983     if(rsc == NULL) {
 984         return FALSE;
 985     }
 986 
 987     rsc->fns->location(rsc, &hosts, TRUE);
 988     for (hIter = hosts; host != NULL && hIter != NULL; hIter = hIter->next) {
 989         pe_node_t *node = (pe_node_t *) hIter->data;
 990 
 991         if(strcmp(host, node->details->uname) == 0) {
 992             crm_trace("Resource %s is running on %s\n", rsc->id, host);
 993             goto done;
 994         } else if(strcmp(host, node->details->id) == 0) {
 995             crm_trace("Resource %s is running on %s\n", rsc->id, host);
 996             goto done;
 997         }
 998     }
 999 
1000     if(host != NULL) {
1001         crm_trace("Resource %s is not running on: %s\n", rsc->id, host);
1002         found = FALSE;
1003 
1004     } else if(host == NULL && hosts == NULL) {
1005         crm_trace("Resource %s is not running\n", rsc->id);
1006         found = FALSE;
1007     }
1008 
1009   done:
1010 
1011     g_list_free(hosts);
1012     return found;
1013 }
1014 
1015 /*!
1016  * \internal
1017  * \brief Create a list of all resources active on host from a given list
1018  *
1019  * \param[in] host      Name of host to check whether resources are active
1020  * \param[in] rsc_list  List of resources to check
1021  *
1022  * \return New list of resources from list that are active on host
1023  */
1024 static GList *
1025 get_active_resources(const char *host, GList *rsc_list)
     /* [previous][next][first][last][top][bottom][index][help] */
1026 {
1027     GList *rIter = NULL;
1028     GList *active = NULL;
1029 
1030     for (rIter = rsc_list; rIter != NULL; rIter = rIter->next) {
1031         pe_resource_t *rsc = (pe_resource_t *) rIter->data;
1032 
1033         /* Expand groups to their members, because if we're restarting a member
1034          * other than the first, we can't otherwise tell which resources are
1035          * stopping and starting.
1036          */
1037         if (rsc->variant == pe_group) {
1038             active = g_list_concat(active,
1039                                    get_active_resources(host, rsc->children));
1040         } else if (resource_is_running_on(rsc, host)) {
1041             active = g_list_append(active, strdup(rsc->id));
1042         }
1043     }
1044     return active;
1045 }
1046 
1047 static void dump_list(GList *items, const char *tag) 
     /* [previous][next][first][last][top][bottom][index][help] */
1048 {
1049     int lpc = 0;
1050     GList *item = NULL;
1051 
1052     for (item = items; item != NULL; item = item->next) {
1053         crm_trace("%s[%d]: %s", tag, lpc, (char*)item->data);
1054         lpc++;
1055     }
1056 }
1057 
1058 static void display_list(GList *items, const char *tag) 
     /* [previous][next][first][last][top][bottom][index][help] */
1059 {
1060     GList *item = NULL;
1061 
1062     for (item = items; item != NULL; item = item->next) {
1063         fprintf(stdout, "%s%s\n", tag, (const char *)item->data);
1064     }
1065 }
1066 
1067 /*!
1068  * \internal
1069  * \brief Upgrade XML to latest schema version and use it as working set input
1070  *
1071  * This also updates the working set timestamp to the current time.
1072  *
1073  * \param[in] data_set   Working set instance to update
1074  * \param[in] xml        XML to use as input
1075  *
1076  * \return Standard Pacemaker return code
1077  * \note On success, caller is responsible for freeing memory allocated for
1078  *       data_set->now.
1079  * \todo This follows the example of other callers of cli_config_update()
1080  *       and returns ENOKEY ("Required key not available") if that fails,
1081  *       but perhaps pcmk_rc_schema_validation would be better in that case.
1082  */
1083 int
1084 update_working_set_xml(pe_working_set_t *data_set, xmlNode **xml)
     /* [previous][next][first][last][top][bottom][index][help] */
1085 {
1086     if (cli_config_update(xml, NULL, FALSE) == FALSE) {
1087         return ENOKEY;
1088     }
1089     data_set->input = *xml;
1090     data_set->now = crm_time_new(NULL);
1091     return pcmk_rc_ok;
1092 }
1093 
1094 /*!
1095  * \internal
1096  * \brief Update a working set's XML input based on a CIB query
1097  *
1098  * \param[in] data_set   Data set instance to initialize
1099  * \param[in] cib        Connection to the CIB manager
1100  *
1101  * \return Standard Pacemaker return code
1102  * \note On success, caller is responsible for freeing memory allocated for
1103  *       data_set->input and data_set->now.
1104  */
1105 static int
1106 update_working_set_from_cib(pe_working_set_t * data_set, cib_t *cib)
     /* [previous][next][first][last][top][bottom][index][help] */
1107 {
1108     xmlNode *cib_xml_copy = NULL;
1109     int rc = pcmk_rc_ok;
1110 
1111     rc = cib->cmds->query(cib, NULL, &cib_xml_copy, cib_scope_local | cib_sync_call);
1112     rc = pcmk_legacy2rc(rc);
1113 
1114     if (rc != pcmk_rc_ok) {
1115         fprintf(stderr, "Could not obtain the current CIB: %s (%d)\n", pcmk_strerror(rc), rc);
1116         return rc;
1117     }
1118     rc = update_working_set_xml(data_set, &cib_xml_copy);
1119     if (rc != pcmk_rc_ok) {
1120         fprintf(stderr, "Could not upgrade the current CIB XML\n");
1121         free_xml(cib_xml_copy);
1122         return rc;
1123     }
1124 
1125     return rc;
1126 }
1127 
1128 // \return Standard Pacemaker return code
1129 static int
1130 update_dataset(cib_t *cib, pe_working_set_t * data_set, bool simulate)
     /* [previous][next][first][last][top][bottom][index][help] */
1131 {
1132     char *pid = NULL;
1133     char *shadow_file = NULL;
1134     cib_t *shadow_cib = NULL;
1135     int rc = pcmk_rc_ok;
1136 
1137     pe_reset_working_set(data_set);
1138     rc = update_working_set_from_cib(data_set, cib);
1139     if (rc != pcmk_rc_ok) {
1140         return rc;
1141     }
1142 
1143     if(simulate) {
1144         pid = pcmk__getpid_s();
1145         shadow_cib = cib_shadow_new(pid);
1146         shadow_file = get_shadow_file(pid);
1147 
1148         if (shadow_cib == NULL) {
1149             fprintf(stderr, "Could not create shadow cib: '%s'\n", pid);
1150             rc = ENXIO;
1151             goto cleanup;
1152         }
1153 
1154         rc = write_xml_file(data_set->input, shadow_file, FALSE);
1155 
1156         if (rc < 0) {
1157             fprintf(stderr, "Could not populate shadow cib: %s (%d)\n", pcmk_strerror(rc), rc);
1158             goto cleanup;
1159         }
1160 
1161         rc = shadow_cib->cmds->signon(shadow_cib, crm_system_name, cib_command);
1162         rc = pcmk_legacy2rc(rc);
1163 
1164         if (rc != pcmk_rc_ok) {
1165             fprintf(stderr, "Could not connect to shadow cib: %s (%d)\n", pcmk_strerror(rc), rc);
1166             goto cleanup;
1167         }
1168 
1169         pcmk__schedule_actions(data_set, data_set->input, NULL);
1170         run_simulation(data_set, shadow_cib, NULL, TRUE);
1171         rc = update_dataset(shadow_cib, data_set, FALSE);
1172 
1173     } else {
1174         cluster_status(data_set);
1175     }
1176 
1177   cleanup:
1178     /* Do not free data_set->input here, we need rsc->xml to be valid later on */
1179     cib_delete(shadow_cib);
1180     free(pid);
1181 
1182     if(shadow_file) {
1183         unlink(shadow_file);
1184         free(shadow_file);
1185     }
1186 
1187     return rc;
1188 }
1189 
1190 static int
1191 max_delay_for_resource(pe_working_set_t * data_set, pe_resource_t *rsc) 
     /* [previous][next][first][last][top][bottom][index][help] */
1192 {
1193     int delay = 0;
1194     int max_delay = 0;
1195 
1196     if(rsc && rsc->children) {
1197         GList *iter = NULL;
1198 
1199         for(iter = rsc->children; iter; iter = iter->next) {
1200             pe_resource_t *child = (pe_resource_t *)iter->data;
1201 
1202             delay = max_delay_for_resource(data_set, child);
1203             if(delay > max_delay) {
1204                 double seconds = delay / 1000.0;
1205                 crm_trace("Calculated new delay of %.1fs due to %s", seconds, child->id);
1206                 max_delay = delay;
1207             }
1208         }
1209 
1210     } else if(rsc) {
1211         char *key = crm_strdup_printf("%s_%s_0", rsc->id, RSC_STOP);
1212         pe_action_t *stop = custom_action(rsc, key, RSC_STOP, NULL, TRUE, FALSE, data_set);
1213         const char *value = g_hash_table_lookup(stop->meta, XML_ATTR_TIMEOUT);
1214 
1215         max_delay = value? (int) crm_parse_ll(value, NULL) : -1;
1216         pe_free_action(stop);
1217     }
1218 
1219 
1220     return max_delay;
1221 }
1222 
1223 static int
1224 max_delay_in(pe_working_set_t * data_set, GList *resources) 
     /* [previous][next][first][last][top][bottom][index][help] */
1225 {
1226     int max_delay = 0;
1227     GList *item = NULL;
1228 
1229     for (item = resources; item != NULL; item = item->next) {
1230         int delay = 0;
1231         pe_resource_t *rsc = pe_find_resource(data_set->resources, (const char *)item->data);
1232 
1233         delay = max_delay_for_resource(data_set, rsc);
1234 
1235         if(delay > max_delay) {
1236             double seconds = delay / 1000.0;
1237             crm_trace("Calculated new delay of %.1fs due to %s", seconds, rsc->id);
1238             max_delay = delay;
1239         }
1240     }
1241 
1242     return 5 + (max_delay / 1000);
1243 }
1244 
1245 #define waiting_for_starts(d, r, h) ((d != NULL) || \
1246                                     (resource_is_running_on((r), (h)) == FALSE))
1247 
1248 /*!
1249  * \internal
1250  * \brief Restart a resource (on a particular host if requested).
1251  *
1252  * \param[in] rsc        The resource to restart
1253  * \param[in] host       The host to restart the resource on (or NULL for all)
1254  * \param[in] timeout_ms Consider failed if actions do not complete in this time
1255  *                       (specified in milliseconds, but a two-second
1256  *                       granularity is actually used; if 0, a timeout will be
1257  *                       calculated based on the resource timeout)
1258  * \param[in] cib        Connection to the CIB manager
1259  *
1260  * \return Standard Pacemaker return code (exits on certain failures)
1261  */
1262 int
1263 cli_resource_restart(pe_resource_t *rsc, const char *host, const char *move_lifetime,
     /* [previous][next][first][last][top][bottom][index][help] */
1264                      int timeout_ms, cib_t *cib, int cib_options,
1265                      gboolean promoted_role_only, gboolean force)
1266 {
1267     int rc = pcmk_rc_ok;
1268     int lpc = 0;
1269     int before = 0;
1270     int step_timeout_s = 0;
1271     int sleep_interval = 2;
1272     int timeout = timeout_ms / 1000;
1273 
1274     bool stop_via_ban = FALSE;
1275     char *rsc_id = NULL;
1276     char *orig_target_role = NULL;
1277 
1278     GList *list_delta = NULL;
1279     GList *target_active = NULL;
1280     GList *current_active = NULL;
1281     GList *restart_target_active = NULL;
1282 
1283     pe_working_set_t *data_set = NULL;
1284 
1285     if(resource_is_running_on(rsc, host) == FALSE) {
1286         const char *id = rsc->clone_name?rsc->clone_name:rsc->id;
1287         if(host) {
1288             printf("%s is not running on %s and so cannot be restarted\n", id, host);
1289         } else {
1290             printf("%s is not running anywhere and so cannot be restarted\n", id);
1291         }
1292         return ENXIO;
1293     }
1294 
1295     rsc_id = strdup(rsc->id);
1296     if ((pe_rsc_is_clone(rsc) || pe_bundle_replicas(rsc)) && host) {
1297         stop_via_ban = TRUE;
1298     }
1299 
1300     /*
1301       grab full cib
1302       determine originally active resources
1303       disable or ban
1304       poll cib and watch for affected resources to get stopped
1305       without --timeout, calculate the stop timeout for each step and wait for that
1306       if we hit --timeout or the service timeout, re-enable or un-ban, report failure and indicate which resources we couldn't take down
1307       if everything stopped, re-enable or un-ban
1308       poll cib and watch for affected resources to get started
1309       without --timeout, calculate the start timeout for each step and wait for that
1310       if we hit --timeout or the service timeout, report (different) failure and indicate which resources we couldn't bring back up
1311       report success
1312 
1313       Optimizations:
1314       - use constraints to determine ordered list of affected resources
1315       - Allow a --no-deps option (aka. --force-restart)
1316     */
1317 
1318     data_set = pe_new_working_set();
1319     if (data_set == NULL) {
1320         crm_perror(LOG_ERR, "Could not allocate working set");
1321         rc = ENOMEM;
1322         goto done;
1323     }
1324     pe__set_working_set_flags(data_set, pe_flag_no_counts|pe_flag_no_compat);
1325     rc = update_dataset(cib, data_set, FALSE);
1326     if(rc != pcmk_rc_ok) {
1327         fprintf(stdout, "Could not get new resource list: %s (%d)\n", pcmk_strerror(rc), rc);
1328         goto done;
1329     }
1330 
1331     restart_target_active = get_active_resources(host, data_set->resources);
1332     current_active = get_active_resources(host, data_set->resources);
1333 
1334     dump_list(current_active, "Origin");
1335 
1336     if (stop_via_ban) {
1337         /* Stop the clone or bundle instance by banning it from the host */
1338         BE_QUIET = TRUE;
1339         rc = cli_resource_ban(rsc_id, host, move_lifetime, NULL, cib,
1340                               cib_options, promoted_role_only);
1341 
1342     } else {
1343         /* Stop the resource by setting target-role to Stopped.
1344          * Remember any existing target-role so we can restore it later
1345          * (though it only makes any difference if it's Slave).
1346          */
1347         char *lookup_id = clone_strip(rsc->id);
1348 
1349         find_resource_attr(cib, XML_NVPAIR_ATTR_VALUE, lookup_id, NULL, NULL,
1350                            NULL, XML_RSC_ATTR_TARGET_ROLE, &orig_target_role);
1351         free(lookup_id);
1352         rc = cli_resource_update_attribute(rsc, rsc_id, NULL, XML_TAG_META_SETS, NULL,
1353                                            XML_RSC_ATTR_TARGET_ROLE,
1354                                            RSC_STOPPED, FALSE, cib, cib_options,
1355                                            data_set, force);
1356     }
1357     if(rc != pcmk_rc_ok) {
1358         fprintf(stderr, "Could not set target-role for %s: %s (%d)\n", rsc_id, pcmk_strerror(rc), rc);
1359         if (current_active) {
1360             g_list_free_full(current_active, free);
1361         }
1362         if (restart_target_active) {
1363             g_list_free_full(restart_target_active, free);
1364         }
1365         goto done;
1366     }
1367 
1368     rc = update_dataset(cib, data_set, TRUE);
1369     if(rc != pcmk_rc_ok) {
1370         fprintf(stderr, "Could not determine which resources would be stopped\n");
1371         goto failure;
1372     }
1373 
1374     target_active = get_active_resources(host, data_set->resources);
1375     dump_list(target_active, "Target");
1376 
1377     list_delta = pcmk__subtract_lists(current_active, target_active, (GCompareFunc) strcmp);
1378     fprintf(stdout, "Waiting for %d resources to stop:\n", g_list_length(list_delta));
1379     display_list(list_delta, " * ");
1380 
1381     step_timeout_s = timeout / sleep_interval;
1382     while (list_delta != NULL) {
1383         before = g_list_length(list_delta);
1384         if(timeout_ms == 0) {
1385             step_timeout_s = max_delay_in(data_set, list_delta) / sleep_interval;
1386         }
1387 
1388         /* We probably don't need the entire step timeout */
1389         for(lpc = 0; (lpc < step_timeout_s) && (list_delta != NULL); lpc++) {
1390             sleep(sleep_interval);
1391             if(timeout) {
1392                 timeout -= sleep_interval;
1393                 crm_trace("%ds remaining", timeout);
1394             }
1395             rc = update_dataset(cib, data_set, FALSE);
1396             if(rc != pcmk_rc_ok) {
1397                 fprintf(stderr, "Could not determine which resources were stopped\n");
1398                 goto failure;
1399             }
1400 
1401             if (current_active) {
1402                 g_list_free_full(current_active, free);
1403             }
1404             current_active = get_active_resources(host, data_set->resources);
1405             g_list_free(list_delta);
1406             list_delta = pcmk__subtract_lists(current_active, target_active, (GCompareFunc) strcmp);
1407             dump_list(current_active, "Current");
1408             dump_list(list_delta, "Delta");
1409         }
1410 
1411         crm_trace("%d (was %d) resources remaining", g_list_length(list_delta), before);
1412         if(before == g_list_length(list_delta)) {
1413             /* aborted during stop phase, print the contents of list_delta */
1414             fprintf(stderr, "Could not complete shutdown of %s, %d resources remaining\n", rsc_id, g_list_length(list_delta));
1415             display_list(list_delta, " * ");
1416             rc = ETIME;
1417             goto failure;
1418         }
1419 
1420     }
1421 
1422     if (stop_via_ban) {
1423         rc = cli_resource_clear(rsc_id, host, NULL, cib, cib_options, TRUE, force);
1424 
1425     } else if (orig_target_role) {
1426         rc = cli_resource_update_attribute(rsc, rsc_id, NULL, XML_TAG_META_SETS,
1427                                            NULL, XML_RSC_ATTR_TARGET_ROLE,
1428                                            orig_target_role, FALSE, cib,
1429                                            cib_options, data_set, force);
1430         free(orig_target_role);
1431         orig_target_role = NULL;
1432     } else {
1433         rc = cli_resource_delete_attribute(rsc, rsc_id, NULL, XML_TAG_META_SETS, NULL,
1434                                            XML_RSC_ATTR_TARGET_ROLE, cib,
1435                                            cib_options, data_set, force);
1436     }
1437 
1438     if(rc != pcmk_rc_ok) {
1439         fprintf(stderr, "Could not unset target-role for %s: %s (%d)\n", rsc_id, pcmk_strerror(rc), rc);
1440         goto done;
1441     }
1442 
1443     if (target_active) {
1444         g_list_free_full(target_active, free);
1445     }
1446     target_active = restart_target_active;
1447     list_delta = pcmk__subtract_lists(target_active, current_active, (GCompareFunc) strcmp);
1448     fprintf(stdout, "Waiting for %d resources to start again:\n", g_list_length(list_delta));
1449     display_list(list_delta, " * ");
1450 
1451     step_timeout_s = timeout / sleep_interval;
1452     while (waiting_for_starts(list_delta, rsc, host)) {
1453         before = g_list_length(list_delta);
1454         if(timeout_ms == 0) {
1455             step_timeout_s = max_delay_in(data_set, list_delta) / sleep_interval;
1456         }
1457 
1458         /* We probably don't need the entire step timeout */
1459         for (lpc = 0; (lpc < step_timeout_s) && waiting_for_starts(list_delta, rsc, host); lpc++) {
1460 
1461             sleep(sleep_interval);
1462             if(timeout) {
1463                 timeout -= sleep_interval;
1464                 crm_trace("%ds remaining", timeout);
1465             }
1466 
1467             rc = update_dataset(cib, data_set, FALSE);
1468             if(rc != pcmk_rc_ok) {
1469                 fprintf(stderr, "Could not determine which resources were started\n");
1470                 goto failure;
1471             }
1472 
1473             if (current_active) {
1474                 g_list_free_full(current_active, free);
1475             }
1476 
1477             /* It's OK if dependent resources moved to a different node,
1478              * so we check active resources on all nodes.
1479              */
1480             current_active = get_active_resources(NULL, data_set->resources);
1481             g_list_free(list_delta);
1482             list_delta = pcmk__subtract_lists(target_active, current_active, (GCompareFunc) strcmp);
1483             dump_list(current_active, "Current");
1484             dump_list(list_delta, "Delta");
1485         }
1486 
1487         if(before == g_list_length(list_delta)) {
1488             /* aborted during start phase, print the contents of list_delta */
1489             fprintf(stdout, "Could not complete restart of %s, %d resources remaining\n", rsc_id, g_list_length(list_delta));
1490             display_list(list_delta, " * ");
1491             rc = ETIME;
1492             goto failure;
1493         }
1494 
1495     }
1496 
1497     rc = pcmk_rc_ok;
1498     goto done;
1499 
1500   failure:
1501     if (stop_via_ban) {
1502         cli_resource_clear(rsc_id, host, NULL, cib, cib_options, TRUE, force);
1503     } else if (orig_target_role) {
1504         cli_resource_update_attribute(rsc, rsc_id, NULL, XML_TAG_META_SETS, NULL,
1505                                       XML_RSC_ATTR_TARGET_ROLE, orig_target_role,
1506                                       FALSE, cib, cib_options, data_set, force);
1507         free(orig_target_role);
1508     } else {
1509         cli_resource_delete_attribute(rsc, rsc_id, NULL, XML_TAG_META_SETS, NULL,
1510                                       XML_RSC_ATTR_TARGET_ROLE, cib, cib_options,
1511                                       data_set, force);
1512     }
1513 
1514 done:
1515     if (list_delta) {
1516         g_list_free(list_delta);
1517     }
1518     if (current_active) {
1519         g_list_free_full(current_active, free);
1520     }
1521     if (target_active && (target_active != restart_target_active)) {
1522         g_list_free_full(target_active, free);
1523     }
1524     if (restart_target_active) {
1525         g_list_free_full(restart_target_active, free);
1526     }
1527     free(rsc_id);
1528     pe_free_working_set(data_set);
1529     return rc;
1530 }
1531 
1532 static inline bool action_is_pending(pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
1533 {
1534     if (pcmk_any_flags_set(action->flags, pe_action_optional|pe_action_pseudo)
1535         || !pcmk_is_set(action->flags, pe_action_runnable)
1536         || pcmk__str_eq("notify", action->task, pcmk__str_casei)) {
1537         return false;
1538     }
1539     return true;
1540 }
1541 
1542 /*!
1543  * \internal
1544  * \brief Return TRUE if any actions in a list are pending
1545  *
1546  * \param[in] actions   List of actions to check
1547  *
1548  * \return TRUE if any actions in the list are pending, FALSE otherwise
1549  */
1550 static bool
1551 actions_are_pending(GListPtr actions)
     /* [previous][next][first][last][top][bottom][index][help] */
1552 {
1553     GListPtr action;
1554 
1555     for (action = actions; action != NULL; action = action->next) {
1556         pe_action_t *a = (pe_action_t *)action->data;
1557         if (action_is_pending(a)) {
1558             crm_notice("Waiting for %s (flags=0x%.8x)", a->uuid, a->flags);
1559             return TRUE;
1560         }
1561     }
1562     return FALSE;
1563 }
1564 
1565 /*!
1566  * \internal
1567  * \brief Print pending actions to stderr
1568  *
1569  * \param[in] actions   List of actions to check
1570  *
1571  * \return void
1572  */
1573 static void
1574 print_pending_actions(GListPtr actions)
     /* [previous][next][first][last][top][bottom][index][help] */
1575 {
1576     GListPtr action;
1577 
1578     fprintf(stderr, "Pending actions:\n");
1579     for (action = actions; action != NULL; action = action->next) {
1580         pe_action_t *a = (pe_action_t *) action->data;
1581 
1582         if (action_is_pending(a)) {
1583             fprintf(stderr, "\tAction %d: %s", a->id, a->uuid);
1584             if (a->node) {
1585                 fprintf(stderr, "\ton %s", a->node->details->uname);
1586             }
1587             fprintf(stderr, "\n");
1588         }
1589     }
1590 }
1591 
1592 /* For --wait, timeout (in seconds) to use if caller doesn't specify one */
1593 #define WAIT_DEFAULT_TIMEOUT_S (60 * 60)
1594 
1595 /* For --wait, how long to sleep between cluster state checks */
1596 #define WAIT_SLEEP_S (2)
1597 
1598 /*!
1599  * \internal
1600  * \brief Wait until all pending cluster actions are complete
1601  *
1602  * This waits until either the CIB's transition graph is idle or a timeout is
1603  * reached.
1604  *
1605  * \param[in] timeout_ms Consider failed if actions do not complete in this time
1606  *                       (specified in milliseconds, but one-second granularity
1607  *                       is actually used; if 0, a default will be used)
1608  * \param[in] cib        Connection to the CIB manager
1609  *
1610  * \return Standard Pacemaker return code
1611  */
1612 int
1613 wait_till_stable(int timeout_ms, cib_t * cib)
     /* [previous][next][first][last][top][bottom][index][help] */
1614 {
1615     pe_working_set_t *data_set = NULL;
1616     int rc = pcmk_rc_ok;
1617     int timeout_s = timeout_ms? ((timeout_ms + 999) / 1000) : WAIT_DEFAULT_TIMEOUT_S;
1618     time_t expire_time = time(NULL) + timeout_s;
1619     time_t time_diff;
1620     bool printed_version_warning = BE_QUIET; // i.e. don't print if quiet
1621 
1622     data_set = pe_new_working_set();
1623     if (data_set == NULL) {
1624         return ENOMEM;
1625     }
1626     pe__set_working_set_flags(data_set, pe_flag_no_counts|pe_flag_no_compat);
1627 
1628     do {
1629 
1630         /* Abort if timeout is reached */
1631         time_diff = expire_time - time(NULL);
1632         if (time_diff > 0) {
1633             crm_info("Waiting up to %ld seconds for cluster actions to complete", time_diff);
1634         } else {
1635             print_pending_actions(data_set->actions);
1636             pe_free_working_set(data_set);
1637             return ETIME;
1638         }
1639         if (rc == pcmk_rc_ok) { /* this avoids sleep on first loop iteration */
1640             sleep(WAIT_SLEEP_S);
1641         }
1642 
1643         /* Get latest transition graph */
1644         pe_reset_working_set(data_set);
1645         rc = update_working_set_from_cib(data_set, cib);
1646         if (rc != pcmk_rc_ok) {
1647             pe_free_working_set(data_set);
1648             return rc;
1649         }
1650         pcmk__schedule_actions(data_set, data_set->input, NULL);
1651 
1652         if (!printed_version_warning) {
1653             /* If the DC has a different version than the local node, the two
1654              * could come to different conclusions about what actions need to be
1655              * done. Warn the user in this case.
1656              *
1657              * @TODO A possible long-term solution would be to reimplement the
1658              * wait as a new controller operation that would be forwarded to the
1659              * DC. However, that would have potential problems of its own.
1660              */
1661             const char *dc_version = g_hash_table_lookup(data_set->config_hash,
1662                                                          "dc-version");
1663 
1664             if (!pcmk__str_eq(dc_version, PACEMAKER_VERSION "-" BUILD_VERSION, pcmk__str_casei)) {
1665                 printf("warning: wait option may not work properly in "
1666                        "mixed-version cluster\n");
1667                 printed_version_warning = TRUE;
1668             }
1669         }
1670 
1671     } while (actions_are_pending(data_set->actions));
1672 
1673     pe_free_working_set(data_set);
1674     return rc;
1675 }
1676 
1677 crm_exit_t
1678 cli_resource_execute_from_params(const char *rsc_name, const char *rsc_class,
     /* [previous][next][first][last][top][bottom][index][help] */
1679                                  const char *rsc_prov, const char *rsc_type,
1680                                  const char *action, GHashTable *params,
1681                                  GHashTable *override_hash, int timeout_ms,
1682                                  int resource_verbose, gboolean force)
1683 {
1684     GHashTable *params_copy = NULL;
1685     crm_exit_t exit_code = CRM_EX_OK;
1686     svc_action_t *op = NULL;
1687 
1688     if (pcmk__str_eq(rsc_class, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
1689         CMD_ERR("Sorry, the %s option doesn't support %s resources yet",
1690                 action, rsc_class);
1691         crm_exit(CRM_EX_UNIMPLEMENT_FEATURE);
1692     }
1693 
1694     /* If no timeout was provided, grab the default. */
1695     if (timeout_ms == 0) {
1696         timeout_ms = crm_get_msec(CRM_DEFAULT_OP_TIMEOUT_S);
1697     }
1698 
1699     /* add meta_timeout env needed by some resource agents */
1700     g_hash_table_insert(params, strdup("CRM_meta_timeout"),
1701                         crm_strdup_printf("%d", timeout_ms));
1702 
1703     /* add crm_feature_set env needed by some resource agents */
1704     g_hash_table_insert(params, strdup(XML_ATTR_CRM_VERSION), strdup(CRM_FEATURE_SET));
1705 
1706     /* resources_action_create frees the params hash table it's passed, but we
1707      * may need to reuse it in a second call to resources_action_create.  Thus
1708      * we'll make a copy here so that gets freed and the original remains for
1709      * reuse.
1710      */
1711     params_copy = crm_str_table_dup(params);
1712 
1713     op = resources_action_create(rsc_name, rsc_class, rsc_prov, rsc_type, action, 0,
1714                                  timeout_ms, params_copy, 0);
1715     if (op == NULL) {
1716         /* Re-run with stderr enabled so we can display a sane error message */
1717         crm_enable_stderr(TRUE);
1718         params_copy = crm_str_table_dup(params);
1719         op = resources_action_create(rsc_name, rsc_class, rsc_prov, rsc_type, action, 0,
1720                                      timeout_ms, params_copy, 0);
1721 
1722         /* Callers of cli_resource_execute expect that the params hash table will
1723          * be freed.  That function uses this one, so for that reason and for
1724          * making the two act the same, we should free the hash table here too.
1725          */
1726         g_hash_table_destroy(params);
1727 
1728         /* We know op will be NULL, but this makes static analysis happy */
1729         services_action_free(op);
1730         crm_exit(CRM_EX_DATAERR);
1731         return exit_code; // Never reached, but helps static analysis
1732     }
1733 
1734     setenv("HA_debug", resource_verbose > 0 ? "1" : "0", 1);
1735     if(resource_verbose > 1) {
1736         setenv("OCF_TRACE_RA", "1", 1);
1737     }
1738 
1739     /* A resource agent using the standard ocf-shellfuncs library will not print
1740      * messages to stderr if it doesn't have a controlling terminal (e.g. if
1741      * crm_resource is called via script or ssh). This forces it to do so.
1742      */
1743     setenv("OCF_TRACE_FILE", "/dev/stderr", 0);
1744 
1745     if (override_hash) {
1746         GHashTableIter iter;
1747         char *name = NULL;
1748         char *value = NULL;
1749 
1750         g_hash_table_iter_init(&iter, override_hash);
1751         while (g_hash_table_iter_next(&iter, (gpointer *) & name, (gpointer *) & value)) {
1752             printf("Overriding the cluster configuration for '%s' with '%s' = '%s'\n",
1753                    rsc_name, name, value);
1754             g_hash_table_replace(op->params, strdup(name), strdup(value));
1755         }
1756     }
1757 
1758     if (services_action_sync(op)) {
1759         int more, lpc, last;
1760         char *local_copy = NULL;
1761 
1762         exit_code = op->rc;
1763 
1764         if (op->status == PCMK_LRM_OP_DONE) {
1765             printf("Operation %s for %s (%s:%s:%s) returned: '%s' (%d)\n",
1766                    action, rsc_name, rsc_class, rsc_prov ? rsc_prov : "", rsc_type,
1767                    services_ocf_exitcode_str(op->rc), op->rc);
1768         } else {
1769             printf("Operation %s for %s (%s:%s:%s) failed: '%s' (%d)\n",
1770                    action, rsc_name, rsc_class, rsc_prov ? rsc_prov : "", rsc_type,
1771                    services_lrm_status_str(op->status), op->status);
1772         }
1773 
1774         /* hide output for validate-all if not in verbose */
1775         if (resource_verbose == 0 && pcmk__str_eq(action, "validate-all", pcmk__str_casei))
1776             goto done;
1777 
1778         if (op->stdout_data) {
1779             local_copy = strdup(op->stdout_data);
1780             more = strlen(local_copy);
1781             last = 0;
1782 
1783             for (lpc = 0; lpc < more; lpc++) {
1784                 if (local_copy[lpc] == '\n' || local_copy[lpc] == 0) {
1785                     local_copy[lpc] = 0;
1786                     printf(" >  stdout: %s\n", local_copy + last);
1787                     last = lpc + 1;
1788                 }
1789             }
1790             free(local_copy);
1791         }
1792         if (op->stderr_data) {
1793             local_copy = strdup(op->stderr_data);
1794             more = strlen(local_copy);
1795             last = 0;
1796 
1797             for (lpc = 0; lpc < more; lpc++) {
1798                 if (local_copy[lpc] == '\n' || local_copy[lpc] == 0) {
1799                     local_copy[lpc] = 0;
1800                     printf(" >  stderr: %s\n", local_copy + last);
1801                     last = lpc + 1;
1802                 }
1803             }
1804             free(local_copy);
1805         }
1806     } else {
1807         exit_code = op->rc == 0 ? CRM_EX_ERROR : op->rc;
1808     }
1809 
1810 done:
1811     services_action_free(op);
1812     /* See comment above about why we free params here. */
1813     g_hash_table_destroy(params);
1814     return exit_code;
1815 }
1816 
1817 crm_exit_t
1818 cli_resource_execute(pe_resource_t *rsc, const char *requested_name,
     /* [previous][next][first][last][top][bottom][index][help] */
1819                      const char *rsc_action, GHashTable *override_hash,
1820                      int timeout_ms, cib_t * cib, pe_working_set_t *data_set,
1821                      int resource_verbose, gboolean force)
1822 {
1823     crm_exit_t exit_code = CRM_EX_OK;
1824     const char *rid = NULL;
1825     const char *rtype = NULL;
1826     const char *rprov = NULL;
1827     const char *rclass = NULL;
1828     const char *action = NULL;
1829     GHashTable *params = NULL;
1830 
1831     if (pcmk__str_eq(rsc_action, "validate", pcmk__str_casei)) {
1832         action = "validate-all";
1833 
1834     } else if (pcmk__str_eq(rsc_action, "force-check", pcmk__str_casei)) {
1835         action = "monitor";
1836 
1837     } else if (pcmk__str_eq(rsc_action, "force-stop", pcmk__str_casei)) {
1838         action = rsc_action+6;
1839 
1840     } else if (pcmk__strcase_any_of(rsc_action, "force-start", "force-demote",
1841                                     "force-promote", NULL)) {
1842         action = rsc_action+6;
1843 
1844         if(pe_rsc_is_clone(rsc)) {
1845             int rc = cli_resource_search(rsc, requested_name, data_set);
1846             if(rc > 0 && force == FALSE) {
1847                 CMD_ERR("It is not safe to %s %s here: the cluster claims it is already active",
1848                         action, rsc->id);
1849                 CMD_ERR("Try setting target-role=Stopped first or specifying "
1850                         "the force option");
1851                 crm_exit(CRM_EX_UNSAFE);
1852             }
1853         }
1854 
1855     } else {
1856         action = rsc_action;
1857     }
1858 
1859     if(pe_rsc_is_clone(rsc)) {
1860         /* Grab the first child resource in the hope it's not a group */
1861         rsc = rsc->children->data;
1862     }
1863 
1864     if(rsc->variant == pe_group) {
1865         CMD_ERR("Sorry, the %s option doesn't support group resources",
1866                 rsc_action);
1867         crm_exit(CRM_EX_UNIMPLEMENT_FEATURE);
1868     }
1869 
1870     rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
1871     rprov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
1872     rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE);
1873 
1874     params = generate_resource_params(rsc, data_set);
1875 
1876     if (timeout_ms == 0) {
1877         timeout_ms = pe_get_configured_timeout(rsc, action, data_set);
1878     }
1879 
1880     rid = pe_rsc_is_anon_clone(rsc->parent)? requested_name : rsc->id;
1881 
1882     exit_code = cli_resource_execute_from_params(rid, rclass, rprov, rtype, action,
1883                                                  params, override_hash, timeout_ms,
1884                                                  resource_verbose, force);
1885     return exit_code;
1886 }
1887 
1888 // \return Standard Pacemaker return code
1889 int
1890 cli_resource_move(pe_resource_t *rsc, const char *rsc_id, const char *host_name,
     /* [previous][next][first][last][top][bottom][index][help] */
1891                   const char *move_lifetime, cib_t *cib, int cib_options,
1892                   pe_working_set_t *data_set, gboolean promoted_role_only,
1893                   gboolean force)
1894 {
1895     int rc = pcmk_rc_ok;
1896     unsigned int count = 0;
1897     pe_node_t *current = NULL;
1898     pe_node_t *dest = pe_find_node(data_set->nodes, host_name);
1899     bool cur_is_dest = FALSE;
1900 
1901     if (dest == NULL) {
1902         return pcmk_rc_node_unknown;
1903     }
1904 
1905     if (promoted_role_only && !pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
1906         pe_resource_t *p = uber_parent(rsc);
1907 
1908         if (pcmk_is_set(p->flags, pe_rsc_promotable)) {
1909             CMD_ERR("Using parent '%s' for move instead of '%s'.", rsc->id, rsc_id);
1910             rsc_id = p->id;
1911             rsc = p;
1912 
1913         } else {
1914             CMD_ERR("Ignoring master option: %s is not promotable", rsc_id);
1915             promoted_role_only = FALSE;
1916         }
1917     }
1918 
1919     current = pe__find_active_requires(rsc, &count);
1920 
1921     if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
1922         GListPtr iter = NULL;
1923         unsigned int master_count = 0;
1924         pe_node_t *master_node = NULL;
1925 
1926         for(iter = rsc->children; iter; iter = iter->next) {
1927             pe_resource_t *child = (pe_resource_t *)iter->data;
1928             enum rsc_role_e child_role = child->fns->state(child, TRUE);
1929 
1930             if(child_role == RSC_ROLE_MASTER) {
1931                 rsc = child;
1932                 master_node = pe__current_node(child);
1933                 master_count++;
1934             }
1935         }
1936         if (promoted_role_only || master_count) {
1937             count = master_count;
1938             current = master_node;
1939         }
1940 
1941     }
1942 
1943     if (count > 1) {
1944         if (pe_rsc_is_clone(rsc)) {
1945             current = NULL;
1946         } else {
1947             return pcmk_rc_multiple;
1948         }
1949     }
1950 
1951     if (current && (current->details == dest->details)) {
1952         cur_is_dest = TRUE;
1953         if (force) {
1954             crm_info("%s is already %s on %s, reinforcing placement with location constraint.",
1955                      rsc_id, promoted_role_only?"promoted":"active", dest->details->uname);
1956         } else {
1957             return pcmk_rc_already;
1958         }
1959     }
1960 
1961     /* Clear any previous prefer constraints across all nodes. */
1962     cli_resource_clear(rsc_id, NULL, data_set->nodes, cib, cib_options, FALSE, force);
1963 
1964     /* Clear any previous ban constraints on 'dest'. */
1965     cli_resource_clear(rsc_id, dest->details->uname, data_set->nodes, cib,
1966                        cib_options, TRUE, force);
1967 
1968     /* Record an explicit preference for 'dest' */
1969     rc = cli_resource_prefer(rsc_id, dest->details->uname, move_lifetime,
1970                              cib, cib_options, promoted_role_only);
1971 
1972     crm_trace("%s%s now prefers node %s%s",
1973               rsc->id, promoted_role_only?" (master)":"", dest->details->uname, force?"(forced)":"");
1974 
1975     /* only ban the previous location if current location != destination location.
1976      * it is possible to use -M to enforce a location without regard of where the
1977      * resource is currently located */
1978     if(force && (cur_is_dest == FALSE)) {
1979         /* Ban the original location if possible */
1980         if(current) {
1981             (void)cli_resource_ban(rsc_id, current->details->uname, move_lifetime,
1982                                    NULL, cib, cib_options, promoted_role_only);
1983 
1984         } else if(count > 1) {
1985             CMD_ERR("Resource '%s' is currently %s in %d locations. "
1986                     "One may now move to %s",
1987                     rsc_id, (promoted_role_only? "promoted" : "active"),
1988                     count, dest->details->uname);
1989             CMD_ERR("To prevent '%s' from being %s at a specific location, "
1990                     "specify a node.",
1991                     rsc_id, (promoted_role_only? "promoted" : "active"));
1992 
1993         } else {
1994             crm_trace("Not banning %s from its current location: not active", rsc_id);
1995         }
1996     }
1997 
1998     return rc;
1999 }
2000 
2001 static void
2002 cli_resource_why_without_rsc_and_host(cib_t *cib_conn,GListPtr resources)
     /* [previous][next][first][last][top][bottom][index][help] */
2003 {
2004     GListPtr lpc = NULL;
2005     GListPtr hosts = NULL;
2006 
2007     for (lpc = resources; lpc != NULL; lpc = lpc->next) {
2008         pe_resource_t *rsc = (pe_resource_t *) lpc->data;
2009         rsc->fns->location(rsc, &hosts, TRUE);
2010 
2011         if (hosts == NULL) {
2012             printf("Resource %s is not running\n", rsc->id);
2013         } else {
2014             printf("Resource %s is running\n", rsc->id);
2015         }
2016 
2017         cli_resource_check(cib_conn, rsc);
2018         g_list_free(hosts);
2019         hosts = NULL;
2020      }
2021 
2022 }
2023 
2024 static void
2025 cli_resource_why_with_rsc_and_host(cib_t *cib_conn, GListPtr resources,
     /* [previous][next][first][last][top][bottom][index][help] */
2026                                    pe_resource_t *rsc, const char *host_uname)
2027 {
2028     if (resource_is_running_on(rsc, host_uname)) {
2029         printf("Resource %s is running on host %s\n",rsc->id,host_uname);
2030     } else {
2031         printf("Resource %s is not running on host %s\n", rsc->id, host_uname);
2032     }
2033     cli_resource_check(cib_conn, rsc);
2034 }
2035 
2036 static void
2037 cli_resource_why_without_rsc_with_host(cib_t *cib_conn,GListPtr resources,pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
2038 {
2039     const char* host_uname =  node->details->uname;
2040     GListPtr allResources = node->details->allocated_rsc;
2041     GListPtr activeResources = node->details->running_rsc;
2042     GListPtr unactiveResources = pcmk__subtract_lists(allResources,activeResources,(GCompareFunc) strcmp);
2043     GListPtr lpc = NULL;
2044 
2045     for (lpc = activeResources; lpc != NULL; lpc = lpc->next) {
2046         pe_resource_t *rsc = (pe_resource_t *) lpc->data;
2047         printf("Resource %s is running on host %s\n",rsc->id,host_uname);
2048         cli_resource_check(cib_conn,rsc);
2049     }
2050 
2051     for(lpc = unactiveResources; lpc != NULL; lpc = lpc->next) {
2052         pe_resource_t *rsc = (pe_resource_t *) lpc->data;
2053         printf("Resource %s is assigned to host %s but not running\n",
2054                rsc->id, host_uname);
2055         cli_resource_check(cib_conn,rsc);
2056      }
2057 
2058      g_list_free(allResources);
2059      g_list_free(activeResources);
2060      g_list_free(unactiveResources);
2061 }
2062 
2063 static void
2064 cli_resource_why_with_rsc_without_host(cib_t *cib_conn, GListPtr resources,
     /* [previous][next][first][last][top][bottom][index][help] */
2065                                        pe_resource_t *rsc)
2066 {
2067     GListPtr hosts = NULL;
2068 
2069     rsc->fns->location(rsc, &hosts, TRUE);
2070     printf("Resource %s is %srunning\n", rsc->id, (hosts? "" : "not "));
2071     cli_resource_check(cib_conn, rsc);
2072     g_list_free(hosts);
2073 }
2074 
2075 void cli_resource_why(cib_t *cib_conn, GListPtr resources, pe_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
2076                       pe_node_t *node)
2077 {
2078     const char *host_uname = (node == NULL)? NULL : node->details->uname;
2079 
2080     if ((rsc == NULL) && (host_uname == NULL)) {
2081         cli_resource_why_without_rsc_and_host(cib_conn, resources);
2082 
2083     } else if ((rsc != NULL) && (host_uname != NULL)) {
2084         cli_resource_why_with_rsc_and_host(cib_conn, resources, rsc,
2085                                            host_uname);
2086 
2087     } else if ((rsc == NULL) && (host_uname != NULL)) {
2088         cli_resource_why_without_rsc_with_host(cib_conn, resources, node);
2089 
2090     } else if ((rsc != NULL) && (host_uname == NULL)) {
2091         cli_resource_why_with_rsc_without_host(cib_conn, resources, rsc);
2092     }
2093 }

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