root/tools/crm_ticket.c

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

DEFINITIONS

This source file includes following definitions.
  1. find_ticket
  2. print_date
  3. print_ticket
  4. print_ticket_list
  5. find_ticket_state
  6. find_ticket_constraints
  7. dump_ticket_xml
  8. dump_constraints
  9. find_ticket_state_attr_legacy
  10. delete_ticket_state_attr_legacy
  11. get_ticket_state_attr
  12. ticket_warning
  13. allow_modification
  14. modify_ticket_state
  15. delete_ticket_state
  16. main

   1 
   2 /* 
   3  * Copyright (C) 2012 Gao,Yan <ygao@suse.com>
   4  * 
   5  * This program is free software; you can redistribute it and/or
   6  * modify it under the terms of the GNU General Public
   7  * License as published by the Free Software Foundation; either
   8  * version 2 of the License, or (at your option) any later version.
   9  * 
  10  * This software is distributed in the hope that it will be useful,
  11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13  * General Public License for more details.
  14  * 
  15  * You should have received a copy of the GNU General Public
  16  * License along with this library; if not, write to the Free Software
  17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  18  */
  19 
  20 #include <crm_internal.h>
  21 
  22 #include <sys/param.h>
  23 
  24 #include <crm/crm.h>
  25 
  26 #include <stdio.h>
  27 #include <sys/types.h>
  28 #include <unistd.h>
  29 
  30 #include <stdlib.h>
  31 #include <errno.h>
  32 #include <fcntl.h>
  33 #include <libgen.h>
  34 
  35 #include <crm/msg_xml.h>
  36 #include <crm/common/xml.h>
  37 #include <crm/common/ipc.h>
  38 
  39 #include <crm/cib.h>
  40 #include <crm/pengine/rules.h>
  41 #include <crm/pengine/status.h>
  42 
  43 #include <../pengine/pengine.h>
  44 
  45 gboolean do_force = FALSE;
  46 gboolean BE_QUIET = FALSE;
  47 const char *ticket_id = NULL;
  48 const char *get_attr_name = NULL;
  49 const char *attr_name = NULL;
  50 const char *attr_value = NULL;
  51 const char *attr_id = NULL;
  52 const char *set_name = NULL;
  53 const char *attr_default = NULL;
  54 char ticket_cmd = 'S';
  55 char *xml_file = NULL;
  56 int cib_options = cib_sync_call;
  57 
  58 extern void cleanup_alloc_calculations(pe_working_set_t * data_set);
  59 
  60 #define CMD_ERR(fmt, args...) do {              \
  61         crm_warn(fmt, ##args);                  \
  62         fprintf(stderr, fmt, ##args);           \
  63     } while(0)
  64 
  65 static ticket_t *
  66 find_ticket(const char *ticket_id, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
  67 {
  68     ticket_t *ticket = NULL;
  69 
  70     ticket = g_hash_table_lookup(data_set->tickets, ticket_id);
  71 
  72     return ticket;
  73 }
  74 
  75 static void
  76 print_date(time_t time)
     /* [previous][next][first][last][top][bottom][index][help] */
  77 {
  78     int lpc = 0;
  79     char date_str[26];
  80 
  81     asctime_r(localtime(&time), date_str);
  82     for (; lpc < 26; lpc++) {
  83         if (date_str[lpc] == '\n') {
  84             date_str[lpc] = 0;
  85         }
  86     }
  87     fprintf(stdout, "'%s'", date_str);
  88 }
  89 
  90 static int
  91 print_ticket(ticket_t * ticket, gboolean raw, gboolean details)
     /* [previous][next][first][last][top][bottom][index][help] */
  92 {
  93     if (raw) {
  94         fprintf(stdout, "%s\n", ticket->id);
  95         return pcmk_ok;
  96     }
  97 
  98     fprintf(stdout, "%s\t%s %s",
  99             ticket->id, ticket->granted ? "granted" : "revoked",
 100             ticket->standby ? "[standby]" : "         ");
 101 
 102     if (details && g_hash_table_size(ticket->state) > 0) {
 103         GHashTableIter iter;
 104         const char *name = NULL;
 105         const char *value = NULL;
 106         int lpc = 0;
 107 
 108         fprintf(stdout, " (");
 109 
 110         g_hash_table_iter_init(&iter, ticket->state);
 111         while (g_hash_table_iter_next(&iter, (void **)&name, (void **)&value)) {
 112             if (lpc > 0) {
 113                 fprintf(stdout, ", ");
 114             }
 115             fprintf(stdout, "%s=", name);
 116             if (crm_str_eq(name, "last-granted", TRUE)
 117                 || crm_str_eq(name, "expires", TRUE)) {
 118                 print_date(crm_parse_int(value, 0));
 119             } else {
 120                 fprintf(stdout, "%s", value);
 121             }
 122             lpc++;
 123         }
 124 
 125         fprintf(stdout, ")\n");
 126 
 127     } else {
 128         if (ticket->last_granted > -1) {
 129             fprintf(stdout, " last-granted=");
 130             print_date(ticket->last_granted);
 131         }
 132         fprintf(stdout, "\n");
 133     }
 134 
 135     return pcmk_ok;
 136 }
 137 
 138 static int
 139 print_ticket_list(pe_working_set_t * data_set, gboolean raw, gboolean details)
     /* [previous][next][first][last][top][bottom][index][help] */
 140 {
 141     GHashTableIter iter;
 142     ticket_t *ticket = NULL;
 143 
 144     g_hash_table_iter_init(&iter, data_set->tickets);
 145 
 146     while (g_hash_table_iter_next(&iter, NULL, (void **)&ticket)) {
 147         print_ticket(ticket, raw, details);
 148     }
 149 
 150     return pcmk_ok;
 151 }
 152 
 153 #define XPATH_MAX 1024
 154 
 155 static int
 156 find_ticket_state(cib_t * the_cib, const char *ticket_id, xmlNode ** ticket_state_xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 157 {
 158     int offset = 0;
 159     int rc = pcmk_ok;
 160     xmlNode *xml_search = NULL;
 161 
 162     char *xpath_string = NULL;
 163 
 164     CRM_ASSERT(ticket_state_xml != NULL);
 165     *ticket_state_xml = NULL;
 166 
 167     xpath_string = calloc(1, XPATH_MAX);
 168     offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "%s", "/cib/status/tickets");
 169 
 170     if (ticket_id) {
 171         offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "/%s[@id=\"%s\"]",
 172                            XML_CIB_TAG_TICKET_STATE, ticket_id);
 173     }
 174 
 175     CRM_LOG_ASSERT(offset > 0);
 176     rc = the_cib->cmds->query(the_cib, xpath_string, &xml_search,
 177                               cib_sync_call | cib_scope_local | cib_xpath);
 178 
 179     if (rc != pcmk_ok) {
 180         goto bail;
 181     }
 182 
 183     crm_log_xml_debug(xml_search, "Match");
 184     if (xml_has_children(xml_search)) {
 185         if (ticket_id) {
 186             fprintf(stdout, "Multiple ticket_states match ticket_id=%s\n", ticket_id);
 187         }
 188         *ticket_state_xml = xml_search;
 189     } else {
 190         *ticket_state_xml = xml_search;
 191     }
 192 
 193   bail:
 194     free(xpath_string);
 195     return rc;
 196 }
 197 
 198 static int
 199 find_ticket_constraints(cib_t * the_cib, const char *ticket_id, xmlNode ** ticket_cons_xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 200 {
 201     int offset = 0;
 202     int rc = pcmk_ok;
 203     xmlNode *xml_search = NULL;
 204 
 205     char *xpath_string = NULL;
 206 
 207     CRM_ASSERT(ticket_cons_xml != NULL);
 208     *ticket_cons_xml = NULL;
 209 
 210     xpath_string = calloc(1, XPATH_MAX);
 211     offset +=
 212         snprintf(xpath_string + offset, XPATH_MAX - offset, "%s/%s",
 213                  get_object_path(XML_CIB_TAG_CONSTRAINTS), XML_CONS_TAG_RSC_TICKET);
 214 
 215     if (ticket_id) {
 216         offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "[@ticket=\"%s\"]",
 217                            ticket_id);
 218     }
 219 
 220     CRM_LOG_ASSERT(offset > 0);
 221     rc = the_cib->cmds->query(the_cib, xpath_string, &xml_search,
 222                               cib_sync_call | cib_scope_local | cib_xpath);
 223 
 224     if (rc != pcmk_ok) {
 225         goto bail;
 226     }
 227 
 228     crm_log_xml_debug(xml_search, "Match");
 229     *ticket_cons_xml = xml_search;
 230 
 231   bail:
 232     free(xpath_string);
 233     return rc;
 234 }
 235 
 236 static int
 237 dump_ticket_xml(cib_t * the_cib, const char *ticket_id)
     /* [previous][next][first][last][top][bottom][index][help] */
 238 {
 239     int rc = pcmk_ok;
 240     xmlNode *state_xml = NULL;
 241 
 242     rc = find_ticket_state(the_cib, ticket_id, &state_xml);
 243 
 244     if (state_xml == NULL) {
 245         return rc;
 246     }
 247 
 248     fprintf(stdout, "State XML:\n");
 249     if (state_xml) {
 250         char *state_xml_str = NULL;
 251 
 252         state_xml_str = dump_xml_formatted(state_xml);
 253         fprintf(stdout, "\n%s\n", crm_str(state_xml_str));
 254         free_xml(state_xml);
 255         free(state_xml_str);
 256     }
 257 
 258     return pcmk_ok;
 259 }
 260 
 261 static int
 262 dump_constraints(cib_t * the_cib, const char *ticket_id)
     /* [previous][next][first][last][top][bottom][index][help] */
 263 {
 264     int rc = pcmk_ok;
 265     xmlNode *cons_xml = NULL;
 266     char *cons_xml_str = NULL;
 267 
 268     rc = find_ticket_constraints(the_cib, ticket_id, &cons_xml);
 269 
 270     if (cons_xml == NULL) {
 271         return rc;
 272     }
 273 
 274     cons_xml_str = dump_xml_formatted(cons_xml);
 275     fprintf(stdout, "Constraints XML:\n\n%s\n", crm_str(cons_xml_str));
 276     free_xml(cons_xml);
 277     free(cons_xml_str);
 278 
 279     return pcmk_ok;
 280 }
 281 
 282 static int
 283 find_ticket_state_attr_legacy(cib_t * the_cib, const char *attr, const char *ticket_id,
     /* [previous][next][first][last][top][bottom][index][help] */
 284                               const char *set_type, const char *set_name, const char *attr_id,
 285                               const char *attr_name, char **value)
 286 {
 287     int offset = 0;
 288     int rc = pcmk_ok;
 289     xmlNode *xml_search = NULL;
 290 
 291     char *xpath_string = NULL;
 292 
 293     CRM_ASSERT(value != NULL);
 294     *value = NULL;
 295 
 296     xpath_string = calloc(1, XPATH_MAX);
 297     offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "%s", "/cib/status/tickets");
 298 
 299     if (set_type) {
 300         offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "/%s", set_type);
 301         if (set_name) {
 302             offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "[@id=\"%s\"]", set_name);
 303         }
 304     }
 305 
 306     offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "//nvpair[");
 307     if (attr_id) {
 308         offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "@id=\"%s\"", attr_id);
 309     }
 310 
 311     if (attr_name) {
 312         const char *attr_prefix = NULL;
 313         char *long_key = NULL;
 314 
 315         if (crm_str_eq(attr_name, "granted", TRUE)) {
 316             attr_prefix = "granted-ticket";
 317         } else {
 318             attr_prefix = attr_name;
 319         }
 320         long_key = crm_concat(attr_prefix, ticket_id, '-');
 321 
 322         if (attr_id) {
 323             offset += snprintf(xpath_string + offset, XPATH_MAX - offset, " and ");
 324         }
 325         offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "@name=\"%s\"", long_key);
 326 
 327         free(long_key);
 328     }
 329     offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "]");
 330     CRM_LOG_ASSERT(offset > 0);
 331 
 332     rc = the_cib->cmds->query(the_cib, xpath_string, &xml_search,
 333                               cib_sync_call | cib_scope_local | cib_xpath);
 334 
 335     if (rc != pcmk_ok) {
 336         goto bail;
 337     }
 338 
 339     crm_log_xml_debug(xml_search, "Match");
 340     if (xml_has_children(xml_search)) {
 341         xmlNode *child = NULL;
 342 
 343         rc = -EINVAL;
 344         fprintf(stdout, "Multiple attributes match name=%s\n", attr_name);
 345 
 346         for (child = __xml_first_child(xml_search); child != NULL; child = __xml_next(child)) {
 347             fprintf(stdout, "  Value: %s \t(id=%s)\n",
 348                     crm_element_value(child, XML_NVPAIR_ATTR_VALUE), ID(child));
 349         }
 350 
 351     } else {
 352         const char *tmp = crm_element_value(xml_search, attr);
 353 
 354         if (tmp) {
 355             *value = strdup(tmp);
 356         }
 357     }
 358 
 359   bail:
 360     free(xpath_string);
 361     free_xml(xml_search);
 362     return rc;
 363 }
 364 
 365 static int
 366 delete_ticket_state_attr_legacy(const char *ticket_id, const char *set_name, const char *attr_id,
     /* [previous][next][first][last][top][bottom][index][help] */
 367                                 const char *attr_name, cib_t * cib)
 368 {
 369     xmlNode *xml_obj = NULL;
 370 
 371     int rc = pcmk_ok;
 372     char *local_attr_id = NULL;
 373 
 374     rc = find_ticket_state_attr_legacy(cib, XML_ATTR_ID, ticket_id, XML_TAG_ATTR_SETS, set_name,
 375                                        attr_id, attr_name, &local_attr_id);
 376 
 377     if (rc == -ENXIO) {
 378         return pcmk_ok;
 379 
 380     } else if (rc != pcmk_ok) {
 381         return rc;
 382     }
 383 
 384     if (attr_id == NULL) {
 385         attr_id = local_attr_id;
 386     }
 387 
 388     xml_obj = crm_create_nvpair_xml(NULL, attr_id, /*attr_name*/ NULL, NULL);
 389     crm_log_xml_debug(xml_obj, "Delete");
 390 
 391     rc = cib->cmds->delete(cib, XML_CIB_TAG_STATUS, xml_obj, cib_options);
 392 
 393     if (rc == pcmk_ok) {
 394         fprintf(stdout, "Deleted legacy %s state attribute: id=%s%s%s%s%s\n", ticket_id,
 395                 local_attr_id, set_name ? " set=" : "", set_name ? set_name : "",
 396                 attr_name ? " name=" : "", attr_name ? attr_name : "");
 397     }
 398 
 399     free_xml(xml_obj);
 400     free(local_attr_id);
 401     return rc;
 402 }
 403 
 404 static int
 405 get_ticket_state_attr(const char *ticket_id, const char *attr_name, const char **attr_value,
     /* [previous][next][first][last][top][bottom][index][help] */
 406                       pe_working_set_t * data_set)
 407 {
 408     ticket_t *ticket = NULL;
 409 
 410     CRM_ASSERT(attr_value != NULL);
 411     *attr_value = NULL;
 412 
 413     ticket = g_hash_table_lookup(data_set->tickets, ticket_id);
 414     if (ticket == NULL) {
 415         return -ENXIO;
 416     }
 417 
 418     *attr_value = g_hash_table_lookup(ticket->state, attr_name);
 419     if (*attr_value == NULL) {
 420         return -ENXIO;
 421     }
 422 
 423     return pcmk_ok;
 424 }
 425 
 426 static gboolean
 427 ticket_warning(const char *ticket_id, const char *action)
     /* [previous][next][first][last][top][bottom][index][help] */
 428 {
 429     gboolean rc = FALSE;
 430     int offset = 0;
 431     static int text_max = 1024;
 432 
 433     char *warning = NULL;
 434     const char *word = NULL;
 435 
 436     warning = calloc(1, text_max);
 437     if (safe_str_eq(action, "grant")) {
 438         offset += snprintf(warning + offset, text_max - offset,
 439                            "This command cannot help you verify whether '%s' has been already granted elsewhere.\n",
 440                            ticket_id);
 441         word = "to";
 442 
 443     } else {
 444         offset += snprintf(warning + offset, text_max - offset,
 445                            "Revoking '%s' can trigger the specified 'loss-policy'(s) relating to '%s'.\n\n",
 446                            ticket_id, ticket_id);
 447 
 448         offset += snprintf(warning + offset, text_max - offset,
 449                            "You can check that with:\ncrm_ticket --ticket %s --constraints\n\n",
 450                            ticket_id);
 451 
 452         offset += snprintf(warning + offset, text_max - offset,
 453                            "Otherwise before revoking '%s', you may want to make '%s' standby with:\ncrm_ticket --ticket %s --standby\n\n",
 454                            ticket_id, ticket_id, ticket_id);
 455         word = "from";
 456     }
 457 
 458     offset += snprintf(warning + offset, text_max - offset,
 459                        "If you really want to %s '%s' %s this site now, and you know what you are doing,\n",
 460                        action, ticket_id, word);
 461 
 462     offset += snprintf(warning + offset, text_max - offset, 
 463                        "please specify --force.");
 464 
 465     CRM_LOG_ASSERT(offset > 0);
 466     fprintf(stdout, "%s\n", warning);
 467 
 468     free(warning);
 469     return rc;
 470 }
 471 
 472 static gboolean
 473 allow_modification(const char *ticket_id, GListPtr attr_delete,
     /* [previous][next][first][last][top][bottom][index][help] */
 474                    GHashTable *attr_set)
 475 {
 476     const char *value = NULL;
 477     GListPtr list_iter = NULL;
 478 
 479     if (do_force) {
 480         return TRUE;
 481     }
 482 
 483     if (g_hash_table_lookup_extended(attr_set, "granted", NULL, (gpointer *) & value)) {
 484         if (crm_is_true(value)) {
 485             ticket_warning(ticket_id, "grant");
 486             return FALSE;
 487 
 488         } else {
 489             ticket_warning(ticket_id, "revoke");
 490             return FALSE;
 491         }
 492     }
 493 
 494     for(list_iter = attr_delete; list_iter; list_iter = list_iter->next) {
 495         const char *key = (const char *)list_iter->data;
 496 
 497         if (safe_str_eq(key, "granted")) {
 498             ticket_warning(ticket_id, "revoke");
 499             return FALSE;
 500         }
 501     }
 502 
 503     return TRUE;
 504 }
 505 
 506 static int
 507 modify_ticket_state(const char * ticket_id, GListPtr attr_delete, GHashTable * attr_set,
     /* [previous][next][first][last][top][bottom][index][help] */
 508                     cib_t * cib, pe_working_set_t * data_set)
 509 {
 510     int rc = pcmk_ok;
 511     xmlNode *xml_top = NULL;
 512     xmlNode *ticket_state_xml = NULL;
 513     gboolean found = FALSE;
 514 
 515     GListPtr list_iter = NULL;
 516     GHashTableIter hash_iter;
 517 
 518     char *key = NULL;
 519     char *value = NULL;
 520 
 521     ticket_t *ticket = NULL;
 522     gboolean is_granting = FALSE;
 523 
 524     for(list_iter = attr_delete; list_iter; list_iter = list_iter->next) {
 525         const char *key = (const char *)list_iter->data;
 526         delete_ticket_state_attr_legacy(ticket_id, set_name, attr_id, key, cib);
 527     }
 528 
 529     rc = find_ticket_state(cib, ticket_id, &ticket_state_xml);
 530     if (rc == pcmk_ok) {
 531         crm_debug("Found a match state for ticket: id=%s", ticket_id);
 532         xml_top = ticket_state_xml;
 533         found = TRUE;
 534 
 535     } else if (rc != -ENXIO) {
 536         return rc;
 537 
 538     } else if (g_hash_table_size(attr_set) == 0){
 539         return pcmk_ok;
 540 
 541     } else {
 542         xmlNode *xml_obj = NULL;
 543 
 544         xml_top = create_xml_node(NULL, XML_CIB_TAG_STATUS);
 545         xml_obj = create_xml_node(xml_top, XML_CIB_TAG_TICKETS);
 546         ticket_state_xml = create_xml_node(xml_obj, XML_CIB_TAG_TICKET_STATE);
 547         crm_xml_add(ticket_state_xml, XML_ATTR_ID, ticket_id);
 548     }
 549 
 550     for(list_iter = attr_delete; list_iter; list_iter = list_iter->next) {
 551         const char *key = (const char *)list_iter->data;
 552         xml_remove_prop(ticket_state_xml, key);
 553     }
 554 
 555     ticket = find_ticket(ticket_id, data_set);
 556 
 557     g_hash_table_iter_init(&hash_iter, attr_set);
 558     while (g_hash_table_iter_next(&hash_iter, (gpointer *) & key, (gpointer *) & value)) {
 559         crm_xml_add(ticket_state_xml, key, value);
 560 
 561         if (safe_str_eq(key, "granted")
 562             && (ticket == NULL || ticket->granted == FALSE)
 563             && crm_is_true(value)) {
 564 
 565             char *now = crm_itoa(time(NULL));
 566 
 567             is_granting = TRUE;
 568             crm_xml_add(ticket_state_xml, "last-granted", now);
 569             free(now);
 570         }
 571     }
 572 
 573     if (found && g_list_length(attr_delete)) {
 574         crm_log_xml_debug(xml_top, "Replace");
 575         rc = cib->cmds->replace(cib, XML_CIB_TAG_STATUS, ticket_state_xml, cib_options);
 576 
 577     } else {
 578         crm_log_xml_debug(xml_top, "Update");
 579         rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, xml_top, cib_options);
 580     }
 581 
 582     free_xml(xml_top);
 583 
 584     if (rc != pcmk_ok) {
 585         return rc;
 586     }
 587 
 588     g_hash_table_iter_init(&hash_iter, attr_set);
 589     while (g_hash_table_iter_next(&hash_iter, (gpointer *) & key, (gpointer *) & value)) {
 590         delete_ticket_state_attr_legacy(ticket_id, set_name, attr_id, key, cib);
 591     }
 592 
 593     if (is_granting == TRUE) {
 594         delete_ticket_state_attr_legacy(ticket_id, set_name, attr_id, "last-granted", cib);
 595     }
 596 
 597     return rc;
 598 }
 599 
 600 static int
 601 delete_ticket_state(const char *ticket_id, cib_t * cib)
     /* [previous][next][first][last][top][bottom][index][help] */
 602 {
 603     xmlNode *ticket_state_xml = NULL;
 604 
 605     int rc = pcmk_ok;
 606 
 607     rc = find_ticket_state(cib, ticket_id, &ticket_state_xml);
 608 
 609     if (rc == -ENXIO) {
 610         return pcmk_ok;
 611 
 612     } else if (rc != pcmk_ok) {
 613         return rc;
 614     }
 615 
 616     crm_log_xml_debug(ticket_state_xml, "Delete");
 617 
 618     rc = cib->cmds->delete(cib, XML_CIB_TAG_STATUS, ticket_state_xml, cib_options);
 619 
 620     if (rc == pcmk_ok) {
 621         fprintf(stdout, "Cleaned up %s\n", ticket_id);
 622     }
 623 
 624     free_xml(ticket_state_xml);
 625     return rc;
 626 }
 627 
 628 /* *INDENT-OFF* */
 629 static struct crm_option long_options[] = {
 630     /* Top-level Options */
 631     {"help",    0, 0, '?', "\t\tThis text"},
 632     {"version", 0, 0, '$', "\t\tVersion information"  },
 633     {"verbose", 0, 0, 'V', "\t\tIncrease debug output"},
 634     {"quiet",   0, 0, 'Q', "\t\tPrint only the value on stdout\n"},
 635 
 636     {"ticket",  1, 0, 't', "\tTicket ID" },
 637 
 638     {"-spacer-",   1, 0, '-', "\nQueries:"},
 639     {"info",       0, 0, 'l', "\t\tDisplay the information of ticket(s)"},
 640     {"details",    0, 0, 'L', "\t\tDisplay the details of ticket(s)"},
 641     {"raw",        0, 0, 'w', "\t\tDisplay the IDs of ticket(s)"},
 642     {"query-xml",  0, 0, 'q', "\tQuery the XML of ticket(s)"},
 643     {"constraints",0, 0, 'c', "\tDisplay the rsc_ticket constraints that apply to ticket(s)"},
 644 
 645     {"-spacer-",   1, 0, '-', "\nCommands:"},
 646     {"grant",      0, 0, 'g', "\t\tGrant a ticket to this cluster site"},
 647     {"revoke",     0, 0, 'r', "\t\tRevoke a ticket from this cluster site"},
 648     {"standby",    0, 0, 's', "\t\tTell this cluster site this ticket is standby"},
 649     {"activate",   0, 0, 'a', "\tTell this cluster site this ticket is active"},
 650     
 651     {"-spacer-",   1, 0, '-', "\nAdvanced Commands:"},
 652     {"get-attr",   1, 0, 'G', "\tDisplay the named attribute for a ticket"},
 653     {"set-attr",   1, 0, 'S', "\tSet the named attribtue for a ticket"},
 654     {"delete-attr",1, 0, 'D', "\tDelete the named attribute for a ticket"},
 655     {"cleanup",    0, 0, 'C', "\t\tDelete all state of a ticket at this cluster site"},
 656     
 657     {"-spacer-",   1, 0, '-', "\nAdditional Options:"},
 658     {"attr-value", 1, 0, 'v', "\tAttribute value to use with -S"},
 659     {"default",    1, 0, 'd', "\t(Advanced) The default attribute value to display if none is found. For use with -G"},
 660     {"force",      0, 0, 'f', "\t\t(Advanced) Force the action to be performed"},
 661     {"xml-file",   1, 0, 'x', NULL, 1},\
 662 
 663     /* legacy options */
 664     {"set-name",   1, 0, 'n', "\t(Advanced) ID of the instance_attributes object to change"},
 665     {"nvpair",     1, 0, 'i', "\t(Advanced) ID of the nvpair object to change/delete"},
 666     
 667     {"-spacer-",        1, 0, '-', "\nExamples:", pcmk_option_paragraph},
 668     {"-spacer-",        1, 0, '-', "Display the info of tickets:", pcmk_option_paragraph},
 669     {"-spacer-",        1, 0, '-', " crm_ticket --info", pcmk_option_example},
 670     {"-spacer-",        1, 0, '-', "Display the detailed info of tickets:", pcmk_option_paragraph},
 671     {"-spacer-",        1, 0, '-', " crm_ticket --details", pcmk_option_example},
 672     {"-spacer-",        1, 0, '-', "Display the XML of 'ticketA':", pcmk_option_paragraph},
 673     {"-spacer-",        1, 0, '-', " crm_ticket --ticket ticketA --query-xml", pcmk_option_example},
 674     {"-spacer-",        1, 0, '-', "Display the rsc_ticket constraints that apply to 'ticketA':", pcmk_option_paragraph},
 675     {"-spacer-",        1, 0, '-', " crm_ticket --ticket ticketA --constraints", pcmk_option_example},
 676 
 677     {"-spacer-",        1, 0, '-', "Grant 'ticketA' to this cluster site:", pcmk_option_paragraph},
 678     {"-spacer-",        1, 0, '-', " crm_ticket --ticket ticketA --grant", pcmk_option_example},
 679     {"-spacer-",        1, 0, '-', "Revoke 'ticketA' from this cluster site:", pcmk_option_paragraph},
 680     {"-spacer-",        1, 0, '-', " crm_ticket --ticket ticketA --revoke", pcmk_option_example},
 681     {"-spacer-",        1, 0, '-', "Make 'ticketA' standby:", pcmk_option_paragraph},
 682     {"-spacer-",        1, 0, '-', "The cluster site will treat a granted 'ticketA' as 'standby'."},
 683     {"-spacer-",        1, 0, '-', "The dependent resources will be stopped or demoted gracefully without triggering loss-policies", pcmk_option_paragraph},
 684     {"-spacer-",        1, 0, '-', " crm_ticket --ticket ticketA --standby", pcmk_option_example},
 685     {"-spacer-",        1, 0, '-', "Activate 'ticketA' from being standby:", pcmk_option_paragraph},
 686     {"-spacer-",        1, 0, '-', " crm_ticket --ticket ticketA --activate", pcmk_option_example},
 687 
 688     {"-spacer-",        1, 0, '-', "Get the value of the 'granted' attribute for 'ticketA':", pcmk_option_paragraph},
 689     {"-spacer-",        1, 0, '-', " crm_ticket --ticket ticketA --get-attr granted", pcmk_option_example},
 690     {"-spacer-",        1, 0, '-', "Set the value of the 'standby' attribute for 'ticketA':", pcmk_option_paragraph},
 691     {"-spacer-",        1, 0, '-', " crm_ticket --ticket ticketA --set-attr standby --attr-value true", pcmk_option_example},
 692     {"-spacer-",        1, 0, '-', "Delete the 'granted' attribute for 'ticketA':", pcmk_option_paragraph},
 693     {"-spacer-",        1, 0, '-', " crm_ticket --ticket ticketA --delete-attr granted", pcmk_option_example},
 694     {"-spacer-",        1, 0, '-', "Erase the operation history of 'ticketA' at this cluster site:", pcmk_option_paragraph},
 695     {"-spacer-",        1, 0, '-', "The cluster site will 'forget' the existing ticket state.", pcmk_option_paragraph},
 696     {"-spacer-",        1, 0, '-', " crm_ticket --ticket ticketA --cleanup", pcmk_option_example},
 697     
 698     {0, 0, 0, 0}
 699 };
 700 /* *INDENT-ON* */
 701 
 702 int
 703 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 704 {
 705     pe_working_set_t data_set;
 706     xmlNode *cib_xml_copy = NULL;
 707     xmlNode *cib_constraints = NULL;
 708 
 709     cib_t *cib_conn = NULL;
 710     int rc = pcmk_ok;
 711 
 712     int option_index = 0;
 713     int argerr = 0;
 714     int flag;
 715     guint modified = 0;
 716 
 717     GListPtr attr_delete = NULL;
 718     GHashTable *attr_set = crm_str_table_new();
 719 
 720     crm_log_init(NULL, LOG_CRIT, FALSE, FALSE, argc, argv, FALSE);
 721     crm_set_options(NULL, "(query|command) [options]", long_options,
 722                     "Perform tasks related to cluster tickets.\nAllows ticket attributes to be queried, modified and deleted.\n");
 723 
 724     if (argc < 2) {
 725         crm_help('?', EX_USAGE);
 726     }
 727 
 728     while (1) {
 729         flag = crm_get_option(argc, argv, &option_index);
 730         if (flag == -1)
 731             break;
 732 
 733         switch (flag) {
 734             case 'V':
 735                 crm_bump_log_level(argc, argv);
 736                 break;
 737             case '$':
 738             case '?':
 739                 crm_help(flag, EX_OK);
 740                 break;
 741             case 'Q':
 742                 BE_QUIET = TRUE;
 743                 break;
 744             case 't':
 745                 ticket_id = optarg;
 746                 break;
 747             case 'l':
 748             case 'L':
 749             case 'w':
 750             case 'q':
 751             case 'c':
 752                 ticket_cmd = flag;
 753                 break;
 754             case 'g':
 755                 g_hash_table_insert(attr_set, strdup("granted"), strdup("true"));
 756                 modified++;
 757                 break;
 758             case 'r':
 759                 g_hash_table_insert(attr_set, strdup("granted"), strdup("false"));
 760                 modified++;
 761                 break;
 762             case 's':
 763                 g_hash_table_insert(attr_set, strdup("standby"), strdup("true"));
 764                 modified++;
 765                 break;
 766             case 'a':
 767                 g_hash_table_insert(attr_set, strdup("standby"), strdup("false"));
 768                 modified++;
 769                 break;
 770             case 'G':
 771                 get_attr_name = optarg;
 772                 ticket_cmd = flag;
 773                 break;
 774             case 'S':
 775                 attr_name = optarg;
 776                 if (attr_name && attr_value) {
 777                     g_hash_table_insert(attr_set, strdup(attr_name), strdup(attr_value));
 778                     attr_name = NULL;
 779                     attr_value = NULL;
 780                     modified++;
 781                 }
 782                 break;
 783             case 'D':
 784                 attr_delete = g_list_append(attr_delete, optarg);
 785                 modified++;
 786                 break;
 787             case 'C':
 788                 ticket_cmd = flag;
 789                 break;
 790             case 'v':
 791                 attr_value = optarg;
 792                 if (attr_name && attr_value) {
 793                     g_hash_table_insert(attr_set, strdup(attr_name), strdup(attr_value));
 794                     attr_name = NULL;
 795                     attr_value = NULL;
 796                     modified++;
 797                 }
 798                 break;
 799             case 'd':
 800                 attr_default = optarg;
 801                 break;
 802             case 'f':
 803                 do_force = TRUE;
 804                 break;
 805             case 'x':
 806                 xml_file = strdup(optarg);
 807                 break;
 808             case 'n':
 809                 set_name = optarg;
 810                 break;
 811             case 'i':
 812                 attr_id = optarg;
 813                 break;
 814 
 815             default:
 816                 CMD_ERR("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag);
 817                 ++argerr;
 818                 break;
 819         }
 820     }
 821 
 822     if (optind < argc && argv[optind] != NULL) {
 823         CMD_ERR("non-option ARGV-elements: ");
 824         while (optind < argc && argv[optind] != NULL) {
 825             CMD_ERR("%s ", argv[optind++]);
 826             ++argerr;
 827         }
 828         CMD_ERR("\n");
 829     }
 830 
 831     if (optind > argc) {
 832         ++argerr;
 833     }
 834 
 835     if (argerr) {
 836         crm_help('?', EX_USAGE);
 837     }
 838 
 839     set_working_set_defaults(&data_set);
 840 
 841     cib_conn = cib_new();
 842     if (cib_conn == NULL) {
 843         rc = -ENOTCONN;
 844         CMD_ERR("Error initiating the connection to the CIB service: %s\n", pcmk_strerror(rc));
 845         return rc;
 846     }
 847 
 848     rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
 849     if (rc != pcmk_ok) {
 850         CMD_ERR("Error signing on to the CIB service: %s\n", pcmk_strerror(rc));
 851         return rc;
 852     }
 853 
 854     if (xml_file != NULL) {
 855         cib_xml_copy = filename2xml(xml_file);
 856 
 857     } else {
 858         rc = cib_conn->cmds->query(cib_conn, NULL, &cib_xml_copy, cib_scope_local | cib_sync_call);
 859     }
 860 
 861     if (rc != pcmk_ok) {
 862         goto bail;
 863 
 864     } else if (cli_config_update(&cib_xml_copy, NULL, FALSE) == FALSE) {
 865         rc = -ENOKEY;
 866         goto bail;
 867     }
 868 
 869     data_set.input = cib_xml_copy;
 870     data_set.now = crm_time_new(NULL);
 871 
 872     cluster_status(&data_set);
 873 
 874     /* For recording the tickets that are referenced in rsc_ticket constraints
 875      * but have never been granted yet. */
 876     cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, data_set.input);
 877     unpack_constraints(cib_constraints, &data_set);
 878 
 879     if (ticket_cmd == 'l' || ticket_cmd == 'L' || ticket_cmd == 'w') {
 880         gboolean raw = FALSE;
 881         gboolean details = FALSE;
 882 
 883         if (ticket_cmd == 'L') {
 884             details = TRUE;
 885         } else if (ticket_cmd == 'w') {
 886             raw = TRUE;
 887         }
 888 
 889         if (ticket_id) {
 890             ticket_t *ticket = find_ticket(ticket_id, &data_set);
 891 
 892             if (ticket == NULL) {
 893                 rc = -ENXIO;
 894                 goto bail;
 895             }
 896             rc = print_ticket(ticket, raw, details);
 897 
 898         } else {
 899             rc = print_ticket_list(&data_set, raw, details);
 900         }
 901 
 902     } else if (ticket_cmd == 'q') {
 903         rc = dump_ticket_xml(cib_conn, ticket_id);
 904 
 905     } else if (ticket_cmd == 'c') {
 906         rc = dump_constraints(cib_conn, ticket_id);
 907 
 908     } else if (ticket_cmd == 'G') {
 909         const char *value = NULL;
 910 
 911         if (ticket_id == NULL) {
 912             CMD_ERR("Must supply a ticket id with -t\n");
 913             rc = -ENXIO;
 914             goto bail;
 915         }
 916 
 917         rc = get_ticket_state_attr(ticket_id, get_attr_name, &value, &data_set);
 918         if (rc == pcmk_ok) {
 919             fprintf(stdout, "%s\n", value);
 920         } else if (rc == -ENXIO && attr_default) {
 921             fprintf(stdout, "%s\n", attr_default);
 922             rc = pcmk_ok;
 923         }
 924 
 925     } else if (ticket_cmd == 'C') {
 926         if (ticket_id == NULL) {
 927             CMD_ERR("Must supply a ticket id with -t\n");
 928             rc = -ENXIO;
 929             goto bail;
 930         }
 931 
 932         if (do_force == FALSE) {
 933             ticket_t *ticket = NULL;
 934 
 935             ticket = find_ticket(ticket_id, &data_set);
 936             if (ticket == NULL) {
 937                 rc = -ENXIO;
 938                 goto bail;
 939             }
 940 
 941             if (ticket->granted) {
 942                 ticket_warning(ticket_id, "revoke");
 943                 rc = -EPERM;
 944                 goto bail;
 945             }
 946         }
 947 
 948         rc = delete_ticket_state(ticket_id, cib_conn);
 949 
 950     } else if (modified) {
 951         if (ticket_id == NULL) {
 952             CMD_ERR("Must supply a ticket id with -t\n");
 953             rc = -ENXIO;
 954             goto bail;
 955         }
 956 
 957         if (attr_value
 958             && (attr_name == NULL || strlen(attr_name) == 0)) {
 959             CMD_ERR("You need to supply an attribute name with the -S command for -v %s\n", attr_value);
 960             rc = -EINVAL;
 961             goto bail;
 962         }
 963 
 964         if (attr_name
 965             && (attr_value == NULL || strlen(attr_value) == 0)) {
 966             CMD_ERR("You need to supply a value with the -v option for -S %s\n", attr_name);
 967             rc = -EINVAL;
 968             goto bail;
 969         }
 970 
 971         if (allow_modification(ticket_id, attr_delete, attr_set) == FALSE) {
 972             rc = -EPERM;
 973             goto bail;
 974         }
 975 
 976         rc = modify_ticket_state(ticket_id, attr_delete, attr_set, cib_conn, &data_set);
 977         
 978         if (rc != pcmk_ok) {
 979             goto bail;
 980         }
 981 
 982     } else if (ticket_cmd == 'S') {
 983         if (ticket_id == NULL) {
 984             CMD_ERR("Must supply a ticket id with -t\n");
 985             rc = -ENXIO;
 986             goto bail;
 987         }
 988 
 989         if (attr_name == NULL || strlen(attr_name) == 0) {
 990             CMD_ERR("You need to supply a command\n");
 991             rc = -EINVAL;
 992             goto bail;
 993         }
 994 
 995         if (attr_value == NULL || strlen(attr_value) == 0) {
 996             CMD_ERR("You need to supply a value with the -v option for -S %s\n", attr_name);
 997             rc = -EINVAL;
 998             goto bail;
 999         }
1000 
1001     } else {
1002         CMD_ERR("Unknown command: %c\n", ticket_cmd);
1003     }
1004 
1005   bail:
1006     if (attr_set) {
1007         g_hash_table_destroy(attr_set);
1008     }
1009     attr_set = NULL;
1010 
1011     if (attr_delete) {
1012         g_list_free(attr_delete);
1013     }
1014     attr_delete = NULL;
1015 
1016     if (cib_conn != NULL) {
1017         cleanup_alloc_calculations(&data_set);
1018         cib_conn->cmds->signoff(cib_conn);
1019         cib_delete(cib_conn);
1020     }
1021 
1022     if (rc == -pcmk_err_no_quorum) {
1023         CMD_ERR("Error performing operation: %s\n", pcmk_strerror(rc));
1024         CMD_ERR("Try using -f\n");
1025 
1026     } else if (rc != pcmk_ok) {
1027         CMD_ERR("Error performing operation: %s\n", pcmk_strerror(rc));
1028     }
1029 
1030     return crm_exit(rc);
1031 }

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