root/tools/crm_resource_ban.c

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

DEFINITIONS

This source file includes following definitions.
  1. parse_cli_lifetime
  2. cli_resource_ban
  3. cli_resource_prefer
  4. resource_clear_node_in_expr
  5. resource_clear_node_in_location
  6. cli_resource_clear
  7. build_clear_xpath_string
  8. cli_resource_clear_all_expired

   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 
  12 #define XPATH_MAX 1024
  13 
  14 static char *
  15 parse_cli_lifetime(const char *move_lifetime)
     /* [previous][next][first][last][top][bottom][index][help] */
  16 {
  17     char *later_s = NULL;
  18     crm_time_t *now = NULL;
  19     crm_time_t *later = NULL;
  20     crm_time_t *duration = NULL;
  21 
  22     if (move_lifetime == NULL) {
  23         return NULL;
  24     }
  25 
  26     duration = crm_time_parse_duration(move_lifetime);
  27     if (duration == NULL) {
  28         CMD_ERR("Invalid duration specified: %s", move_lifetime);
  29         CMD_ERR("Please refer to"
  30                 " https://en.wikipedia.org/wiki/ISO_8601#Durations"
  31                 " for examples of valid durations");
  32         return NULL;
  33     }
  34 
  35     now = crm_time_new(NULL);
  36     later = crm_time_add(now, duration);
  37     if (later == NULL) {
  38         CMD_ERR("Unable to add %s to current time", move_lifetime);
  39         CMD_ERR("Please report to " PACKAGE_BUGREPORT " as possible bug");
  40         crm_time_free(now);
  41         crm_time_free(duration);
  42         return NULL;
  43     }
  44 
  45     crm_time_log(LOG_INFO, "now     ", now,
  46                  crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
  47     crm_time_log(LOG_INFO, "later   ", later,
  48                  crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
  49     crm_time_log(LOG_INFO, "duration", duration, crm_time_log_date | crm_time_log_timeofday);
  50     later_s = crm_time_as_string(later, crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
  51     printf("Migration will take effect until: %s\n", later_s);
  52 
  53     crm_time_free(duration);
  54     crm_time_free(later);
  55     crm_time_free(now);
  56     return later_s;
  57 }
  58 
  59 // \return Standard Pacemaker return code
  60 int
  61 cli_resource_ban(const char *rsc_id, const char *host, const char *move_lifetime,
     /* [previous][next][first][last][top][bottom][index][help] */
  62                  GListPtr allnodes, cib_t * cib_conn, int cib_options,
  63                  gboolean promoted_role_only)
  64 {
  65     char *later_s = NULL;
  66     int rc = pcmk_rc_ok;
  67     xmlNode *fragment = NULL;
  68     xmlNode *location = NULL;
  69 
  70     if(host == NULL) {
  71         GListPtr n = allnodes;
  72         for(; n && rc == pcmk_rc_ok; n = n->next) {
  73             pe_node_t *target = n->data;
  74 
  75             rc = cli_resource_ban(rsc_id, target->details->uname, move_lifetime,
  76                                   NULL, cib_conn, cib_options, promoted_role_only);
  77         }
  78         return rc;
  79     }
  80 
  81     later_s = parse_cli_lifetime(move_lifetime);
  82     if(move_lifetime && later_s == NULL) {
  83         return EINVAL;
  84     }
  85 
  86     fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
  87 
  88     location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
  89     crm_xml_set_id(location, "cli-ban-%s-on-%s", rsc_id, host);
  90 
  91     if (BE_QUIET == FALSE) {
  92         CMD_ERR("WARNING: Creating rsc_location constraint '%s'"
  93                 " with a score of -INFINITY for resource %s"
  94                 " on %s.", ID(location), rsc_id, host);
  95         CMD_ERR("\tThis will prevent %s from %s on %s until the constraint "
  96                 "is removed using the clear option or by editing the CIB "
  97                 "with an appropriate tool",
  98                 rsc_id, (promoted_role_only? "being promoted" : "running"), host);
  99         CMD_ERR("\tThis will be the case even if %s is"
 100                 " the last node in the cluster", host);
 101     }
 102 
 103     crm_xml_add(location, XML_LOC_ATTR_SOURCE, rsc_id);
 104     if(promoted_role_only) {
 105         crm_xml_add(location, XML_RULE_ATTR_ROLE, RSC_ROLE_MASTER_S);
 106     } else {
 107         crm_xml_add(location, XML_RULE_ATTR_ROLE, RSC_ROLE_STARTED_S);
 108     }
 109 
 110     if (later_s == NULL) {
 111         /* Short form */
 112         crm_xml_add(location, XML_CIB_TAG_NODE, host);
 113         crm_xml_add(location, XML_RULE_ATTR_SCORE, CRM_MINUS_INFINITY_S);
 114 
 115     } else {
 116         xmlNode *rule = create_xml_node(location, XML_TAG_RULE);
 117         xmlNode *expr = create_xml_node(rule, XML_TAG_EXPRESSION);
 118 
 119         crm_xml_set_id(rule, "cli-ban-%s-on-%s-rule", rsc_id, host);
 120         crm_xml_add(rule, XML_RULE_ATTR_SCORE, CRM_MINUS_INFINITY_S);
 121         crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and");
 122 
 123         crm_xml_set_id(expr, "cli-ban-%s-on-%s-expr", rsc_id, host);
 124         crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, CRM_ATTR_UNAME);
 125         crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq");
 126         crm_xml_add(expr, XML_EXPR_ATTR_VALUE, host);
 127         crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string");
 128 
 129         expr = create_xml_node(rule, "date_expression");
 130         crm_xml_set_id(expr, "cli-ban-%s-on-%s-lifetime", rsc_id, host);
 131         crm_xml_add(expr, "operation", "lt");
 132         crm_xml_add(expr, "end", later_s);
 133     }
 134 
 135     crm_log_xml_notice(fragment, "Modify");
 136     rc = cib_conn->cmds->update(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, cib_options);
 137     rc = pcmk_legacy2rc(rc);
 138 
 139     free_xml(fragment);
 140     free(later_s);
 141     return rc;
 142 }
 143 
 144 // \return Standard Pacemaker return code
 145 int
 146 cli_resource_prefer(const char *rsc_id, const char *host, const char *move_lifetime,
     /* [previous][next][first][last][top][bottom][index][help] */
 147                     cib_t * cib_conn, int cib_options, gboolean promoted_role_only)
 148 {
 149     char *later_s = parse_cli_lifetime(move_lifetime);
 150     int rc = pcmk_rc_ok;
 151     xmlNode *location = NULL;
 152     xmlNode *fragment = NULL;
 153 
 154     if(move_lifetime && later_s == NULL) {
 155         return EINVAL;
 156     }
 157 
 158     if(cib_conn == NULL) {
 159         free(later_s);
 160         return ENOTCONN;
 161     }
 162 
 163     fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
 164 
 165     location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
 166     crm_xml_set_id(location, "cli-prefer-%s", rsc_id);
 167 
 168     crm_xml_add(location, XML_LOC_ATTR_SOURCE, rsc_id);
 169     if(promoted_role_only) {
 170         crm_xml_add(location, XML_RULE_ATTR_ROLE, RSC_ROLE_MASTER_S);
 171     } else {
 172         crm_xml_add(location, XML_RULE_ATTR_ROLE, RSC_ROLE_STARTED_S);
 173     }
 174 
 175     if (later_s == NULL) {
 176         /* Short form */
 177         crm_xml_add(location, XML_CIB_TAG_NODE, host);
 178         crm_xml_add(location, XML_RULE_ATTR_SCORE, CRM_INFINITY_S);
 179 
 180     } else {
 181         xmlNode *rule = create_xml_node(location, XML_TAG_RULE);
 182         xmlNode *expr = create_xml_node(rule, XML_TAG_EXPRESSION);
 183 
 184         crm_xml_set_id(rule, "cli-prefer-rule-%s", rsc_id);
 185         crm_xml_add(rule, XML_RULE_ATTR_SCORE, CRM_INFINITY_S);
 186         crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and");
 187 
 188         crm_xml_set_id(expr, "cli-prefer-expr-%s", rsc_id);
 189         crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, CRM_ATTR_UNAME);
 190         crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq");
 191         crm_xml_add(expr, XML_EXPR_ATTR_VALUE, host);
 192         crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string");
 193 
 194         expr = create_xml_node(rule, "date_expression");
 195         crm_xml_set_id(expr, "cli-prefer-lifetime-end-%s", rsc_id);
 196         crm_xml_add(expr, "operation", "lt");
 197         crm_xml_add(expr, "end", later_s);
 198     }
 199 
 200     crm_log_xml_info(fragment, "Modify");
 201     rc = cib_conn->cmds->update(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, cib_options);
 202     rc = pcmk_legacy2rc(rc);
 203 
 204     free_xml(fragment);
 205     free(later_s);
 206     return rc;
 207 }
 208 
 209 /* Nodes can be specified two different ways in the CIB, so we have two different
 210  * functions to try clearing out any constraints on them:
 211  *
 212  * (1) The node could be given by attribute=/value= in an expression XML node.
 213  * That's what resource_clear_node_in_expr handles.  That XML looks like this:
 214  *
 215  * <rsc_location id="cli-prefer-dummy" rsc="dummy" role="Started">
 216  *   <rule id="cli-prefer-rule-dummy" score="INFINITY" boolean-op="and">
 217  *     <expression id="cli-prefer-expr-dummy" attribute="#uname" operation="eq" value="test02" type="string"/>
 218  *     <date_expression id="cli-prefer-lifetime-end-dummy" operation="lt" end="2018-12-12 14:05:37 -05:00"/>
 219  *   </rule>
 220  * </rsc_location>
 221  *
 222  * (2) The mode could be given by node= in an rsc_location XML node.  That's
 223  * what resource_clear_node_in_location handles.  That XML looks like this:
 224  *
 225  * <rsc_location id="cli-prefer-dummy" rsc="dummy" role="Started" node="node1" score="INFINITY"/>
 226  *
 227  * \return Standard Pacemaker return code
 228  */
 229 static int
 230 resource_clear_node_in_expr(const char *rsc_id, const char *host, cib_t * cib_conn,
     /* [previous][next][first][last][top][bottom][index][help] */
 231                             int cib_options)
 232 {
 233     int rc = pcmk_rc_ok;
 234     char *xpath_string = NULL;
 235 
 236     xpath_string = crm_strdup_printf("//rsc_location[@id='cli-prefer-%s'][rule[@id='cli-prefer-rule-%s']/expression[@attribute='#uname' and @value='%s']]",
 237                                      rsc_id, rsc_id, host);
 238 
 239     rc = cib_conn->cmds->remove(cib_conn, xpath_string, NULL, cib_xpath | cib_options);
 240     if (rc == -ENXIO) {
 241         rc = pcmk_rc_ok;
 242     } else {
 243         rc = pcmk_legacy2rc(rc);
 244     }
 245 
 246     free(xpath_string);
 247     return rc;
 248 }
 249 
 250 // \return Standard Pacemaker return code
 251 static int
 252 resource_clear_node_in_location(const char *rsc_id, const char *host, cib_t * cib_conn,
     /* [previous][next][first][last][top][bottom][index][help] */
 253                                 int cib_options, bool clear_ban_constraints, gboolean force)
 254 {
 255     int rc = pcmk_rc_ok;
 256     xmlNode *fragment = NULL;
 257     xmlNode *location = NULL;
 258 
 259     fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
 260 
 261     if (clear_ban_constraints == TRUE) {
 262         location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
 263         crm_xml_set_id(location, "cli-ban-%s-on-%s", rsc_id, host);
 264     }
 265 
 266     location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
 267     crm_xml_set_id(location, "cli-prefer-%s", rsc_id);
 268     if (force == FALSE) {
 269         crm_xml_add(location, XML_CIB_TAG_NODE, host);
 270     }
 271 
 272     crm_log_xml_info(fragment, "Delete");
 273     rc = cib_conn->cmds->remove(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, cib_options);
 274     if (rc == -ENXIO) {
 275         rc = pcmk_rc_ok;
 276     } else {
 277         rc = pcmk_legacy2rc(rc);
 278     }
 279 
 280     free(fragment);
 281     return rc;
 282 }
 283 
 284 // \return Standard Pacemaker return code
 285 int
 286 cli_resource_clear(const char *rsc_id, const char *host, GListPtr allnodes, cib_t * cib_conn,
     /* [previous][next][first][last][top][bottom][index][help] */
 287                    int cib_options, bool clear_ban_constraints, gboolean force)
 288 {
 289     int rc = pcmk_rc_ok;
 290 
 291     if(cib_conn == NULL) {
 292         return ENOTCONN;
 293     }
 294 
 295     if (host) {
 296         rc = resource_clear_node_in_expr(rsc_id, host, cib_conn, cib_options);
 297 
 298         /* rc does not tell us whether the previous operation did anything, only
 299          * whether it failed or not.  Thus, as long as it did not fail, we need
 300          * to try the second clear method.
 301          */
 302         if (rc == pcmk_rc_ok) {
 303             rc = resource_clear_node_in_location(rsc_id, host, cib_conn,
 304                                                  cib_options, clear_ban_constraints,
 305                                                  force);
 306         }
 307 
 308     } else {
 309         GListPtr n = allnodes;
 310 
 311         /* Iterate over all nodes, attempting to clear the constraint from each.
 312          * On the first error, abort.
 313          */
 314         for(; n; n = n->next) {
 315             pe_node_t *target = n->data;
 316 
 317             rc = cli_resource_clear(rsc_id, target->details->uname, NULL,
 318                                     cib_conn, cib_options, clear_ban_constraints,
 319                                     force);
 320             if (rc != pcmk_rc_ok) {
 321                 break;
 322             }
 323         }
 324     }
 325 
 326     return rc;
 327 }
 328 
 329 static char *
 330 build_clear_xpath_string(xmlNode *constraint_node, const char *rsc, const char *node, gboolean promoted_role_only)
     /* [previous][next][first][last][top][bottom][index][help] */
 331 {
 332     int offset = 0;
 333     char *xpath_string = NULL;
 334     char *first_half = NULL;
 335     char *rsc_role_substr = NULL;
 336     char *date_substr = NULL;
 337 
 338     if (pcmk__starts_with(ID(constraint_node), "cli-ban-")) {
 339         date_substr = crm_strdup_printf("//date_expression[@id='%s-lifetime']",
 340                                         ID(constraint_node));
 341 
 342     } else if (pcmk__starts_with(ID(constraint_node), "cli-prefer-")) {
 343         date_substr = crm_strdup_printf("//date_expression[@id='cli-prefer-lifetime-end-%s']",
 344                                         crm_element_value(constraint_node, "rsc"));
 345     } else {
 346         return NULL;
 347     }
 348 
 349     first_half = calloc(1, XPATH_MAX);
 350     offset += snprintf(first_half + offset, XPATH_MAX - offset, "//rsc_location");
 351 
 352     if (node != NULL || rsc != NULL || promoted_role_only == TRUE) {
 353         offset += snprintf(first_half + offset, XPATH_MAX - offset, "[");
 354 
 355         if (node != NULL) {
 356             if (rsc != NULL || promoted_role_only == TRUE) {
 357                 offset += snprintf(first_half + offset, XPATH_MAX - offset, "@node='%s' and ", node);
 358             } else {
 359                 offset += snprintf(first_half + offset, XPATH_MAX - offset, "@node='%s'", node);
 360             }
 361         }
 362 
 363         if (rsc != NULL && promoted_role_only == TRUE) {
 364             rsc_role_substr = crm_strdup_printf("@rsc='%s' and @role='%s'", rsc, RSC_ROLE_MASTER_S);
 365             offset += snprintf(first_half + offset, XPATH_MAX - offset, "@rsc='%s' and @role='%s']", rsc, RSC_ROLE_MASTER_S);
 366         } else if (rsc != NULL) {
 367             rsc_role_substr = crm_strdup_printf("@rsc='%s'", rsc);
 368             offset += snprintf(first_half + offset, XPATH_MAX - offset, "@rsc='%s']", rsc);
 369         } else if (promoted_role_only == TRUE) {
 370             rsc_role_substr = crm_strdup_printf("@role='%s'", RSC_ROLE_MASTER_S);
 371             offset += snprintf(first_half + offset, XPATH_MAX - offset, "@role='%s']", RSC_ROLE_MASTER_S);
 372         } else {
 373             offset += snprintf(first_half + offset, XPATH_MAX - offset, "]");
 374         }
 375     }
 376 
 377     if (node != NULL) {
 378         if (rsc_role_substr != NULL) {
 379             xpath_string = crm_strdup_printf("%s|//rsc_location[%s]/rule[expression[@attribute='#uname' and @value='%s']]%s",
 380                                              first_half, rsc_role_substr, node, date_substr);
 381         } else {
 382             xpath_string = crm_strdup_printf("%s|//rsc_location/rule[expression[@attribute='#uname' and @value='%s']]%s",
 383                                              first_half, node, date_substr);
 384         }
 385     } else {
 386         xpath_string = crm_strdup_printf("%s%s", first_half, date_substr);
 387     }
 388 
 389     free(first_half);
 390     free(date_substr);
 391     free(rsc_role_substr);
 392 
 393     return xpath_string;
 394 }
 395 
 396 // \return Standard Pacemaker return code
 397 int
 398 cli_resource_clear_all_expired(xmlNode *root, cib_t *cib_conn, int cib_options,
     /* [previous][next][first][last][top][bottom][index][help] */
 399                                const char *rsc, const char *node, gboolean promoted_role_only)
 400 {
 401     xmlXPathObject *xpathObj = NULL;
 402     xmlNode *cib_constraints = NULL;
 403     crm_time_t *now = crm_time_new(NULL);
 404     int i;
 405     int rc = pcmk_rc_ok;
 406 
 407     cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, root);
 408     xpathObj = xpath_search(cib_constraints, "//" XML_CONS_TAG_RSC_LOCATION);
 409 
 410     for (i = 0; i < numXpathResults(xpathObj); i++) {
 411         xmlNode *constraint_node = getXpathResult(xpathObj, i);
 412         xmlNode *date_expr_node = NULL;
 413         crm_time_t *end = NULL;
 414         char *xpath_string = NULL;
 415 
 416         xpath_string = build_clear_xpath_string(constraint_node, rsc, node, promoted_role_only);
 417         if (xpath_string == NULL) {
 418             continue;
 419         }
 420 
 421         date_expr_node = get_xpath_object(xpath_string, constraint_node, LOG_DEBUG);
 422         if (date_expr_node == NULL) {
 423             free(xpath_string);
 424             continue;
 425         }
 426 
 427         /* And then finally, see if the date expression is expired.  If so,
 428          * clear the constraint.
 429          */
 430         end = crm_time_new(crm_element_value(date_expr_node, "end"));
 431 
 432         if (crm_time_compare(now, end) == 1) {
 433             xmlNode *fragment = NULL;
 434             xmlNode *location = NULL;
 435 
 436             fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
 437             location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
 438             crm_xml_set_id(location, "%s", ID(constraint_node));
 439             crm_log_xml_info(fragment, "Delete");
 440 
 441             rc = cib_conn->cmds->remove(cib_conn, XML_CIB_TAG_CONSTRAINTS,
 442                                         fragment, cib_options);
 443             rc = pcmk_legacy2rc(rc);
 444 
 445             if (rc != pcmk_rc_ok) {
 446                 free(xpath_string);
 447                 goto bail;
 448             }
 449 
 450             free_xml(fragment);
 451         }
 452 
 453         crm_time_free(end);
 454         free(xpath_string);
 455     }
 456 
 457 bail:
 458     freeXpathObject(xpathObj);
 459     crm_time_free(now);
 460     return rc;
 461 }

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