root/tools/crm_ticket.c

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

DEFINITIONS

This source file includes following definitions.
  1. attr_value_cb
  2. command_cb
  3. delete_attr_cb
  4. get_attr_cb
  5. grant_standby_cb
  6. set_attr_cb
  7. ticket_grant_warning
  8. ticket_revoke_warning
  9. build_arg_context
  10. main

   1 /*
   2  * Copyright 2012-2024 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_internal.h>
  11 
  12 #include <sys/param.h>
  13 
  14 #include <crm/crm.h>
  15 
  16 #include <stdio.h>
  17 #include <sys/types.h>
  18 #include <unistd.h>
  19 
  20 #include <stdlib.h>
  21 #include <errno.h>
  22 #include <fcntl.h>
  23 #include <libgen.h>
  24 
  25 #include <crm/common/xml.h>
  26 #include <crm/common/ipc.h>
  27 #include <crm/common/cmdline_internal.h>
  28 
  29 #include <crm/cib.h>
  30 #include <crm/cib/internal.h>
  31 #include <crm/pengine/rules.h>
  32 #include <crm/pengine/status.h>
  33 #include <crm/pengine/internal.h>
  34 
  35 #include <pacemaker-internal.h>
  36 
  37 GError *error = NULL;
  38 
  39 #define SUMMARY "Perform tasks related to cluster tickets\n\n" \
  40                 "Allows ticket attributes to be queried, modified and deleted."
  41 
  42 struct {
  43     gchar *attr_default;
  44     gchar *attr_id;
  45     char *attr_name;
  46     char *attr_value;
  47     gboolean force;
  48     char *get_attr_name;
  49     gboolean quiet;
  50     gchar *set_name;
  51     char ticket_cmd;
  52     gchar *ticket_id;
  53     gchar *xml_file;
  54 } options = {
  55     .ticket_cmd = 'S'
  56 };
  57 
  58 GList *attr_delete;
  59 GHashTable *attr_set;
  60 bool modified = false;
  61 int cib_options = cib_sync_call;
  62 static pcmk__output_t *out = NULL;
  63 
  64 #define INDENT "                               "
  65 
  66 static pcmk__supported_format_t formats[] = {
  67     PCMK__SUPPORTED_FORMAT_NONE,
  68     PCMK__SUPPORTED_FORMAT_TEXT,
  69     PCMK__SUPPORTED_FORMAT_XML,
  70     { NULL, NULL, NULL }
  71 };
  72 
  73 static gboolean
  74 attr_value_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
     /* [previous][next][first][last][top][bottom][index][help] */
  75     pcmk__str_update(&options.attr_value, optarg);
  76 
  77     if (!options.attr_name || !options.attr_value) {
  78         return TRUE;
  79     }
  80 
  81     pcmk__insert_dup(attr_set, options.attr_name, options.attr_value);
  82     pcmk__str_update(&options.attr_name, NULL);
  83     pcmk__str_update(&options.attr_value, NULL);
  84 
  85     modified = true;
  86 
  87     return TRUE;
  88 }
  89 
  90 static gboolean
  91 command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
     /* [previous][next][first][last][top][bottom][index][help] */
  92     if (pcmk__str_any_of(option_name, "--info", "-l", NULL)) {
  93         options.ticket_cmd = 'l';
  94     } else if (pcmk__str_any_of(option_name, "--details", "-L", NULL)) {
  95         options.ticket_cmd = 'L';
  96     } else if (pcmk__str_any_of(option_name, "--raw", "-w", NULL)) {
  97         options.ticket_cmd = 'w';
  98     } else if (pcmk__str_any_of(option_name, "--query-xml", "-q", NULL)) {
  99         options.ticket_cmd = 'q';
 100     } else if (pcmk__str_any_of(option_name, "--constraints", "-c", NULL)) {
 101         options.ticket_cmd = 'c';
 102     } else if (pcmk__str_any_of(option_name, "--cleanup", "-C", NULL)) {
 103         options.ticket_cmd = 'C';
 104     }
 105 
 106     return TRUE;
 107 }
 108 
 109 static gboolean
 110 delete_attr_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
     /* [previous][next][first][last][top][bottom][index][help] */
 111     attr_delete = g_list_append(attr_delete, strdup(optarg));
 112     modified = true;
 113     return TRUE;
 114 }
 115 
 116 static gboolean
 117 get_attr_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
     /* [previous][next][first][last][top][bottom][index][help] */
 118     pcmk__str_update(&options.get_attr_name, optarg);
 119     options.ticket_cmd = 'G';
 120     return TRUE;
 121 }
 122 
 123 static gboolean
 124 grant_standby_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
     /* [previous][next][first][last][top][bottom][index][help] */
 125     if (pcmk__str_any_of(option_name, "--grant", "-g", NULL)) {
 126         pcmk__insert_dup(attr_set, PCMK__XA_GRANTED, PCMK_VALUE_TRUE);
 127         modified = true;
 128     } else if (pcmk__str_any_of(option_name, "--revoke", "-r", NULL)) {
 129         pcmk__insert_dup(attr_set, PCMK__XA_GRANTED, PCMK_VALUE_FALSE);
 130         modified = true;
 131     } else if (pcmk__str_any_of(option_name, "--standby", "-s", NULL)) {
 132         pcmk__insert_dup(attr_set, PCMK_XA_STANDBY, PCMK_VALUE_TRUE);
 133         modified = true;
 134     } else if (pcmk__str_any_of(option_name, "--activate", "-a", NULL)) {
 135         pcmk__insert_dup(attr_set, PCMK_XA_STANDBY, PCMK_VALUE_FALSE);
 136         modified = true;
 137     }
 138 
 139     return TRUE;
 140 }
 141 
 142 static gboolean
 143 set_attr_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
     /* [previous][next][first][last][top][bottom][index][help] */
 144     pcmk__str_update(&options.attr_name, optarg);
 145 
 146     if (!options.attr_name || !options.attr_value) {
 147         return TRUE;
 148     }
 149 
 150     pcmk__insert_dup(attr_set, options.attr_name, options.attr_value);
 151     pcmk__str_update(&options.attr_name, NULL);
 152     pcmk__str_update(&options.attr_value, NULL);
 153 
 154     modified = true;
 155 
 156     return TRUE;
 157 }
 158 
 159 static GOptionEntry query_entries[] = {
 160     { "info", 'l', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
 161       "Display the information of ticket(s)",
 162       NULL },
 163 
 164     { "details", 'L', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
 165       "Display the details of ticket(s)",
 166       NULL },
 167 
 168     { "raw", 'w', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
 169       "Display the IDs of ticket(s)",
 170       NULL },
 171 
 172     { "query-xml", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
 173       "Query the XML of ticket(s)",
 174       NULL },
 175 
 176     { "constraints", 'c', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
 177       "Display the " PCMK_XE_RSC_TICKET " constraints that apply to ticket(s)",
 178       NULL },
 179 
 180     { NULL }
 181 };
 182 
 183 static GOptionEntry command_entries[] = {
 184     { "grant", 'g', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, grant_standby_cb,
 185       "Grant a ticket to this cluster site",
 186       NULL },
 187 
 188     { "revoke", 'r', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, grant_standby_cb,
 189       "Revoke a ticket from this cluster site",
 190       NULL },
 191 
 192     { "standby", 's', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, grant_standby_cb,
 193       "Tell this cluster site this ticket is standby",
 194       NULL },
 195 
 196     { "activate", 'a', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, grant_standby_cb,
 197       "Tell this cluster site this ticket is active",
 198       NULL },
 199 
 200     { NULL }
 201 };
 202 
 203 static GOptionEntry advanced_entries[] = {
 204     { "get-attr", 'G', 0, G_OPTION_ARG_CALLBACK, get_attr_cb,
 205       "Display the named attribute for a ticket",
 206       "ATTRIBUTE" },
 207 
 208     { "set-attr", 'S', 0, G_OPTION_ARG_CALLBACK, set_attr_cb,
 209       "Set the named attribute for a ticket",
 210       "ATTRIBUTE" },
 211 
 212     { "delete-attr", 'D', 0, G_OPTION_ARG_CALLBACK, delete_attr_cb,
 213       "Delete the named attribute for a ticket",
 214       "ATTRIBUTE" },
 215 
 216     { "cleanup", 'C', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
 217       "Delete all state of a ticket at this cluster site",
 218       NULL },
 219 
 220     { NULL}
 221 };
 222 
 223 static GOptionEntry addl_entries[] = {
 224     { "attr-value", 'v', 0, G_OPTION_ARG_CALLBACK, attr_value_cb,
 225       "Attribute value to use with -S",
 226       "VALUE" },
 227 
 228     { "default", 'd', 0, G_OPTION_ARG_STRING, &options.attr_default,
 229       "(Advanced) Default attribute value to display if none is found\n"
 230       INDENT "(for use with -G)",
 231       "VALUE" },
 232 
 233     { "force", 'f', 0, G_OPTION_ARG_NONE, &options.force,
 234       "(Advanced) Force the action to be performed",
 235       NULL },
 236 
 237     { "ticket", 't', 0, G_OPTION_ARG_STRING, &options.ticket_id,
 238       "Ticket ID",
 239       "ID" },
 240 
 241     { "xml-file", 'x', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &options.xml_file,
 242       NULL,
 243       NULL },
 244 
 245     { NULL }
 246 };
 247 
 248 static GOptionEntry deprecated_entries[] = {
 249     { "set-name", 'n', 0, G_OPTION_ARG_STRING, &options.set_name,
 250       "(Advanced) ID of the " PCMK_XE_INSTANCE_ATTRIBUTES " object to change",
 251       "ID" },
 252 
 253     { "nvpair", 'i', 0, G_OPTION_ARG_STRING, &options.attr_id,
 254       "(Advanced) ID of the nvpair object to change/delete",
 255       "ID" },
 256 
 257     { "quiet", 'Q', 0, G_OPTION_ARG_NONE, &options.quiet,
 258       "Print only the value on stdout",
 259       NULL },
 260 
 261     { NULL }
 262 };
 263 
 264 static void
 265 ticket_grant_warning(gchar *ticket_id)
     /* [previous][next][first][last][top][bottom][index][help] */
 266 {
 267     out->err(out, "This command cannot help you verify whether '%s' has "
 268                   "been already granted elsewhere.\n"
 269                   "If you really want to grant '%s' to this site now, and "
 270                   "you know what you are doing,\n"
 271                   "please specify --force.",
 272                   ticket_id, ticket_id);
 273 }
 274 
 275 static void
 276 ticket_revoke_warning(gchar *ticket_id)
     /* [previous][next][first][last][top][bottom][index][help] */
 277 {
 278     out->err(out, "Revoking '%s' can trigger the specified '" PCMK_XA_LOSS_POLICY
 279               "'(s) relating to '%s'.\n\n"
 280               "You can check that with:\n"
 281               "crm_ticket --ticket %s --constraints\n\n"
 282               "Otherwise before revoking '%s', you may want to make '%s'"
 283               "standby with:\n"
 284               "crm_ticket --ticket %s --standby\n\n"
 285               "If you really want to revoke '%s' from this site now, and "
 286               "you know what you are doing,\n"
 287               "please specify --force.",
 288               ticket_id, ticket_id, ticket_id, ticket_id, ticket_id,
 289               ticket_id, ticket_id);
 290 }
 291 
 292 static GOptionContext *
 293 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group)
     /* [previous][next][first][last][top][bottom][index][help] */
 294 {
 295     GOptionContext *context = NULL;
 296 
 297     const char *description = "Examples:\n\n"
 298                               "Display the info of tickets:\n\n"
 299                               "\tcrm_ticket --info\n\n"
 300                               "Display the detailed info of tickets:\n\n"
 301                               "\tcrm_ticket --details\n\n"
 302                               "Display the XML of 'ticketA':\n\n"
 303                               "\tcrm_ticket --ticket ticketA --query-xml\n\n"
 304                               "Display the " PCMK_XE_RSC_TICKET " constraints that apply to 'ticketA':\n\n"
 305                               "\tcrm_ticket --ticket ticketA --constraints\n\n"
 306                               "Grant 'ticketA' to this cluster site:\n\n"
 307                               "\tcrm_ticket --ticket ticketA --grant\n\n"
 308                               "Revoke 'ticketA' from this cluster site:\n\n"
 309                               "\tcrm_ticket --ticket ticketA --revoke\n\n"
 310                               "Make 'ticketA' standby (the cluster site will treat a granted\n"
 311                               "'ticketA' as 'standby', and the dependent resources will be\n"
 312                               "stopped or demoted gracefully without triggering loss-policies):\n\n"
 313                               "\tcrm_ticket --ticket ticketA --standby\n\n"
 314                               "Activate 'ticketA' from being standby:\n\n"
 315                               "\tcrm_ticket --ticket ticketA --activate\n\n"
 316                               "Get the value of the 'granted' attribute for 'ticketA':\n\n"
 317                               "\tcrm_ticket --ticket ticketA --get-attr granted\n\n"
 318                               "Set the value of the 'standby' attribute for 'ticketA':\n\n"
 319                               "\tcrm_ticket --ticket ticketA --set-attr standby --attr-value true\n\n"
 320                               "Delete the 'granted' attribute for 'ticketA':\n\n"
 321                               "\tcrm_ticket --ticket ticketA --delete-attr granted\n\n"
 322                               "Erase the operation history of 'ticketA' at this cluster site,\n"
 323                               "causing the cluster site to 'forget' the existing ticket state:\n\n"
 324                               "\tcrm_ticket --ticket ticketA --cleanup\n\n";
 325 
 326     context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
 327     g_option_context_set_description(context, description);
 328 
 329     pcmk__add_arg_group(context, "queries", "Queries:",
 330                         "Show queries", query_entries);
 331     pcmk__add_arg_group(context, "commands", "Commands:",
 332                         "Show command options", command_entries);
 333     pcmk__add_arg_group(context, "advanced", "Advanced Options:",
 334                         "Show advanced options", advanced_entries);
 335     pcmk__add_arg_group(context, "additional", "Additional Options:",
 336                         "Show additional options", addl_entries);
 337     pcmk__add_arg_group(context, "deprecated", "Deprecated Options:",
 338                         "Show deprecated options", deprecated_entries);
 339 
 340     return context;
 341 }
 342 
 343 int
 344 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 345 {
 346     pcmk_scheduler_t *scheduler = NULL;
 347     xmlNode *cib_xml_copy = NULL;
 348 
 349     cib_t *cib_conn = NULL;
 350     crm_exit_t exit_code = CRM_EX_OK;
 351     int rc = pcmk_rc_ok;
 352 
 353     GOptionGroup *output_group = NULL;
 354     pcmk__common_args_t *args = NULL;
 355     GOptionContext *context = NULL;
 356     gchar **processed_args = NULL;
 357 
 358     attr_set = pcmk__strkey_table(free, free);
 359     attr_delete = NULL;
 360 
 361     args = pcmk__new_common_args(SUMMARY);
 362     context = build_arg_context(args, &output_group);
 363     processed_args = pcmk__cmdline_preproc(argv, "dintvxCDGS");
 364 
 365     pcmk__register_formats(output_group, formats);
 366     if (!g_option_context_parse_strv(context, &processed_args, &error)) {
 367         exit_code = CRM_EX_USAGE;
 368         goto done;
 369     }
 370 
 371     pcmk__cli_init_logging("crm_ticket", args->verbosity);
 372 
 373     rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
 374     if (rc != pcmk_rc_ok) {
 375         exit_code = pcmk_rc2exitc(rc);
 376         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 377                     "Error creating output format %s: %s", args->output_ty,
 378                     pcmk_rc_str(rc));
 379         goto done;
 380     }
 381 
 382     pe__register_messages(out);
 383     pcmk__register_lib_messages(out);
 384 
 385     if (args->version) {
 386         out->version(out, false);
 387         goto done;
 388     }
 389 
 390     scheduler = pe_new_working_set();
 391     if (scheduler == NULL) {
 392         rc = errno;
 393         exit_code = pcmk_rc2exitc(rc);
 394         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 395                     "Could not allocate scheduler data: %s", pcmk_rc_str(rc));
 396         goto done;
 397     }
 398     pcmk__set_scheduler_flags(scheduler,
 399                               pcmk_sched_no_counts|pcmk_sched_no_compat);
 400 
 401     cib_conn = cib_new();
 402     if (cib_conn == NULL) {
 403         exit_code = CRM_EX_DISCONNECT;
 404         g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Could not connect to the CIB manager");
 405         goto done;
 406     }
 407 
 408     rc = cib__signon_attempts(cib_conn, crm_system_name, cib_command, 5);
 409     rc = pcmk_legacy2rc(rc);
 410 
 411     if (rc != pcmk_rc_ok) {
 412         exit_code = pcmk_rc2exitc(rc);
 413         g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Could not connect to the CIB: %s",
 414                     pcmk_rc_str(rc));
 415         goto done;
 416     }
 417 
 418     if (options.xml_file != NULL) {
 419         cib_xml_copy = pcmk__xml_read(options.xml_file);
 420 
 421     } else {
 422         rc = cib_conn->cmds->query(cib_conn, NULL, &cib_xml_copy, cib_scope_local | cib_sync_call);
 423         rc = pcmk_legacy2rc(rc);
 424 
 425         if (rc != pcmk_rc_ok) {
 426             exit_code = pcmk_rc2exitc(rc);
 427             g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Could not get local CIB: %s",
 428                         pcmk_rc_str(rc));
 429             goto done;
 430         }
 431     }
 432 
 433     rc = pcmk__update_configured_schema(&cib_xml_copy, false);
 434     if (rc != pcmk_rc_ok) {
 435         exit_code = pcmk_rc2exitc(rc);
 436         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 437                     "Could not update local CIB to latest schema version");
 438         goto done;
 439     }
 440 
 441     scheduler->input = cib_xml_copy;
 442     scheduler->now = crm_time_new(NULL);
 443 
 444     cluster_status(scheduler);
 445 
 446     /* For recording the tickets that are referenced in PCMK_XE_RSC_TICKET
 447      * constraints but have never been granted yet.
 448      */
 449     pcmk__unpack_constraints(scheduler);
 450 
 451     if (options.ticket_cmd == 'l' || options.ticket_cmd == 'L' || options.ticket_cmd == 'w') {
 452         bool raw = false;
 453         bool details = false;
 454 
 455         if (options.ticket_cmd == 'L') {
 456             details = true;
 457         } else if (options.ticket_cmd == 'w') {
 458             raw = true;
 459         }
 460 
 461         rc = pcmk__ticket_info(out, scheduler, options.ticket_id, details, raw);
 462         exit_code = pcmk_rc2exitc(rc);
 463 
 464         if (rc == ENXIO) {
 465             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 466                         "No such ticket '%s'", options.ticket_id);
 467         } else if (rc != pcmk_rc_ok) {
 468             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 469                         "Could not get ticket info: %s", pcmk_rc_str(rc));
 470         }
 471 
 472     } else if (options.ticket_cmd == 'q') {
 473         rc = pcmk__ticket_state(out, cib_conn, options.ticket_id);
 474 
 475         if (rc != pcmk_rc_ok && rc != pcmk_rc_duplicate_id) {
 476             exit_code = pcmk_rc2exitc(rc);
 477             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 478                         "Could not query ticket XML: %s", pcmk_rc_str(rc));
 479         } else {
 480             exit_code = CRM_EX_OK;
 481         }
 482 
 483     } else if (options.ticket_cmd == 'c') {
 484         rc = pcmk__ticket_constraints(out, cib_conn, options.ticket_id);
 485         exit_code = pcmk_rc2exitc(rc);
 486 
 487         if (rc != pcmk_rc_ok) {
 488             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 489                         "Could not show ticket constraints: %s", pcmk_rc_str(rc));
 490         }
 491 
 492     } else if (options.ticket_cmd == 'G') {
 493         if (options.ticket_id == NULL) {
 494             exit_code = CRM_EX_NOSUCH;
 495             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 496                         "Must supply ticket ID with -t");
 497             goto done;
 498         }
 499 
 500         rc = pcmk__ticket_get_attr(out, scheduler, options.ticket_id,
 501                                    options.get_attr_name, options.attr_default);
 502         exit_code = pcmk_rc2exitc(rc);
 503 
 504     } else if (options.ticket_cmd == 'C') {
 505         if (options.ticket_id == NULL) {
 506             exit_code = CRM_EX_USAGE;
 507             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 508                         "Must supply ticket ID with -t");
 509             goto done;
 510         }
 511 
 512         rc = pcmk__ticket_delete(out, cib_conn, scheduler, options.ticket_id,
 513                                  options.force);
 514         exit_code = pcmk_rc2exitc(rc);
 515 
 516         switch (rc) {
 517             case ENXIO:
 518                 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 519                             "No such ticket '%s'", options.ticket_id);
 520                 break;
 521 
 522             case EACCES:
 523                 ticket_revoke_warning(options.ticket_id);
 524                 break;
 525 
 526             case pcmk_rc_ok:
 527             case pcmk_rc_duplicate_id:
 528                 break;
 529 
 530             default:
 531                 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 532                             "Could not clean up ticket: %s", pcmk_rc_str(rc));
 533                 break;
 534         }
 535 
 536     } else if (modified) {
 537         if (options.ticket_id == NULL) {
 538             exit_code = CRM_EX_USAGE;
 539             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 540                         "Must supply ticket ID with -t");
 541             goto done;
 542         }
 543 
 544         if (options.attr_value
 545             && (pcmk__str_empty(options.attr_name))) {
 546             exit_code = CRM_EX_USAGE;
 547             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 548                         "Must supply attribute name with -S for -v %s", options.attr_value);
 549             goto done;
 550         }
 551 
 552         if (options.attr_name
 553             && (pcmk__str_empty(options.attr_value))) {
 554             exit_code = CRM_EX_USAGE;
 555             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 556                         "Must supply attribute value with -v for -S %s", options.attr_value);
 557             goto done;
 558         }
 559 
 560         if (attr_delete != NULL) {
 561             rc = pcmk__ticket_remove_attr(out, cib_conn, scheduler, options.ticket_id,
 562                                           attr_delete, options.force);
 563 
 564             if (rc == EACCES) {
 565                 ticket_revoke_warning(options.ticket_id);
 566                 exit_code = pcmk_rc2exitc(rc);
 567                 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 568                             "Ticket modification not allowed without --force");
 569             }
 570         } else {
 571             rc = pcmk__ticket_set_attr(out, cib_conn, scheduler, options.ticket_id,
 572                                        attr_set, options.force);
 573 
 574             if (rc == EACCES) {
 575                 const char *value = NULL;
 576 
 577                 value = g_hash_table_lookup(attr_set, PCMK__XA_GRANTED);
 578                 if (crm_is_true(value)) {
 579                     ticket_grant_warning(options.ticket_id);
 580                 } else {
 581                     ticket_revoke_warning(options.ticket_id);
 582                 }
 583 
 584                 exit_code = pcmk_rc2exitc(rc);
 585                 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 586                             "Ticket modification not allowed without --force");
 587             }
 588         }
 589 
 590         exit_code = pcmk_rc2exitc(rc);
 591 
 592         if (rc != pcmk_rc_ok && error == NULL) {
 593             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 594                         "Could not modify ticket: %s", pcmk_rc_str(rc));
 595         }
 596 
 597     } else if (options.ticket_cmd == 'S') {
 598         /* Correct usage was handled in the "if (modified)" block above, so
 599          * this is just for reporting usage errors
 600          */
 601 
 602         if (pcmk__str_empty(options.attr_name)) {
 603             // We only get here if ticket_cmd was left as default
 604             exit_code = CRM_EX_USAGE;
 605             g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Must supply a command");
 606             goto done;
 607         }
 608 
 609         if (options.ticket_id == NULL) {
 610             exit_code = CRM_EX_USAGE;
 611             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 612                         "Must supply ticket ID with -t");
 613             goto done;
 614         }
 615 
 616         if (pcmk__str_empty(options.attr_value)) {
 617             exit_code = CRM_EX_USAGE;
 618             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 619                         "Must supply value with -v for -S %s", options.attr_name);
 620             goto done;
 621         }
 622 
 623     } else {
 624         exit_code = CRM_EX_USAGE;
 625         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 626                     "Unknown command: %c", options.ticket_cmd);
 627     }
 628 
 629  done:
 630     if (attr_set) {
 631         g_hash_table_destroy(attr_set);
 632     }
 633     attr_set = NULL;
 634 
 635     if (attr_delete) {
 636         g_list_free_full(attr_delete, free);
 637     }
 638     attr_delete = NULL;
 639 
 640     pe_free_working_set(scheduler);
 641     scheduler = NULL;
 642 
 643     cib__clean_up_connection(&cib_conn);
 644 
 645     g_strfreev(processed_args);
 646     pcmk__free_arg_context(context);
 647     g_free(options.attr_default);
 648     g_free(options.attr_id);
 649     free(options.attr_name);
 650     free(options.attr_value);
 651     free(options.get_attr_name);
 652     g_free(options.set_name);
 653     g_free(options.ticket_id);
 654     g_free(options.xml_file);
 655 
 656     pcmk__output_and_clear_error(&error, out);
 657 
 658     if (out != NULL) {
 659         out->finish(out, exit_code, true, NULL);
 660         pcmk__output_free(out);
 661     }
 662 
 663     pcmk__unregister_formats();
 664     crm_exit(exit_code);
 665 }

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