diff options
Diffstat (limited to 'tools/crm_ticket.c')
-rw-r--r-- | tools/crm_ticket.c | 614 |
1 files changed, 134 insertions, 480 deletions
diff --git a/tools/crm_ticket.c b/tools/crm_ticket.c index d95b581..2faa74e 100644 --- a/tools/crm_ticket.c +++ b/tools/crm_ticket.c @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the Pacemaker project contributors + * Copyright 2012-2024 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -22,7 +22,6 @@ #include <fcntl.h> #include <libgen.h> -#include <crm/msg_xml.h> #include <crm/common/xml.h> #include <crm/common/ipc.h> #include <crm/common/cmdline_internal.h> @@ -60,9 +59,17 @@ GList *attr_delete; GHashTable *attr_set; bool modified = false; int cib_options = cib_sync_call; +static pcmk__output_t *out = NULL; #define INDENT " " +static pcmk__supported_format_t formats[] = { + PCMK__SUPPORTED_FORMAT_NONE, + PCMK__SUPPORTED_FORMAT_TEXT, + PCMK__SUPPORTED_FORMAT_XML, + { NULL, NULL, NULL } +}; + static gboolean attr_value_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) { pcmk__str_update(&options.attr_value, optarg); @@ -71,7 +78,7 @@ attr_value_cb(const gchar *option_name, const gchar *optarg, gpointer data, GErr return TRUE; } - g_hash_table_insert(attr_set, strdup(options.attr_name), strdup(options.attr_value)); + pcmk__insert_dup(attr_set, options.attr_name, options.attr_value); pcmk__str_update(&options.attr_name, NULL); pcmk__str_update(&options.attr_value, NULL); @@ -116,16 +123,16 @@ get_attr_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError static gboolean grant_standby_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) { if (pcmk__str_any_of(option_name, "--grant", "-g", NULL)) { - g_hash_table_insert(attr_set, strdup("granted"), strdup("true")); + pcmk__insert_dup(attr_set, PCMK__XA_GRANTED, PCMK_VALUE_TRUE); modified = true; } else if (pcmk__str_any_of(option_name, "--revoke", "-r", NULL)) { - g_hash_table_insert(attr_set, strdup("granted"), strdup("false")); + pcmk__insert_dup(attr_set, PCMK__XA_GRANTED, PCMK_VALUE_FALSE); modified = true; } else if (pcmk__str_any_of(option_name, "--standby", "-s", NULL)) { - g_hash_table_insert(attr_set, strdup("standby"), strdup("true")); + pcmk__insert_dup(attr_set, PCMK_XA_STANDBY, PCMK_VALUE_TRUE); modified = true; } else if (pcmk__str_any_of(option_name, "--activate", "-a", NULL)) { - g_hash_table_insert(attr_set, strdup("standby"), strdup("false")); + pcmk__insert_dup(attr_set, PCMK_XA_STANDBY, PCMK_VALUE_FALSE); modified = true; } @@ -140,7 +147,7 @@ set_attr_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError return TRUE; } - g_hash_table_insert(attr_set, strdup(options.attr_name), strdup(options.attr_value)); + pcmk__insert_dup(attr_set, options.attr_name, options.attr_value); pcmk__str_update(&options.attr_name, NULL); pcmk__str_update(&options.attr_value, NULL); @@ -167,7 +174,7 @@ static GOptionEntry query_entries[] = { NULL }, { "constraints", 'c', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb, - "Display the rsc_ticket constraints that apply to ticket(s)", + "Display the " PCMK_XE_RSC_TICKET " constraints that apply to ticket(s)", NULL }, { NULL } @@ -240,7 +247,7 @@ static GOptionEntry addl_entries[] = { static GOptionEntry deprecated_entries[] = { { "set-name", 'n', 0, G_OPTION_ARG_STRING, &options.set_name, - "(Advanced) ID of the instance_attributes object to change", + "(Advanced) ID of the " PCMK_XE_INSTANCE_ATTRIBUTES " object to change", "ID" }, { "nvpair", 'i', 0, G_OPTION_ARG_STRING, &options.attr_id, @@ -254,420 +261,37 @@ static GOptionEntry deprecated_entries[] = { { NULL } }; -static pcmk_ticket_t * -find_ticket(gchar *ticket_id, pcmk_scheduler_t *scheduler) -{ - return g_hash_table_lookup(scheduler->tickets, ticket_id); -} - static void -print_date(time_t time) +ticket_grant_warning(gchar *ticket_id) { - int lpc = 0; - char date_str[26]; - - asctime_r(localtime(&time), date_str); - for (; lpc < 26; lpc++) { - if (date_str[lpc] == '\n') { - date_str[lpc] = 0; - } - } - fprintf(stdout, "'%s'", date_str); + out->err(out, "This command cannot help you verify whether '%s' has " + "been already granted elsewhere.\n" + "If you really want to grant '%s' to this site now, and " + "you know what you are doing,\n" + "please specify --force.", + ticket_id, ticket_id); } static void -print_ticket(pcmk_ticket_t *ticket, bool raw, bool details) -{ - if (raw) { - fprintf(stdout, "%s\n", ticket->id); - return; - } - - fprintf(stdout, "%s\t%s %s", - ticket->id, ticket->granted ? "granted" : "revoked", - ticket->standby ? "[standby]" : " "); - - if (details && g_hash_table_size(ticket->state) > 0) { - GHashTableIter iter; - const char *name = NULL; - const char *value = NULL; - int lpc = 0; - - fprintf(stdout, " ("); - - g_hash_table_iter_init(&iter, ticket->state); - while (g_hash_table_iter_next(&iter, (void **)&name, (void **)&value)) { - if (lpc > 0) { - fprintf(stdout, ", "); - } - fprintf(stdout, "%s=", name); - if (pcmk__str_any_of(name, "last-granted", "expires", NULL)) { - long long time_ll; - - pcmk__scan_ll(value, &time_ll, 0); - print_date((time_t) time_ll); - } else { - fprintf(stdout, "%s", value); - } - lpc++; - } - - fprintf(stdout, ")\n"); - - } else { - if (ticket->last_granted > -1) { - fprintf(stdout, " last-granted="); - print_date(ticket->last_granted); - } - fprintf(stdout, "\n"); - } - - return; -} - -static void -print_ticket_list(pcmk_scheduler_t *scheduler, bool raw, bool details) -{ - GHashTableIter iter; - pcmk_ticket_t *ticket = NULL; - - g_hash_table_iter_init(&iter, scheduler->tickets); - - while (g_hash_table_iter_next(&iter, NULL, (void **)&ticket)) { - print_ticket(ticket, raw, details); - } -} - -static int -find_ticket_state(cib_t * the_cib, gchar *ticket_id, xmlNode ** ticket_state_xml) -{ - int rc = pcmk_rc_ok; - xmlNode *xml_search = NULL; - - GString *xpath = NULL; - - CRM_ASSERT(ticket_state_xml != NULL); - *ticket_state_xml = NULL; - - xpath = g_string_sized_new(1024); - g_string_append(xpath, - "/" XML_TAG_CIB "/" XML_CIB_TAG_STATUS - "/" XML_CIB_TAG_TICKETS); - - if (ticket_id != NULL) { - pcmk__g_strcat(xpath, - "/" XML_CIB_TAG_TICKET_STATE - "[@" XML_ATTR_ID "=\"", ticket_id, "\"]", NULL); - } - - rc = the_cib->cmds->query(the_cib, (const char *) xpath->str, &xml_search, - cib_sync_call | cib_scope_local | cib_xpath); - rc = pcmk_legacy2rc(rc); - g_string_free(xpath, TRUE); - - if (rc != pcmk_rc_ok) { - return rc; - } - - crm_log_xml_debug(xml_search, "Match"); - if (xml_search->children != NULL) { - if (ticket_id) { - fprintf(stdout, "Multiple ticket_states match ticket_id=%s\n", ticket_id); - } - *ticket_state_xml = xml_search; - } else { - *ticket_state_xml = xml_search; - } - return rc; -} - -static int -find_ticket_constraints(cib_t * the_cib, gchar *ticket_id, xmlNode ** ticket_cons_xml) -{ - int rc = pcmk_rc_ok; - xmlNode *xml_search = NULL; - - GString *xpath = NULL; - const char *xpath_base = NULL; - - CRM_ASSERT(ticket_cons_xml != NULL); - *ticket_cons_xml = NULL; - - xpath_base = pcmk_cib_xpath_for(XML_CIB_TAG_CONSTRAINTS); - if (xpath_base == NULL) { - crm_err(XML_CIB_TAG_CONSTRAINTS " CIB element not known (bug?)"); - return -ENOMSG; - } - - xpath = g_string_sized_new(1024); - pcmk__g_strcat(xpath, xpath_base, "/" XML_CONS_TAG_RSC_TICKET, NULL); - - if (ticket_id != NULL) { - pcmk__g_strcat(xpath, - "[@" XML_TICKET_ATTR_TICKET "=\"", ticket_id, "\"]", - NULL); - } - - rc = the_cib->cmds->query(the_cib, (const char *) xpath->str, &xml_search, - cib_sync_call | cib_scope_local | cib_xpath); - rc = pcmk_legacy2rc(rc); - g_string_free(xpath, TRUE); - - if (rc != pcmk_rc_ok) { - return rc; - } - - crm_log_xml_debug(xml_search, "Match"); - *ticket_cons_xml = xml_search; - - return rc; -} - -static int -dump_ticket_xml(cib_t * the_cib, gchar *ticket_id) -{ - int rc = pcmk_rc_ok; - xmlNode *state_xml = NULL; - - rc = find_ticket_state(the_cib, ticket_id, &state_xml); - - if (state_xml == NULL) { - return rc; - } - - fprintf(stdout, "State XML:\n"); - if (state_xml) { - char *state_xml_str = NULL; - - state_xml_str = dump_xml_formatted(state_xml); - fprintf(stdout, "\n%s", state_xml_str); - free_xml(state_xml); - free(state_xml_str); - } - - return rc; -} - -static int -dump_constraints(cib_t * the_cib, gchar *ticket_id) -{ - int rc = pcmk_rc_ok; - xmlNode *cons_xml = NULL; - char *cons_xml_str = NULL; - - rc = find_ticket_constraints(the_cib, ticket_id, &cons_xml); - - if (cons_xml == NULL) { - return rc; - } - - cons_xml_str = dump_xml_formatted(cons_xml); - fprintf(stdout, "Constraints XML:\n\n%s", cons_xml_str); - free_xml(cons_xml); - free(cons_xml_str); - - return rc; -} - -static int -get_ticket_state_attr(gchar *ticket_id, const char *attr_name, const char **attr_value, - pcmk_scheduler_t *scheduler) -{ - pcmk_ticket_t *ticket = NULL; - - CRM_ASSERT(attr_value != NULL); - *attr_value = NULL; - - ticket = g_hash_table_lookup(scheduler->tickets, ticket_id); - if (ticket == NULL) { - return ENXIO; - } - - *attr_value = g_hash_table_lookup(ticket->state, attr_name); - if (*attr_value == NULL) { - return ENXIO; - } - - return pcmk_rc_ok; -} - -static void -ticket_warning(gchar *ticket_id, const char *action) -{ - GString *warning = g_string_sized_new(1024); - const char *word = NULL; - - CRM_ASSERT(action != NULL); - - if (strcmp(action, "grant") == 0) { - pcmk__g_strcat(warning, - "This command cannot help you verify whether '", - ticket_id, - "' has been already granted elsewhere.\n", NULL); - word = "to"; - - } else { - pcmk__g_strcat(warning, - "Revoking '", ticket_id, "' can trigger the specified " - "'loss-policy'(s) relating to '", ticket_id, "'.\n\n" - "You can check that with:\n" - "crm_ticket --ticket ", ticket_id, " --constraints\n\n" - "Otherwise before revoking '", ticket_id, "', " - "you may want to make '", ticket_id, "' " - "standby with:\n" - "crm_ticket --ticket ", ticket_id, " --standby\n\n", - NULL); - word = "from"; - } - - pcmk__g_strcat(warning, - "If you really want to ", action, " '", ticket_id, "' ", - word, " this site now, and you know what you are doing,\n" - "please specify --force.", NULL); - - fprintf(stdout, "%s\n", (const char *) warning->str); - - g_string_free(warning, TRUE); -} - -static bool -allow_modification(gchar *ticket_id) +ticket_revoke_warning(gchar *ticket_id) { - const char *value = NULL; - GList *list_iter = NULL; - - if (options.force) { - return true; - } - - if (g_hash_table_lookup_extended(attr_set, "granted", NULL, (gpointer *) & value)) { - if (crm_is_true(value)) { - ticket_warning(ticket_id, "grant"); - return false; - - } else { - ticket_warning(ticket_id, "revoke"); - return false; - } - } - - for(list_iter = attr_delete; list_iter; list_iter = list_iter->next) { - const char *key = (const char *)list_iter->data; - - if (pcmk__str_eq(key, "granted", pcmk__str_casei)) { - ticket_warning(ticket_id, "revoke"); - return false; - } - } - - return true; -} - -static int -modify_ticket_state(gchar *ticket_id, cib_t *cib, pcmk_scheduler_t *scheduler) -{ - int rc = pcmk_rc_ok; - xmlNode *xml_top = NULL; - xmlNode *ticket_state_xml = NULL; - bool found = false; - - GList *list_iter = NULL; - GHashTableIter hash_iter; - - char *key = NULL; - char *value = NULL; - - pcmk_ticket_t *ticket = NULL; - - rc = find_ticket_state(cib, ticket_id, &ticket_state_xml); - if (rc == pcmk_rc_ok) { - crm_debug("Found a match state for ticket: id=%s", ticket_id); - xml_top = ticket_state_xml; - found = true; - - } else if (rc != ENXIO) { - return rc; - - } else if (g_hash_table_size(attr_set) == 0){ - return pcmk_rc_ok; - - } else { - xmlNode *xml_obj = NULL; - - xml_top = create_xml_node(NULL, XML_CIB_TAG_STATUS); - xml_obj = create_xml_node(xml_top, XML_CIB_TAG_TICKETS); - ticket_state_xml = create_xml_node(xml_obj, XML_CIB_TAG_TICKET_STATE); - crm_xml_add(ticket_state_xml, XML_ATTR_ID, ticket_id); - } - - for(list_iter = attr_delete; list_iter; list_iter = list_iter->next) { - const char *key = (const char *)list_iter->data; - xml_remove_prop(ticket_state_xml, key); - } - - ticket = find_ticket(ticket_id, scheduler); - - g_hash_table_iter_init(&hash_iter, attr_set); - while (g_hash_table_iter_next(&hash_iter, (gpointer *) & key, (gpointer *) & value)) { - crm_xml_add(ticket_state_xml, key, value); - - if (pcmk__str_eq(key, "granted", pcmk__str_casei) - && (ticket == NULL || ticket->granted == FALSE) - && crm_is_true(value)) { - - char *now = pcmk__ttoa(time(NULL)); - - crm_xml_add(ticket_state_xml, "last-granted", now); - free(now); - } - } - - if (found && (attr_delete != NULL)) { - crm_log_xml_debug(xml_top, "Replace"); - rc = cib->cmds->replace(cib, XML_CIB_TAG_STATUS, ticket_state_xml, cib_options); - rc = pcmk_legacy2rc(rc); - - } else { - crm_log_xml_debug(xml_top, "Update"); - rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, xml_top, cib_options); - rc = pcmk_legacy2rc(rc); - } - - free_xml(xml_top); - return rc; -} - -static int -delete_ticket_state(gchar *ticket_id, cib_t * cib) -{ - xmlNode *ticket_state_xml = NULL; - - int rc = pcmk_rc_ok; - - rc = find_ticket_state(cib, ticket_id, &ticket_state_xml); - - if (rc == ENXIO) { - return pcmk_rc_ok; - - } else if (rc != pcmk_rc_ok) { - return rc; - } - - crm_log_xml_debug(ticket_state_xml, "Delete"); - - rc = cib->cmds->remove(cib, XML_CIB_TAG_STATUS, ticket_state_xml, cib_options); - rc = pcmk_legacy2rc(rc); - - if (rc == pcmk_rc_ok) { - fprintf(stdout, "Cleaned up %s\n", ticket_id); - } - - free_xml(ticket_state_xml); - return rc; + out->err(out, "Revoking '%s' can trigger the specified '" PCMK_XA_LOSS_POLICY + "'(s) relating to '%s'.\n\n" + "You can check that with:\n" + "crm_ticket --ticket %s --constraints\n\n" + "Otherwise before revoking '%s', you may want to make '%s'" + "standby with:\n" + "crm_ticket --ticket %s --standby\n\n" + "If you really want to revoke '%s' from this site now, and " + "you know what you are doing,\n" + "please specify --force.", + ticket_id, ticket_id, ticket_id, ticket_id, ticket_id, + ticket_id, ticket_id); } static GOptionContext * -build_arg_context(pcmk__common_args_t *args) { +build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) +{ GOptionContext *context = NULL; const char *description = "Examples:\n\n" @@ -677,7 +301,7 @@ build_arg_context(pcmk__common_args_t *args) { "\tcrm_ticket --details\n\n" "Display the XML of 'ticketA':\n\n" "\tcrm_ticket --ticket ticketA --query-xml\n\n" - "Display the rsc_ticket constraints that apply to 'ticketA':\n\n" + "Display the " PCMK_XE_RSC_TICKET " constraints that apply to 'ticketA':\n\n" "\tcrm_ticket --ticket ticketA --constraints\n\n" "Grant 'ticketA' to this cluster site:\n\n" "\tcrm_ticket --ticket ticketA --grant\n\n" @@ -699,7 +323,7 @@ build_arg_context(pcmk__common_args_t *args) { "causing the cluster site to 'forget' the existing ticket state:\n\n" "\tcrm_ticket --ticket ticketA --cleanup\n\n"; - context = pcmk__build_arg_context(args, NULL, NULL, NULL); + context = pcmk__build_arg_context(args, "text (default), xml", group, NULL); g_option_context_set_description(context, description); pcmk__add_arg_group(context, "queries", "Queries:", @@ -726,6 +350,7 @@ main(int argc, char **argv) crm_exit_t exit_code = CRM_EX_OK; int rc = pcmk_rc_ok; + GOptionGroup *output_group = NULL; pcmk__common_args_t *args = NULL; GOptionContext *context = NULL; gchar **processed_args = NULL; @@ -734,9 +359,10 @@ main(int argc, char **argv) attr_delete = NULL; args = pcmk__new_common_args(SUMMARY); - context = build_arg_context(args); + context = build_arg_context(args, &output_group); processed_args = pcmk__cmdline_preproc(argv, "dintvxCDGS"); + pcmk__register_formats(output_group, formats); if (!g_option_context_parse_strv(context, &processed_args, &error)) { exit_code = CRM_EX_USAGE; goto done; @@ -744,11 +370,21 @@ main(int argc, char **argv) pcmk__cli_init_logging("crm_ticket", args->verbosity); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + if (rc != pcmk_rc_ok) { + exit_code = pcmk_rc2exitc(rc); + g_set_error(&error, PCMK__EXITC_ERROR, exit_code, + "Error creating output format %s: %s", args->output_ty, + pcmk_rc_str(rc)); + goto done; + } + + pe__register_messages(out); + pcmk__register_lib_messages(out); + if (args->version) { - g_strfreev(processed_args); - pcmk__free_arg_context(context); - /* FIXME: When crm_ticket is converted to use formatted output, this can go. */ - pcmk__cli_help('v'); + out->version(out, false); + goto done; } scheduler = pe_new_working_set(); @@ -759,7 +395,7 @@ main(int argc, char **argv) "Could not allocate scheduler data: %s", pcmk_rc_str(rc)); goto done; } - pe__set_working_set_flags(scheduler, + pcmk__set_scheduler_flags(scheduler, pcmk_sched_no_counts|pcmk_sched_no_compat); cib_conn = cib_new(); @@ -780,7 +416,7 @@ main(int argc, char **argv) } if (options.xml_file != NULL) { - cib_xml_copy = filename2xml(options.xml_file); + cib_xml_copy = pcmk__xml_read(options.xml_file); } else { rc = cib_conn->cmds->query(cib_conn, NULL, &cib_xml_copy, cib_scope_local | cib_sync_call); @@ -794,8 +430,9 @@ main(int argc, char **argv) } } - if (!cli_config_update(&cib_xml_copy, NULL, FALSE)) { - exit_code = CRM_EX_CONFIG; + rc = pcmk_update_configured_schema(&cib_xml_copy, false); + if (rc != pcmk_rc_ok) { + exit_code = pcmk_rc2exitc(rc); g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Could not update local CIB to latest schema version"); goto done; @@ -806,8 +443,9 @@ main(int argc, char **argv) cluster_status(scheduler); - /* For recording the tickets that are referenced in rsc_ticket constraints - * but have never been granted yet. */ + /* For recording the tickets that are referenced in PCMK_XE_RSC_TICKET + * constraints but have never been granted yet. + */ pcmk__unpack_constraints(scheduler); if (options.ticket_cmd == 'l' || options.ticket_cmd == 'L' || options.ticket_cmd == 'w') { @@ -820,32 +458,30 @@ main(int argc, char **argv) raw = true; } - if (options.ticket_id) { - pcmk_ticket_t *ticket = find_ticket(options.ticket_id, scheduler); - - if (ticket == NULL) { - exit_code = CRM_EX_NOSUCH; - g_set_error(&error, PCMK__EXITC_ERROR, exit_code, - "No such ticket '%s'", options.ticket_id); - goto done; - } - print_ticket(ticket, raw, details); + rc = pcmk__ticket_info(out, scheduler, options.ticket_id, details, raw); + exit_code = pcmk_rc2exitc(rc); - } else { - print_ticket_list(scheduler, raw, details); + if (rc == ENXIO) { + g_set_error(&error, PCMK__EXITC_ERROR, exit_code, + "No such ticket '%s'", options.ticket_id); + } else if (rc != pcmk_rc_ok) { + g_set_error(&error, PCMK__EXITC_ERROR, exit_code, + "Could not get ticket info: %s", pcmk_rc_str(rc)); } } else if (options.ticket_cmd == 'q') { - rc = dump_ticket_xml(cib_conn, options.ticket_id); - exit_code = pcmk_rc2exitc(rc); + rc = pcmk__ticket_state(out, cib_conn, options.ticket_id); - if (rc != pcmk_rc_ok) { + if (rc != pcmk_rc_ok && rc != pcmk_rc_duplicate_id) { + exit_code = pcmk_rc2exitc(rc); g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Could not query ticket XML: %s", pcmk_rc_str(rc)); + } else { + exit_code = CRM_EX_OK; } } else if (options.ticket_cmd == 'c') { - rc = dump_constraints(cib_conn, options.ticket_id); + rc = pcmk__ticket_constraints(out, cib_conn, options.ticket_id); exit_code = pcmk_rc2exitc(rc); if (rc != pcmk_rc_ok) { @@ -854,8 +490,6 @@ main(int argc, char **argv) } } else if (options.ticket_cmd == 'G') { - const char *value = NULL; - if (options.ticket_id == NULL) { exit_code = CRM_EX_NOSUCH; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, @@ -863,14 +497,8 @@ main(int argc, char **argv) goto done; } - rc = get_ticket_state_attr(options.ticket_id, options.get_attr_name, - &value, scheduler); - if (rc == pcmk_rc_ok) { - fprintf(stdout, "%s\n", value); - } else if (rc == ENXIO && options.attr_default) { - fprintf(stdout, "%s\n", options.attr_default); - rc = pcmk_rc_ok; - } + rc = pcmk__ticket_get_attr(out, scheduler, options.ticket_id, + options.get_attr_name, options.attr_default); exit_code = pcmk_rc2exitc(rc); } else if (options.ticket_cmd == 'C') { @@ -881,30 +509,28 @@ main(int argc, char **argv) goto done; } - if (options.force == FALSE) { - pcmk_ticket_t *ticket = NULL; + rc = pcmk__ticket_delete(out, cib_conn, scheduler, options.ticket_id, + options.force); + exit_code = pcmk_rc2exitc(rc); - ticket = find_ticket(options.ticket_id, scheduler); - if (ticket == NULL) { - exit_code = CRM_EX_NOSUCH; + switch (rc) { + case ENXIO: g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "No such ticket '%s'", options.ticket_id); - goto done; - } + break; - if (ticket->granted) { - ticket_warning(options.ticket_id, "revoke"); - exit_code = CRM_EX_INSUFFICIENT_PRIV; - goto done; - } - } + case EACCES: + ticket_revoke_warning(options.ticket_id); + break; - rc = delete_ticket_state(options.ticket_id, cib_conn); - exit_code = pcmk_rc2exitc(rc); + case pcmk_rc_ok: + case pcmk_rc_duplicate_id: + break; - if (rc != pcmk_rc_ok) { - g_set_error(&error, PCMK__EXITC_ERROR, exit_code, - "Could not clean up ticket: %s", pcmk_rc_str(rc)); + default: + g_set_error(&error, PCMK__EXITC_ERROR, exit_code, + "Could not clean up ticket: %s", pcmk_rc_str(rc)); + break; } } else if (modified) { @@ -931,17 +557,39 @@ main(int argc, char **argv) goto done; } - if (!allow_modification(options.ticket_id)) { - exit_code = CRM_EX_INSUFFICIENT_PRIV; - g_set_error(&error, PCMK__EXITC_ERROR, exit_code, - "Ticket modification not allowed"); - goto done; + if (attr_delete != NULL) { + rc = pcmk__ticket_remove_attr(out, cib_conn, scheduler, options.ticket_id, + attr_delete, options.force); + + if (rc == EACCES) { + ticket_revoke_warning(options.ticket_id); + exit_code = pcmk_rc2exitc(rc); + g_set_error(&error, PCMK__EXITC_ERROR, exit_code, + "Ticket modification not allowed without --force"); + } + } else { + rc = pcmk__ticket_set_attr(out, cib_conn, scheduler, options.ticket_id, + attr_set, options.force); + + if (rc == EACCES) { + const char *value = NULL; + + value = g_hash_table_lookup(attr_set, PCMK__XA_GRANTED); + if (crm_is_true(value)) { + ticket_grant_warning(options.ticket_id); + } else { + ticket_revoke_warning(options.ticket_id); + } + + exit_code = pcmk_rc2exitc(rc); + g_set_error(&error, PCMK__EXITC_ERROR, exit_code, + "Ticket modification not allowed without --force"); + } } - rc = modify_ticket_state(options.ticket_id, cib_conn, scheduler); exit_code = pcmk_rc2exitc(rc); - if (rc != pcmk_rc_ok) { + if (rc != pcmk_rc_ok && error == NULL) { g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Could not modify ticket: %s", pcmk_rc_str(rc)); } @@ -1005,7 +653,13 @@ main(int argc, char **argv) g_free(options.ticket_id); g_free(options.xml_file); - pcmk__output_and_clear_error(&error, NULL); + pcmk__output_and_clear_error(&error, out); + + if (out != NULL) { + out->finish(out, exit_code, true, NULL); + pcmk__output_free(out); + } + pcmk__unregister_formats(); crm_exit(exit_code); } |