Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F1842174
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
24 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/tools/crm_ticket.c b/tools/crm_ticket.c
index 7cb3701c1e..d9319d56ee 100644
--- a/tools/crm_ticket.c
+++ b/tools/crm_ticket.c
@@ -1,667 +1,725 @@
/*
* Copyright 2012-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <crm/common/xml.h>
#include <crm/common/ipc.h>
#include <crm/common/cmdline_internal.h>
#include <crm/cib.h>
#include <crm/cib/internal.h>
#include <crm/pengine/rules.h>
#include <crm/pengine/status.h>
#include <crm/pengine/internal.h>
#include <pacemaker-internal.h>
GError *error = NULL;
#define SUMMARY "Perform tasks related to cluster tickets\n\n" \
"Allows ticket attributes to be queried, modified and deleted."
struct {
gchar *attr_default;
gchar *attr_id;
char *attr_name;
char *attr_value;
gboolean force;
char *get_attr_name;
gboolean quiet;
gchar *set_name;
char ticket_cmd;
gchar *ticket_id;
gchar *xml_file;
} options = {
.ticket_cmd = 'S'
};
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);
if (!options.attr_name || !options.attr_value) {
return TRUE;
}
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);
modified = true;
return TRUE;
}
static gboolean
command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
if (pcmk__str_any_of(option_name, "--info", "-l", NULL)) {
options.ticket_cmd = 'l';
} else if (pcmk__str_any_of(option_name, "--details", "-L", NULL)) {
options.ticket_cmd = 'L';
} else if (pcmk__str_any_of(option_name, "--raw", "-w", NULL)) {
options.ticket_cmd = 'w';
} else if (pcmk__str_any_of(option_name, "--query-xml", "-q", NULL)) {
options.ticket_cmd = 'q';
} else if (pcmk__str_any_of(option_name, "--constraints", "-c", NULL)) {
options.ticket_cmd = 'c';
} else if (pcmk__str_any_of(option_name, "--cleanup", "-C", NULL)) {
options.ticket_cmd = 'C';
}
return TRUE;
}
static gboolean
delete_attr_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
attr_delete = g_list_append(attr_delete, strdup(optarg));
modified = true;
return TRUE;
}
static gboolean
get_attr_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
pcmk__str_update(&options.get_attr_name, optarg);
options.ticket_cmd = 'G';
return TRUE;
}
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)) {
pcmk__insert_dup(attr_set, PCMK__XA_GRANTED, PCMK_VALUE_TRUE);
modified = true;
} else if (pcmk__str_any_of(option_name, "--revoke", "-r", NULL)) {
pcmk__insert_dup(attr_set, PCMK__XA_GRANTED, PCMK_VALUE_FALSE);
modified = true;
} else if (pcmk__str_any_of(option_name, "--standby", "-s", NULL)) {
pcmk__insert_dup(attr_set, PCMK_XA_STANDBY, PCMK_VALUE_TRUE);
modified = true;
} else if (pcmk__str_any_of(option_name, "--activate", "-a", NULL)) {
pcmk__insert_dup(attr_set, PCMK_XA_STANDBY, PCMK_VALUE_FALSE);
modified = true;
}
return TRUE;
}
static gboolean
set_attr_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
pcmk__str_update(&options.attr_name, optarg);
if (!options.attr_name || !options.attr_value) {
return TRUE;
}
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);
modified = true;
return TRUE;
}
static GOptionEntry query_entries[] = {
{ "info", 'l', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Display the information of ticket(s)",
NULL },
{ "details", 'L', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Display the details of ticket(s)",
NULL },
{ "raw", 'w', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Display the IDs of ticket(s)",
NULL },
{ "query-xml", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Query the XML of ticket(s)",
NULL },
{ "constraints", 'c', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Display the " PCMK_XE_RSC_TICKET " constraints that apply to ticket(s)",
NULL },
{ NULL }
};
static GOptionEntry command_entries[] = {
{ "grant", 'g', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, grant_standby_cb,
"Grant a ticket to this cluster site",
NULL },
{ "revoke", 'r', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, grant_standby_cb,
"Revoke a ticket from this cluster site",
NULL },
{ "standby", 's', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, grant_standby_cb,
"Tell this cluster site this ticket is standby",
NULL },
{ "activate", 'a', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, grant_standby_cb,
"Tell this cluster site this ticket is active",
NULL },
{ NULL }
};
static GOptionEntry advanced_entries[] = {
{ "get-attr", 'G', 0, G_OPTION_ARG_CALLBACK, get_attr_cb,
"Display the named attribute for a ticket",
"ATTRIBUTE" },
{ "set-attr", 'S', 0, G_OPTION_ARG_CALLBACK, set_attr_cb,
"Set the named attribute for a ticket",
"ATTRIBUTE" },
{ "delete-attr", 'D', 0, G_OPTION_ARG_CALLBACK, delete_attr_cb,
"Delete the named attribute for a ticket",
"ATTRIBUTE" },
{ "cleanup", 'C', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Delete all state of a ticket at this cluster site",
NULL },
{ NULL}
};
static GOptionEntry addl_entries[] = {
{ "attr-value", 'v', 0, G_OPTION_ARG_CALLBACK, attr_value_cb,
"Attribute value to use with -S",
"VALUE" },
{ "default", 'd', 0, G_OPTION_ARG_STRING, &options.attr_default,
"(Advanced) Default attribute value to display if none is found\n"
INDENT "(for use with -G)",
"VALUE" },
{ "force", 'f', 0, G_OPTION_ARG_NONE, &options.force,
"(Advanced) Force the action to be performed",
NULL },
{ "ticket", 't', 0, G_OPTION_ARG_STRING, &options.ticket_id,
"Ticket ID",
"ID" },
{ "xml-file", 'x', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &options.xml_file,
NULL,
NULL },
{ NULL }
};
static GOptionEntry deprecated_entries[] = {
{ "set-name", 'n', 0, G_OPTION_ARG_STRING, &options.set_name,
"(Advanced) ID of the " PCMK_XE_INSTANCE_ATTRIBUTES " object to change",
"ID" },
{ "nvpair", 'i', 0, G_OPTION_ARG_STRING, &options.attr_id,
"(Advanced) ID of the nvpair object to change/delete",
"ID" },
{ "quiet", 'Q', 0, G_OPTION_ARG_NONE, &options.quiet,
"Print only the value on stdout",
NULL },
{ NULL }
};
+/*!
+ * \internal
+ * \brief Output a configuration error
+ *
+ * \param[in] ctx Output object
+ * \param[in] msg printf(3)-style format string
+ * \param[in] ... Format string arguments
+ */
+G_GNUC_PRINTF(2, 3)
+static void
+output_config_error(void *ctx, const char *msg, ...)
+{
+ va_list ap;
+ char *buf = NULL;
+ pcmk__output_t *out = ctx;
+
+ va_start(ap, msg);
+ pcmk__assert(vasprintf(&buf, msg, ap) > 0);
+ if (!out->is_quiet(out)) {
+ out->err(out, "error: %s", buf);
+ }
+ va_end(ap);
+}
+
+/*!
+ * \internal
+ * \brief Output a configuration warning
+ *
+ * \param[in] ctx Output object
+ * \param[in] msg printf(3)-style format string
+ * \param[in] ... Format string arguments
+ */
+G_GNUC_PRINTF(2, 3)
+static void
+output_config_warning(void *ctx, const char *msg, ...)
+{
+ va_list ap;
+ char *buf = NULL;
+ pcmk__output_t *out = ctx;
+
+ va_start(ap, msg);
+ pcmk__assert(vasprintf(&buf, msg, ap) > 0);
+ if (!out->is_quiet(out)) {
+ out->err(out, "warning: %s", buf);
+ }
+ va_end(ap);
+}
+
static void
ticket_grant_warning(gchar *ticket_id)
{
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
ticket_revoke_warning(gchar *ticket_id)
{
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, GOptionGroup **group)
{
GOptionContext *context = NULL;
const char *description = "Examples:\n\n"
"Display the info of tickets:\n\n"
"\tcrm_ticket --info\n\n"
"Display the detailed info of tickets:\n\n"
"\tcrm_ticket --details\n\n"
"Display the XML of 'ticketA':\n\n"
"\tcrm_ticket --ticket ticketA --query-xml\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"
"Revoke 'ticketA' from this cluster site:\n\n"
"\tcrm_ticket --ticket ticketA --revoke\n\n"
"Make 'ticketA' standby (the cluster site will treat a granted\n"
"'ticketA' as 'standby', and the dependent resources will be\n"
"stopped or demoted gracefully without triggering loss-policies):\n\n"
"\tcrm_ticket --ticket ticketA --standby\n\n"
"Activate 'ticketA' from being standby:\n\n"
"\tcrm_ticket --ticket ticketA --activate\n\n"
"Get the value of the 'granted' attribute for 'ticketA':\n\n"
"\tcrm_ticket --ticket ticketA --get-attr granted\n\n"
"Set the value of the 'standby' attribute for 'ticketA':\n\n"
"\tcrm_ticket --ticket ticketA --set-attr standby --attr-value true\n\n"
"Delete the 'granted' attribute for 'ticketA':\n\n"
"\tcrm_ticket --ticket ticketA --delete-attr granted\n\n"
"Erase the operation history of 'ticketA' at this cluster site,\n"
"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, "text (default), xml", group, NULL);
g_option_context_set_description(context, description);
pcmk__add_arg_group(context, "queries", "Queries:",
"Show queries", query_entries);
pcmk__add_arg_group(context, "commands", "Commands:",
"Show command options", command_entries);
pcmk__add_arg_group(context, "advanced", "Advanced Options:",
"Show advanced options", advanced_entries);
pcmk__add_arg_group(context, "additional", "Additional Options:",
"Show additional options", addl_entries);
pcmk__add_arg_group(context, "deprecated", "Deprecated Options:",
"Show deprecated options", deprecated_entries);
return context;
}
int
main(int argc, char **argv)
{
pcmk_scheduler_t *scheduler = NULL;
xmlNode *cib_xml_copy = NULL;
cib_t *cib_conn = NULL;
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;
attr_set = pcmk__strkey_table(free, free);
attr_delete = NULL;
args = pcmk__new_common_args(SUMMARY);
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;
}
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);
+ out->quiet = options.quiet;
+
+ pcmk__set_config_error_handler(output_config_error, out);
+ pcmk__set_config_warning_handler(output_config_warning, out);
+
if (args->version) {
out->version(out, false);
goto done;
}
scheduler = pe_new_working_set();
if (scheduler == NULL) {
rc = errno;
exit_code = pcmk_rc2exitc(rc);
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
"Could not allocate scheduler data: %s", pcmk_rc_str(rc));
goto done;
}
pcmk__set_scheduler_flags(scheduler, pcmk__sched_no_counts);
cib_conn = cib_new();
if (cib_conn == NULL) {
exit_code = CRM_EX_DISCONNECT;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Could not connect to the CIB manager");
goto done;
}
rc = cib__signon_attempts(cib_conn, cib_command, 5);
rc = pcmk_legacy2rc(rc);
if (rc != pcmk_rc_ok) {
exit_code = pcmk_rc2exitc(rc);
g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Could not connect to the CIB: %s",
pcmk_rc_str(rc));
goto done;
}
if (options.xml_file != NULL) {
cib_xml_copy = pcmk__xml_read(options.xml_file);
} else {
rc = cib_conn->cmds->query(cib_conn, NULL, &cib_xml_copy,
cib_sync_call);
rc = pcmk_legacy2rc(rc);
if (rc != pcmk_rc_ok) {
exit_code = pcmk_rc2exitc(rc);
g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Could not get local CIB: %s",
pcmk_rc_str(rc));
goto done;
}
}
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;
}
scheduler->input = cib_xml_copy;
scheduler->priv->now = crm_time_new(NULL);
- pcmk_unpack_scheduler_input(scheduler);
+ rc = pcmk_unpack_scheduler_input(scheduler);
+ if (rc != pcmk_rc_ok) {
+ /* Error printing is handled by pcmk__set_config_error_handler */
+ exit_code = pcmk_rc2exitc(rc);
+ goto done;
+ }
/* 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') {
bool raw = false;
bool details = false;
if (options.ticket_cmd == 'L') {
details = true;
} else if (options.ticket_cmd == 'w') {
raw = true;
}
rc = pcmk__ticket_info(out, scheduler, options.ticket_id, details, raw);
exit_code = pcmk_rc2exitc(rc);
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 = pcmk__ticket_state(out, cib_conn, options.ticket_id);
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 = pcmk__ticket_constraints(out, cib_conn, options.ticket_id);
exit_code = pcmk_rc2exitc(rc);
if (rc != pcmk_rc_ok) {
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
"Could not show ticket constraints: %s", pcmk_rc_str(rc));
}
} else if (options.ticket_cmd == 'G') {
if (options.ticket_id == NULL) {
exit_code = CRM_EX_NOSUCH;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
"Must supply ticket ID with -t");
goto done;
}
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') {
if (options.ticket_id == NULL) {
exit_code = CRM_EX_USAGE;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
"Must supply ticket ID with -t");
goto done;
}
rc = pcmk__ticket_delete(out, cib_conn, scheduler, options.ticket_id,
options.force);
exit_code = pcmk_rc2exitc(rc);
switch (rc) {
case ENXIO:
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
"No such ticket '%s'", options.ticket_id);
break;
case EACCES:
ticket_revoke_warning(options.ticket_id);
break;
case pcmk_rc_ok:
case pcmk_rc_duplicate_id:
break;
default:
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
"Could not clean up ticket: %s", pcmk_rc_str(rc));
break;
}
} else if (modified) {
if (options.ticket_id == NULL) {
exit_code = CRM_EX_USAGE;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
"Must supply ticket ID with -t");
goto done;
}
if (options.attr_value
&& (pcmk__str_empty(options.attr_name))) {
exit_code = CRM_EX_USAGE;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
"Must supply attribute name with -S for -v %s", options.attr_value);
goto done;
}
if (options.attr_name
&& (pcmk__str_empty(options.attr_value))) {
exit_code = CRM_EX_USAGE;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
"Must supply attribute value with -v for -S %s", options.attr_value);
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 = CRM_EX_UNSAFE;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
"Ticket modification not allowed without --force");
goto done;
}
} 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 = CRM_EX_UNSAFE;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
"Ticket modification not allowed without --force");
goto done;
}
}
exit_code = pcmk_rc2exitc(rc);
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));
}
} else if (options.ticket_cmd == 'S') {
/* Correct usage was handled in the "if (modified)" block above, so
* this is just for reporting usage errors
*/
if (pcmk__str_empty(options.attr_name)) {
// We only get here if ticket_cmd was left as default
exit_code = CRM_EX_USAGE;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Must supply a command");
goto done;
}
if (options.ticket_id == NULL) {
exit_code = CRM_EX_USAGE;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
"Must supply ticket ID with -t");
goto done;
}
if (pcmk__str_empty(options.attr_value)) {
exit_code = CRM_EX_USAGE;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
"Must supply value with -v for -S %s", options.attr_name);
goto done;
}
} else {
exit_code = CRM_EX_USAGE;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
"Unknown command: %c", options.ticket_cmd);
}
done:
if (attr_set) {
g_hash_table_destroy(attr_set);
}
attr_set = NULL;
if (attr_delete) {
g_list_free_full(attr_delete, free);
}
attr_delete = NULL;
pe_free_working_set(scheduler);
scheduler = NULL;
cib__clean_up_connection(&cib_conn);
g_strfreev(processed_args);
pcmk__free_arg_context(context);
g_free(options.attr_default);
g_free(options.attr_id);
free(options.attr_name);
free(options.attr_value);
free(options.get_attr_name);
g_free(options.set_name);
g_free(options.ticket_id);
g_free(options.xml_file);
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);
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 23, 1:24 PM (18 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1018749
Default Alt Text
(24 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment