summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-03 13:39:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-03 13:39:28 +0000
commit924f5ea83e48277e014ebf0d19a27187cb93e2f7 (patch)
tree75920a275bba045f6d108204562c218a9a26ea15 /tools
parentAdding upstream version 2.1.7. (diff)
downloadpacemaker-upstream.tar.xz
pacemaker-upstream.zip
Adding upstream version 2.1.8~rc1.upstream/2.1.8_rc1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/attrd_updater.c12
-rw-r--r--tools/cibadmin.c209
-rw-r--r--tools/cibsecret.in2
-rw-r--r--tools/crm_attribute.c316
-rw-r--r--tools/crm_diff.c50
-rw-r--r--tools/crm_error.c4
-rw-r--r--tools/crm_mon.c324
-rw-r--r--tools/crm_mon.h3
-rw-r--r--tools/crm_mon_curses.c28
-rw-r--r--tools/crm_node.c87
-rw-r--r--tools/crm_resource.c1101
-rw-r--r--tools/crm_resource.h26
-rw-r--r--tools/crm_resource_ban.c188
-rw-r--r--tools/crm_resource_print.c271
-rw-r--r--tools/crm_resource_runtime.c779
-rw-r--r--tools/crm_rule.c15
-rw-r--r--tools/crm_shadow.c94
-rw-r--r--tools/crm_simulate.c52
-rw-r--r--tools/crm_ticket.c614
-rw-r--r--tools/crm_verify.c174
-rw-r--r--tools/crmadmin.c14
-rw-r--r--tools/stonith_admin.c23
22 files changed, 2300 insertions, 2086 deletions
diff --git a/tools/attrd_updater.c b/tools/attrd_updater.c
index 5f91356..5316101 100644
--- a/tools/attrd_updater.c
+++ b/tools/attrd_updater.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2023 the Pacemaker project contributors
+ * Copyright 2004-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -18,13 +18,13 @@
#include <sys/types.h>
#include <crm/crm.h>
-#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
#include <crm/common/ipc_attrd_internal.h>
#include <crm/common/cmdline_internal.h>
#include <crm/common/output_internal.h>
#include <crm/common/xml_internal.h>
-#include <crm/common/attrd_internal.h>
+#include <crm/common/attrs_internal.h>
#include <pcmki/pcmki_output.h>
@@ -85,9 +85,9 @@ private_cb (const gchar *option_name, const gchar *optarg, gpointer data, GError
static gboolean
section_cb (const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
- if (pcmk__str_any_of(optarg, "nodes", "forever", NULL)) {
+ if (pcmk__str_any_of(optarg, PCMK_XE_NODES, "forever", NULL)) {
pcmk__set_node_attr_flags(options.attr_options, pcmk__node_attr_perm);
- } else if (pcmk__str_any_of(optarg, "status", "reboot", NULL)) {
+ } else if (pcmk__str_any_of(optarg, PCMK_XE_STATUS, "reboot", NULL)) {
pcmk__clear_node_attr_flags(options.attr_options, pcmk__node_attr_perm);
} else {
g_set_error(err, PCMK__EXITC_ERROR, CRM_EX_USAGE, "Unknown value for --lifetime: %s",
@@ -398,7 +398,7 @@ print_attrd_values(pcmk__output_t *out, const GList *reply)
const pcmk__attrd_query_pair_t *pair = iter->data;
out->message(out, "attribute", NULL, NULL, pair->name, pair->value,
- pair->node);
+ pair->node, false, false);
printed_values = true;
}
}
diff --git a/tools/cibadmin.c b/tools/cibadmin.c
index 44488b5..9ac252d 100644
--- a/tools/cibadmin.c
+++ b/tools/cibadmin.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2023 the Pacemaker project contributors
+ * Copyright 2004-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -10,7 +10,6 @@
#include <crm_internal.h>
#include <stdio.h>
#include <crm/crm.h>
-#include <crm/msg_xml.h>
#include <crm/common/cmdline_internal.h>
#include <crm/common/ipc.h>
#include <crm/common/xml.h>
@@ -53,6 +52,7 @@ static struct {
gboolean get_node_path;
gboolean local;
gboolean no_children;
+ gboolean score_update;
gboolean sync_call;
/* @COMPAT: For "-!" version option. Not advertised nor marked as
@@ -79,9 +79,9 @@ print_xml_output(xmlNode * xml)
}
if (pcmk_is_set(options.cmd_options, cib_xpath_address)) {
- const char *id = crm_element_value(xml, XML_ATTR_ID);
+ const char *id = crm_element_value(xml, PCMK_XA_ID);
- if (pcmk__str_eq((const char *)xml->name, "xpath-query", pcmk__str_casei)) {
+ if (pcmk__xe_is(xml, PCMK__XE_XPATH_QUERY)) {
xmlNode *child = NULL;
for (child = xml->children; child; child = child->next) {
@@ -93,9 +93,12 @@ print_xml_output(xmlNode * xml)
}
} else {
- char *buffer = dump_xml_formatted(xml);
- fprintf(stdout, "%s", buffer);
- free(buffer);
+ GString *buf = g_string_sized_new(1024);
+
+ pcmk__xml_string(xml, pcmk__xml_fmt_pretty, buf, 0);
+
+ fprintf(stdout, "%s", buf->str);
+ g_string_free(buf, TRUE);
}
}
@@ -138,18 +141,18 @@ static inline bool
scope_is_valid(const char *scope)
{
return pcmk__str_any_of(scope,
- XML_CIB_TAG_CONFIGURATION,
- XML_CIB_TAG_NODES,
- XML_CIB_TAG_RESOURCES,
- XML_CIB_TAG_CONSTRAINTS,
- XML_CIB_TAG_CRMCONFIG,
- XML_CIB_TAG_RSCCONFIG,
- XML_CIB_TAG_OPCONFIG,
- XML_CIB_TAG_ACLS,
- XML_TAG_FENCING_TOPOLOGY,
- XML_CIB_TAG_TAGS,
- XML_CIB_TAG_ALERTS,
- XML_CIB_TAG_STATUS,
+ PCMK_XE_CONFIGURATION,
+ PCMK_XE_NODES,
+ PCMK_XE_RESOURCES,
+ PCMK_XE_CONSTRAINTS,
+ PCMK_XE_CRM_CONFIG,
+ PCMK_XE_RSC_DEFAULTS,
+ PCMK_XE_OP_DEFAULTS,
+ PCMK_XE_ACLS,
+ PCMK_XE_FENCING_TOPOLOGY,
+ PCMK_XE_TAGS,
+ PCMK_XE_ALERTS,
+ PCMK_XE_STATUS,
NULL);
}
@@ -283,8 +286,8 @@ static GOptionEntry command_entries[] = {
{ "delete", 'D', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Delete first object matching supplied criteria (for example, "
- "<" XML_ATTR_OP " " XML_ATTR_ID "=\"rsc1_op1\" "
- XML_ATTR_NAME "=\"monitor\"/>).\n"
+ "<" PCMK_XE_OP " " PCMK_XA_ID "=\"rsc1_op1\" "
+ PCMK_XA_NAME "=\"monitor\"/>).\n"
INDENT "The XML element name and all attributes must match in order for "
"the element to be deleted.",
NULL },
@@ -298,7 +301,7 @@ static GOptionEntry command_entries[] = {
{ "empty", 'a', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
command_cb,
"Output an empty CIB. Accepts an optional schema name argument to use as "
- "the " XML_ATTR_VALIDATION " value.\n"
+ "the " PCMK_XA_VALIDATE_WITH " value.\n"
INDENT "If no schema is given, the latest will be used.",
"[schema]" },
@@ -350,12 +353,12 @@ static GOptionEntry addl_entries[] = {
{ "scope", 'o', G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, section_cb,
"Limit scope of operation to specific section of CIB\n"
- INDENT "Valid values: " XML_CIB_TAG_CONFIGURATION ", " XML_CIB_TAG_NODES
- ", " XML_CIB_TAG_RESOURCES ", " XML_CIB_TAG_CONSTRAINTS
- ", " XML_CIB_TAG_CRMCONFIG ", " XML_CIB_TAG_RSCCONFIG ",\n"
- INDENT " " XML_CIB_TAG_OPCONFIG ", " XML_CIB_TAG_ACLS
- ", " XML_TAG_FENCING_TOPOLOGY ", " XML_CIB_TAG_TAGS
- ", " XML_CIB_TAG_ALERTS ", " XML_CIB_TAG_STATUS "\n"
+ INDENT "Valid values: " PCMK_XE_CONFIGURATION ", " PCMK_XE_NODES
+ ", " PCMK_XE_RESOURCES ", " PCMK_XE_CONSTRAINTS
+ ", " PCMK_XE_CRM_CONFIG ", " PCMK_XE_RSC_DEFAULTS ",\n"
+ INDENT " " PCMK_XE_OP_DEFAULTS ", " PCMK_XE_ACLS
+ ", " PCMK_XE_FENCING_TOPOLOGY ", " PCMK_XE_TAGS ", " PCMK_XE_ALERTS
+ ", " PCMK_XE_STATUS "\n"
INDENT "If both --scope/-o and --xpath/-a are specified, the last one to "
"appear takes effect",
"value" },
@@ -370,10 +373,10 @@ static GOptionEntry addl_entries[] = {
&options.get_node_path,
"When performing XPath queries, return paths of any matches found\n"
INDENT "(for example, "
- "\"/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION
- "/" XML_CIB_TAG_RESOURCES "/" XML_CIB_TAG_INCARNATION
- "[@" XML_ATTR_ID "='dummy-clone']"
- "/" XML_CIB_TAG_RESOURCE "[@" XML_ATTR_ID "='dummy']\")",
+ "\"/" PCMK_XE_CIB "/" PCMK_XE_CONFIGURATION
+ "/" PCMK_XE_RESOURCES "/" PCMK_XE_CLONE
+ "[@" PCMK_XA_ID "='dummy-clone']"
+ "/" PCMK_XE_PRIMITIVE "[@" PCMK_XA_ID "='dummy']\")",
NULL },
{ "show-access", 'S', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
@@ -386,6 +389,32 @@ static GOptionEntry addl_entries[] = {
INDENT "Default value: 'auto'",
"[value]" },
+ { "score", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &options.score_update,
+ "Treat new attribute values as atomic score updates where possible "
+ "(with --modify/-M)\n\n"
+
+ INDENT "This currently happens by default and cannot be disabled, but\n"
+ INDENT "this default behavior is deprecated and will be removed in a\n"
+ INDENT "future release. Set this flag if this behavior is desired.\n\n"
+
+ INDENT "This option takes effect when updating XML attributes. For an\n"
+ INDENT "attribute named \"name\", if the new value is \"name++\" or\n"
+ INDENT "\"name+=X\" for some score X, the new value is set as follows:\n"
+ INDENT " * If attribute \"name\" is not already set to some value in\n"
+ INDENT " the element being updated, the new value is set as a literal\n"
+ INDENT " string.\n"
+ INDENT " * If the new value is \"name++\", then the attribute is set to\n"
+ INDENT " its existing value (parsed as a score) plus 1.\n"
+ INDENT " * If the new value is \"name+=X\" for some score X, then the\n"
+ INDENT " attribute is set to its existing value plus X, where the\n"
+ INDENT " existing value and X are parsed and added as scores.\n\n"
+
+ INDENT "Scores are integer values capped at INFINITY and -INFINITY.\n"
+ INDENT "Refer to Pacemaker Explained and to the char2score() function\n"
+ INDENT "for more details on scores, including how they're parsed and\n"
+ INDENT "added.",
+ NULL },
+
{ "allow-create", 'c', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE,
&options.allow_create,
"(Advanced) Allow target of --modify/-M to be created if it does not "
@@ -430,34 +459,33 @@ build_arg_context(pcmk__common_args_t *args)
"Query the configuration from the local node:\n\n"
"\t# cibadmin --query --local\n\n"
"Query just the cluster options configuration:\n\n"
- "\t# cibadmin --query --scope " XML_CIB_TAG_CRMCONFIG "\n\n"
- "Query all '" XML_RSC_ATTR_TARGET_ROLE "' settings:\n\n"
+ "\t# cibadmin --query --scope " PCMK_XE_CRM_CONFIG "\n\n"
+ "Query all '" PCMK_META_TARGET_ROLE "' settings:\n\n"
"\t# cibadmin --query --xpath "
- "\"//" XML_CIB_TAG_NVPAIR
- "[@" XML_NVPAIR_ATTR_NAME "='" XML_RSC_ATTR_TARGET_ROLE"']\""
- "\n\n"
- "Remove all '" XML_RSC_ATTR_MANAGED "' settings:\n\n"
+ "\"//" PCMK_XE_NVPAIR
+ "[@" PCMK_XA_NAME "='" PCMK_META_TARGET_ROLE"']\"\n\n"
+ "Remove all '" PCMK_META_IS_MANAGED "' settings:\n\n"
"\t# cibadmin --delete-all --xpath "
- "\"//" XML_CIB_TAG_NVPAIR
- "[@" XML_NVPAIR_ATTR_NAME "='" XML_RSC_ATTR_MANAGED "']\"\n\n"
+ "\"//" PCMK_XE_NVPAIR
+ "[@" PCMK_XA_NAME "='" PCMK_META_IS_MANAGED "']\"\n\n"
"Remove the resource named 'old':\n\n"
"\t# cibadmin --delete --xml-text "
- "'<" XML_CIB_TAG_RESOURCE " " XML_ATTR_ID "=\"old\"/>'\n\n"
+ "'<" PCMK_XE_PRIMITIVE " " PCMK_XA_ID "=\"old\"/>'\n\n"
"Remove all resources from the configuration:\n\n"
- "\t# cibadmin --replace --scope " XML_CIB_TAG_RESOURCES
- " --xml-text '<" XML_CIB_TAG_RESOURCES "/>'\n\n"
+ "\t# cibadmin --replace --scope " PCMK_XE_RESOURCES
+ " --xml-text '<" PCMK_XE_RESOURCES "/>'\n\n"
"Replace complete configuration with contents of "
"$HOME/pacemaker.xml:\n\n"
"\t# cibadmin --replace --xml-file $HOME/pacemaker.xml\n\n"
- "Replace " XML_CIB_TAG_CONSTRAINTS " section of configuration with "
+ "Replace " PCMK_XE_CONSTRAINTS " section of configuration with "
"contents of $HOME/constraints.xml:\n\n"
- "\t# cibadmin --replace --scope " XML_CIB_TAG_CONSTRAINTS
+ "\t# cibadmin --replace --scope " PCMK_XE_CONSTRAINTS
" --xml-file $HOME/constraints.xml\n\n"
"Increase configuration version to prevent old configurations from "
"being loaded accidentally:\n\n"
"\t# cibadmin --modify --xml-text "
- "'<" XML_TAG_CIB " " XML_ATTR_GENERATION_ADMIN
- "=\"" XML_ATTR_GENERATION_ADMIN "++\"/>'\n\n"
+ "'<" PCMK_XE_CIB " " PCMK_XA_ADMIN_EPOCH
+ "=\"" PCMK_XA_ADMIN_EPOCH "++\"/>'\n\n"
"Edit the configuration with your favorite $EDITOR:\n\n"
"\t# cibadmin --query > $HOME/local.xml\n\n"
"\t# $EDITOR $HOME/local.xml\n\n"
@@ -567,13 +595,14 @@ main(int argc, char **argv)
if (strcmp(options.cib_action, "empty") == 0) {
// Output an empty CIB
- char *buf = NULL;
+ GString *buf = g_string_sized_new(1024);
output = createEmptyCib(1);
- crm_xml_add(output, XML_ATTR_VALIDATION, options.validate_with);
- buf = dump_xml_formatted(output);
- fprintf(stdout, "%s", buf);
- free(buf);
+ crm_xml_add(output, PCMK_XA_VALIDATE_WITH, options.validate_with);
+
+ pcmk__xml_string(output, pcmk__xml_fmt_pretty, buf, 0);
+ fprintf(stdout, "%s", buf->str);
+ g_string_free(buf, TRUE);
goto done;
}
@@ -658,16 +687,16 @@ main(int argc, char **argv)
}
if (options.input_file != NULL) {
- input = filename2xml(options.input_file);
+ input = pcmk__xml_read(options.input_file);
source = options.input_file;
} else if (options.input_xml != NULL) {
- input = string2xml(options.input_xml);
+ input = pcmk__xml_parse(options.input_xml);
source = "input string";
} else if (options.input_stdin) {
+ input = pcmk__xml_read(NULL);
source = "STDIN";
- input = stdin2xml();
} else if (options.acl_render_mode != pcmk__acl_render_none) {
char *username = pcmk__uid2username(geteuid());
@@ -751,12 +780,20 @@ main(int argc, char **argv)
goto done;
}
- version = crm_element_value(input, XML_ATTR_CRM_VERSION);
+ version = crm_element_value(input, PCMK_XA_CRM_FEATURE_SET);
digest = calculate_xml_versioned_digest(input, FALSE, TRUE, version);
fprintf(stderr, "Versioned (%s) digest: ", version);
fprintf(stdout, "%s\n", pcmk__s(digest, "<null>"));
free(digest);
goto done;
+
+ } else if (pcmk__str_eq(options.cib_action, PCMK__CIB_REQUEST_MODIFY,
+ pcmk__str_none)) {
+ /* @COMPAT When we drop default support for expansion in cibadmin, guard
+ * with `if (options.score_update)`
+ */
+ cib__set_call_options(options.cmd_options, crm_system_name,
+ cib_score_update);
}
rc = do_init();
@@ -773,9 +810,13 @@ main(int argc, char **argv)
}
rc = do_work(input, &output);
- if (rc > 0) {
- /* wait for the reply by creating a mainloop and running it until
- * the callbacks are invoked...
+ if (!pcmk_is_set(options.cmd_options, cib_sync_call)
+ && (the_cib->variant != cib_file)
+ && (rc >= 0)) {
+ /* For async call, positive rc is the call ID (file always synchronous).
+ *
+ * Wait for the reply by creating a mainloop and running it until the
+ * callbacks are invoked.
*/
request_id = rc;
@@ -791,32 +832,36 @@ main(int argc, char **argv)
crm_info("Starting mainloop");
g_main_loop_run(mainloop);
- } else if ((rc == -pcmk_err_schema_unchanged)
- && (strcmp(options.cib_action,
- PCMK__CIB_REQUEST_UPGRADE) == 0)) {
- report_schema_unchanged();
-
- } else if (rc < 0) {
+ } else {
rc = pcmk_legacy2rc(rc);
- crm_err("Call failed: %s", pcmk_rc_str(rc));
- fprintf(stderr, "Call failed: %s\n", pcmk_rc_str(rc));
- if (rc == pcmk_rc_schema_validation) {
- if (strcmp(options.cib_action, PCMK__CIB_REQUEST_UPGRADE) == 0) {
- xmlNode *obj = NULL;
- int version = 0;
+ if ((rc == pcmk_rc_schema_unchanged)
+ && (strcmp(options.cib_action, PCMK__CIB_REQUEST_UPGRADE) == 0)) {
- if (the_cib->cmds->query(the_cib, NULL, &obj,
- options.cmd_options) == pcmk_ok) {
- update_validation(&obj, &version, 0, TRUE, FALSE);
- }
- free_xml(obj);
+ report_schema_unchanged();
+
+ } else if (rc != pcmk_rc_ok) {
+ crm_err("Call failed: %s", pcmk_rc_str(rc));
+ fprintf(stderr, "Call failed: %s\n", pcmk_rc_str(rc));
+ exit_code = pcmk_rc2exitc(rc);
- } else if (output) {
- validate_xml_verbose(output);
+ if (rc == pcmk_rc_schema_validation) {
+ if (strcmp(options.cib_action,
+ PCMK__CIB_REQUEST_UPGRADE) == 0) {
+ xmlNode *obj = NULL;
+
+ if (the_cib->cmds->query(the_cib, NULL, &obj,
+ options.cmd_options) == pcmk_ok) {
+ pcmk__update_schema(&obj, NULL, true, false);
+ }
+ free_xml(obj);
+
+ } else if (output != NULL) {
+ // Show validation errors to stderr
+ pcmk__validate_xml(output, NULL, NULL, NULL);
+ }
}
}
- exit_code = pcmk_rc2exitc(rc);
}
if ((output != NULL)
@@ -883,11 +928,11 @@ do_work(xmlNode *input, xmlNode **output)
/* construct the request */
the_cib->call_timeout = options.message_timeout_sec;
if ((strcmp(options.cib_action, PCMK__CIB_REQUEST_REPLACE) == 0)
- && pcmk__xe_is(input, XML_TAG_CIB)) {
- xmlNode *status = pcmk_find_cib_element(input, XML_CIB_TAG_STATUS);
+ && pcmk__xe_is(input, PCMK_XE_CIB)) {
+ xmlNode *status = pcmk_find_cib_element(input, PCMK_XE_STATUS);
if (status == NULL) {
- create_xml_node(input, XML_CIB_TAG_STATUS);
+ pcmk__xe_create(input, PCMK_XE_STATUS);
}
}
diff --git a/tools/cibsecret.in b/tools/cibsecret.in
index 4569863..9df4201 100644
--- a/tools/cibsecret.in
+++ b/tools/cibsecret.in
@@ -171,7 +171,7 @@ check_env() {
else
fatal $CRM_EX_NOT_INSTALLED "please install pssh, pdsh, or ssh to run $PROG"
fi
- ps -ef | grep '[p]acemaker-controld' >/dev/null ||
+ ps axww | grep '[p]acemaker-controld' >/dev/null ||
fatal $CRM_EX_UNAVAILABLE "pacemaker not running? $PROG needs pacemaker"
}
diff --git a/tools/crm_attribute.c b/tools/crm_attribute.c
index defe294..f9b1434 100644
--- a/tools/crm_attribute.c
+++ b/tools/crm_attribute.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2023 the Pacemaker project contributors
+ * Copyright 2004-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -22,7 +22,6 @@
#include <sys/types.h>
#include <crm/crm.h>
-#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/ipc.h>
#include <crm/common/util.h>
@@ -30,7 +29,7 @@
#include <crm/cib.h>
#include <crm/cib/internal.h>
-#include <crm/common/attrd_internal.h>
+#include <crm/common/attrs_internal.h>
#include <crm/common/cmdline_internal.h>
#include <crm/common/ipc_attrd_internal.h>
#include <crm/common/ipc_controld.h>
@@ -41,36 +40,18 @@
#define SUMMARY "crm_attribute - query and update Pacemaker cluster options and node attributes"
+enum attr_cmd {
+ attr_cmd_none,
+ attr_cmd_delete,
+ attr_cmd_list,
+ attr_cmd_query,
+ attr_cmd_update,
+};
+
GError *error = NULL;
crm_exit_t exit_code = CRM_EX_OK;
uint64_t cib_opts = cib_sync_call;
-PCMK__OUTPUT_ARGS("attribute", "const char *", "const char *", "const char *",
- "const char *", "const char *")
-static int
-attribute_text(pcmk__output_t *out, va_list args)
-{
- const char *scope = va_arg(args, const char *);
- const char *instance = va_arg(args, const char *);
- const char *name = va_arg(args, const char *);
- const char *value = va_arg(args, const char *);
- const char *host G_GNUC_UNUSED = va_arg(args, const char *);
-
- if (out->quiet) {
- if (value != NULL) {
- pcmk__formatted_printf(out, "%s\n", value);
- }
- } else {
- out->info(out, "%s%s %s%s %s%s value=%s",
- scope ? "scope=" : "", scope ? scope : "",
- instance ? "id=" : "", instance ? instance : "",
- name ? "name=" : "", name ? name : "",
- value ? value : "(null)");
- }
-
- return pcmk_rc_ok;
-}
-
static pcmk__supported_format_t formats[] = {
PCMK__SUPPORTED_FORMAT_NONE,
PCMK__SUPPORTED_FORMAT_TEXT,
@@ -78,14 +59,8 @@ static pcmk__supported_format_t formats[] = {
{ NULL, NULL, NULL }
};
-static pcmk__message_entry_t fmt_functions[] = {
- { "attribute", "text", attribute_text },
-
- { NULL, NULL, NULL }
-};
-
struct {
- char command;
+ enum attr_cmd command;
gchar *attr_default;
gchar *attr_id;
gchar *attr_name;
@@ -98,26 +73,49 @@ struct {
gchar *set_name;
char *set_type;
gchar *type;
- gboolean promotion_score;
+ char *opt_list;
+ gboolean all;
+ bool promotion_score;
+ gboolean score_update;
} options = {
- .command = 'G',
- .promotion_score = FALSE
+ .command = attr_cmd_query,
};
#define INDENT " "
static gboolean
+list_cb(const gchar *option_name, const gchar *optarg, gpointer data,
+ GError **error) {
+ options.command = attr_cmd_list;
+ pcmk__str_update(&options.opt_list, optarg);
+ return TRUE;
+}
+
+static gboolean
delete_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- options.command = 'D';
+ options.command = attr_cmd_delete;
pcmk__str_update(&options.attr_value, NULL);
return TRUE;
}
static gboolean
+attr_name_cb(const gchar *option_name, const gchar *optarg, gpointer data,
+ GError **error)
+{
+ options.promotion_score = false;
+
+ if (options.attr_name != NULL) {
+ g_free(options.attr_name);
+ }
+ options.attr_name = g_strdup(optarg);
+ return TRUE;
+}
+
+static gboolean
promotion_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
char *score_name = NULL;
- options.promotion_score = TRUE;
+ options.promotion_score = true;
if (options.attr_name) {
g_free(options.attr_name);
@@ -136,7 +134,7 @@ promotion_cb(const gchar *option_name, const gchar *optarg, gpointer data, GErro
static gboolean
update_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- options.command = 'u';
+ options.command = attr_cmd_update;
pcmk__str_update(&options.attr_value, optarg);
return TRUE;
}
@@ -147,14 +145,14 @@ utilization_cb(const gchar *option_name, const gchar *optarg, gpointer data, GEr
g_free(options.type);
}
- options.type = g_strdup(XML_CIB_TAG_NODES);
- pcmk__str_update(&options.set_type, XML_TAG_UTILIZATION);
+ options.type = g_strdup(PCMK_XE_NODES);
+ pcmk__str_update(&options.set_type, PCMK_XE_UTILIZATION);
return TRUE;
}
static gboolean
value_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- options.command = 'G';
+ options.command = attr_cmd_query;
pcmk__str_update(&options.attr_value, NULL);
return TRUE;
}
@@ -180,13 +178,20 @@ wait_cb (const gchar *option_name, const gchar *optarg, gpointer data, GError **
}
static GOptionEntry selecting_entries[] = {
+ { "all", 'a', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &options.all,
+ "With -L/--list-options, include advanced and deprecated options in the\n"
+ INDENT "output. This is always treated as true when --output-as=xml is\n"
+ INDENT "specified.",
+ NULL,
+ },
+
{ "id", 'i', 0, G_OPTION_ARG_STRING, &options.attr_id,
"(Advanced) Operate on instance of specified attribute with this\n"
INDENT "XML ID",
"XML_ID"
},
- { "name", 'n', 0, G_OPTION_ARG_STRING, &options.attr_name,
+ { "name", 'n', G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, attr_name_cb,
"Operate on attribute or option with this name. For queries, this\n"
INDENT "is optional, in which case all matching attributes will be\n"
INDENT "returned.",
@@ -217,8 +222,14 @@ static GOptionEntry selecting_entries[] = {
};
static GOptionEntry command_entries[] = {
+ { "list-options", 'L', G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, list_cb,
+ "List all available options of the given type.\n"
+ INDENT "Allowed values: " PCMK__VALUE_CLUSTER,
+ "TYPE"
+ },
+
{ "delete", 'D', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, delete_cb,
- "Delete the attribute/option",
+ "Delete the attribute/option (with -n or -P)",
NULL
},
@@ -229,7 +240,7 @@ static GOptionEntry command_entries[] = {
},
{ "update", 'v', 0, G_OPTION_ARG_CALLBACK, update_cb,
- "Update the value of the attribute/option",
+ "Update the value of the attribute/option (with -n or -P)",
"VALUE"
},
@@ -260,6 +271,35 @@ static GOptionEntry addl_entries[] = {
"SECTION"
},
+ { "score", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &options.score_update,
+ "Treat new attribute values as atomic score updates where possible\n"
+ INDENT "(with --update/-v, when running against a CIB file or updating\n"
+ INDENT "an attribute outside the " PCMK_XE_STATUS " section; enabled\n"
+ INDENT "by default if --promotion/-p is specified)\n\n"
+
+ INDENT "This currently happens by default and cannot be disabled, but\n"
+ INDENT "this default behavior is deprecated and will be removed in a\n"
+ INDENT "future release (exception: this will remain the default with\n"
+ INDENT "--promotion/-p). Set this flag if this behavior is desired.\n\n"
+
+ INDENT "This option takes effect when updating XML attributes. For an\n"
+ INDENT "attribute named \"name\", if the new value is \"name++\" or\n"
+ INDENT "\"name+=X\" for some score X, the new value is set as follows:\n"
+ INDENT " * If attribute \"name\" is not already set to some value in\n"
+ INDENT " the element being updated, the new value is set as a literal\n"
+ INDENT " string.\n"
+ INDENT " * If the new value is \"name++\", then the attribute is set to\n"
+ INDENT " its existing value (parsed as a score) plus 1.\n"
+ INDENT " * If the new value is \"name+=X\" for some score X, then the\n"
+ INDENT " attribute is set to its existing value plus X, where the\n"
+ INDENT " existing value and X are parsed and added as scores.\n\n"
+
+ INDENT "Scores are integer values capped at INFINITY and -INFINITY.\n"
+ INDENT "Refer to Pacemaker Explained and to the char2score() function\n"
+ INDENT "for more details on scores, including how they're parsed and\n"
+ INDENT "added.",
+ NULL },
+
{ "wait", 'W', 0, G_OPTION_ARG_CALLBACK, wait_cb,
"Wait for some event to occur before returning. Values are 'no' (wait\n"
INDENT "only for the attribute daemon to acknowledge the request),\n"
@@ -288,7 +328,7 @@ static GOptionEntry deprecated_entries[] = {
NULL, NULL
},
- { "attr-name", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &options.attr_name,
+ { "attr-name", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, attr_name_cb,
NULL, NULL
},
@@ -314,36 +354,39 @@ static GOptionEntry deprecated_entries[] = {
static void
get_node_name_from_local(void)
{
- char *hostname = pcmk_hostname();
+ struct utsname hostinfo;
g_free(options.dest_uname);
- /* This silliness is so that dest_uname is always a glib-managed
- * string so we know how to free it later. pcmk_hostname returns
- * a newly allocated string via strdup.
- */
- options.dest_uname = g_strdup(hostname);
- free(hostname);
+ if (uname(&hostinfo) == 0) {
+ options.dest_uname = g_strdup(hostinfo.nodename);
+ } else {
+ options.dest_uname = NULL;
+ }
}
static int
-send_attrd_update(char command, const char *attr_node, const char *attr_name,
- const char *attr_value, const char *attr_set,
- const char *attr_dampen, uint32_t attr_options)
+send_attrd_update(enum attr_cmd command, const char *attr_node,
+ const char *attr_name, const char *attr_value,
+ const char *attr_set, const char *attr_dampen,
+ uint32_t attr_options)
{
int rc = pcmk_rc_ok;
uint32_t opts = attr_options;
switch (command) {
- case 'D':
+ case attr_cmd_delete:
rc = pcmk__attrd_api_delete(NULL, attr_node, attr_name, opts);
break;
- case 'u':
+ case attr_cmd_update:
rc = pcmk__attrd_api_update(NULL, attr_node, attr_name,
attr_value, NULL, attr_set, NULL,
opts | pcmk__node_attr_value);
break;
+
+ default:
+ break;
}
if (rc != pcmk_rc_ok) {
@@ -364,7 +407,7 @@ delete_attr_on_node(xmlNode *child, void *userdata)
{
struct delete_data_s *dd = (struct delete_data_s *) userdata;
- const char *attr_name = crm_element_value(child, XML_NVPAIR_ATTR_NAME);
+ const char *attr_name = crm_element_value(child, PCMK_XA_NAME);
int rc = pcmk_rc_ok;
if (!pcmk__str_eq(attr_name, options.attr_pattern, pcmk__str_regex)) {
@@ -383,6 +426,22 @@ delete_attr_on_node(xmlNode *child, void *userdata)
return rc;
}
+static void
+command_list(pcmk__output_t *out)
+{
+ if (pcmk__str_eq(options.opt_list, PCMK__VALUE_CLUSTER, pcmk__str_none)) {
+ exit_code = pcmk_rc2exitc(pcmk__list_cluster_options(out, options.all));
+
+ } else {
+ // @TODO Improve usage messages to reduce duplication
+ exit_code = CRM_EX_USAGE;
+ g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
+ "Invalid --list-options value '%s'. Allowed values: "
+ PCMK__VALUE_CLUSTER,
+ pcmk__s(options.opt_list, "(BUG: none)"));
+ }
+}
+
static int
command_delete(pcmk__output_t *out, cib_t *cib)
{
@@ -405,10 +464,6 @@ command_delete(pcmk__output_t *out, cib_t *cib)
rc = pcmk__xe_foreach_child(result, NULL, delete_attr_on_node, &dd);
- if (rc != pcmk_rc_ok) {
- goto done_deleting;
- }
-
} else {
rc = cib__delete_node_attr(out, cib, cib_opts, options.type, options.dest_node,
options.set_type, options.set_name, options.attr_id,
@@ -440,7 +495,7 @@ update_attr_on_node(xmlNode *child, void *userdata)
{
struct update_data_s *ud = (struct update_data_s *) userdata;
- const char *attr_name = crm_element_value(child, XML_NVPAIR_ATTR_NAME);
+ const char *attr_name = crm_element_value(child, PCMK_XA_NAME);
if (!pcmk__str_eq(attr_name, options.attr_pattern, pcmk__str_regex)) {
return pcmk_rc_ok;
@@ -450,7 +505,7 @@ update_attr_on_node(xmlNode *child, void *userdata)
options.dest_node, options.set_type,
options.set_name, options.attr_id,
attr_name, options.attr_value, NULL,
- ud->is_remote_node ? "remote" : NULL);
+ ud->is_remote_node? PCMK_VALUE_REMOTE : NULL);
}
static int
@@ -461,9 +516,10 @@ command_update(pcmk__output_t *out, cib_t *cib, int is_remote_node)
xmlNode *result = NULL;
bool use_pattern = options.attr_pattern != NULL;
- CRM_LOG_ASSERT(options.type != NULL);
- CRM_LOG_ASSERT(options.attr_name != NULL);
- CRM_LOG_ASSERT(options.attr_value != NULL);
+ /* @COMPAT When we drop default support for expansion in crm_attribute,
+ * guard with `if (options.score_update)`
+ */
+ cib__set_call_options(cib_opts, crm_system_name, cib_score_update);
/* See the comment in command_query regarding xpath and regular expressions. */
if (use_pattern) {
@@ -479,16 +535,12 @@ command_update(pcmk__output_t *out, cib_t *cib, int is_remote_node)
rc = pcmk__xe_foreach_child(result, NULL, update_attr_on_node, &ud);
- if (rc != pcmk_rc_ok) {
- goto done_updating;
- }
-
} else {
rc = cib__update_node_attr(out, cib, cib_opts, options.type,
options.dest_node, options.set_type,
options.set_name, options.attr_id,
- options.attr_name, options.attr_value,
- NULL, is_remote_node ? "remote" : NULL);
+ options.attr_name, options.attr_value, NULL,
+ is_remote_node? PCMK_VALUE_REMOTE : NULL);
}
done_updating:
@@ -507,9 +559,8 @@ output_one_attribute(xmlNode *node, void *userdata)
{
struct output_data_s *od = (struct output_data_s *) userdata;
- const char *name = crm_element_value(node, XML_NVPAIR_ATTR_NAME);
- const char *value = crm_element_value(node, XML_NVPAIR_ATTR_VALUE);
- const char *host = crm_element_value(node, PCMK__XA_ATTR_NODE_NAME);
+ const char *name = crm_element_value(node, PCMK_XA_NAME);
+ const char *value = crm_element_value(node, PCMK_XA_VALUE);
const char *type = options.type;
const char *attr_id = options.attr_id;
@@ -518,7 +569,8 @@ output_one_attribute(xmlNode *node, void *userdata)
return pcmk_rc_ok;
}
- od->out->message(od->out, "attribute", type, attr_id, name, value, host);
+ od->out->message(od->out, "attribute", type, attr_id, name, value, NULL,
+ od->out->quiet, true);
od->did_output = true;
crm_info("Read %s='%s' %s%s",
pcmk__s(name, "<null>"), pcmk__s(value, ""),
@@ -556,10 +608,9 @@ command_query(pcmk__output_t *out, cib_t *cib)
const char *attr_id = options.attr_id;
const char *attr_name = options.attr_name;
const char *attr_default = options.attr_default;
- const char *dest_uname = options.dest_uname;
out->message(out, "attribute", type, attr_id, attr_name, attr_default,
- dest_uname);
+ NULL, out->quiet, true);
rc = pcmk_rc_ok;
} else if (rc != pcmk_rc_ok) {
@@ -589,22 +640,22 @@ set_type(void)
if (options.type == NULL) {
if (options.promotion_score) {
// Updating a promotion score node attribute
- options.type = g_strdup(XML_CIB_TAG_STATUS);
+ options.type = g_strdup(PCMK_XE_STATUS);
} else if (options.dest_uname != NULL) {
// Updating some other node attribute
- options.type = g_strdup(XML_CIB_TAG_NODES);
+ options.type = g_strdup(PCMK_XE_NODES);
} else {
// Updating cluster options
- options.type = g_strdup(XML_CIB_TAG_CRMCONFIG);
+ options.type = g_strdup(PCMK_XE_CRM_CONFIG);
}
} else if (pcmk__str_eq(options.type, "reboot", pcmk__str_casei)) {
- options.type = g_strdup(XML_CIB_TAG_STATUS);
+ options.type = g_strdup(PCMK_XE_STATUS);
} else if (pcmk__str_eq(options.type, "forever", pcmk__str_casei)) {
- options.type = g_strdup(XML_CIB_TAG_NODES);
+ options.type = g_strdup(PCMK_XE_NODES);
}
}
@@ -614,14 +665,16 @@ use_attrd(void)
/* Only go through the attribute manager for transient attributes, and
* then only if we're not using a file as the CIB.
*/
- return pcmk__str_eq(options.type, XML_CIB_TAG_STATUS, pcmk__str_casei) &&
+ return pcmk__str_eq(options.type, PCMK_XE_STATUS, pcmk__str_casei) &&
getenv("CIB_file") == NULL && getenv("CIB_shadow") == NULL;
}
static bool
try_ipc_update(void)
{
- return use_attrd() && (options.command == 'D' || options.command == 'u');
+ return use_attrd()
+ && ((options.command == attr_cmd_delete)
+ || (options.command == attr_cmd_update));
}
static bool
@@ -630,13 +683,30 @@ pattern_used_correctly(void)
/* --pattern can only be used with:
* -G (query), -v (update), or -D (delete)
*/
- return options.command == 'G' || options.command == 'u' || options.command == 'D';
+ switch (options.command) {
+ case attr_cmd_delete:
+ case attr_cmd_query:
+ case attr_cmd_update:
+ return true;
+ default:
+ return false;
+ }
}
static bool
delete_used_correctly(void)
{
- return options.command != 'D' || options.attr_name != NULL || options.attr_pattern != NULL;
+ return (options.command != attr_cmd_delete)
+ || (options.attr_name != NULL)
+ || (options.attr_pattern != NULL);
+}
+
+static bool
+update_used_correctly(void)
+{
+ return (options.command != attr_cmd_update)
+ || (options.attr_name != NULL)
+ || (options.attr_pattern != NULL);
}
static GOptionContext *
@@ -664,10 +734,14 @@ build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
"\tcrm_attribute --node myhost --name location --update backoffice\n\n"
"Delete the 'location' node attribute for host 'myhost':\n\n"
"\tcrm_attribute --node myhost --name location --delete\n\n"
- "Query the value of the 'cluster-delay' cluster option:\n\n"
- "\tcrm_attribute --type crm_config --name cluster-delay --query\n\n"
- "Query value of the 'cluster-delay' cluster option and print only the value:\n\n"
- "\tcrm_attribute --type crm_config --name cluster-delay --query --quiet\n\n";
+ "Query the value of the '" PCMK_OPT_CLUSTER_DELAY
+ "' cluster option:\n\n"
+ "\tcrm_attribute --type crm_config --name "
+ PCMK_OPT_CLUSTER_DELAY " --query\n\n"
+ "Query value of the '" PCMK_OPT_CLUSTER_DELAY
+ "' cluster option and print only the value:\n\n"
+ "\tcrm_attribute --type crm_config --name "
+ PCMK_OPT_CLUSTER_DELAY " --query --quiet\n\n";
context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
pcmk__add_main_args(context, extra_prog_entries);
@@ -717,7 +791,6 @@ main(int argc, char **argv)
}
pcmk__register_lib_messages(out);
- pcmk__register_messages(out, fmt_functions);
if (args->version) {
out->version(out, false);
@@ -726,6 +799,11 @@ main(int argc, char **argv)
out->quiet = args->quiet;
+ if (options.command == attr_cmd_list) {
+ command_list(out);
+ goto done;
+ }
+
if (options.promotion_score && options.attr_name == NULL) {
exit_code = CRM_EX_USAGE;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
@@ -753,8 +831,8 @@ main(int argc, char **argv)
set_type();
// Use default node if not given (except for cluster options and tickets)
- if (!pcmk__strcase_any_of(options.type, XML_CIB_TAG_CRMCONFIG, XML_CIB_TAG_TICKETS,
- NULL)) {
+ if (!pcmk__strcase_any_of(options.type,
+ PCMK_XE_CRM_CONFIG, PCMK_XE_TICKETS, NULL)) {
/* If we are being called from a resource agent via the cluster,
* the correct local node name will be passed as an environment
* variable. Otherwise, we have to ask the cluster.
@@ -762,8 +840,23 @@ main(int argc, char **argv)
const char *target = pcmk__node_attr_target(options.dest_uname);
if (target != NULL) {
- g_free(options.dest_uname);
- options.dest_uname = g_strdup(target);
+ /* If options.dest_uname is "auto" or "localhost", then
+ * pcmk__node_attr_target() may return it, depending on environment
+ * variables. In that case, attribute lookups will fail for "auto"
+ * (unless there's a node named "auto"). attrd maps "localhost" to
+ * the true local node name for queries.
+ *
+ * @TODO
+ * * Investigate whether "localhost" is mapped to a real node name
+ * for non-query commands. If not, possibly modify it so that it
+ * is.
+ * * Map "auto" to "localhost" (probably).
+ */
+ if (target != (const char *) options.dest_uname) {
+ g_free(options.dest_uname);
+ options.dest_uname = g_strdup(target);
+ }
+
} else if (getenv("CIB_file") != NULL && options.dest_uname == NULL) {
get_node_name_from_local();
}
@@ -800,6 +893,13 @@ main(int argc, char **argv)
goto done;
}
+ if (!update_used_correctly()) {
+ exit_code = CRM_EX_USAGE;
+ g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
+ "Error: must specify attribute name or pattern to update");
+ goto done;
+ }
+
if (options.attr_pattern) {
if (options.attr_name) {
exit_code = CRM_EX_USAGE;
@@ -824,20 +924,26 @@ main(int argc, char **argv)
options.attr_options |= pcmk__node_attr_remote;
}
- if (pcmk__str_eq(options.set_type, XML_TAG_UTILIZATION, pcmk__str_none)) {
+ if (pcmk__str_eq(options.set_type, PCMK_XE_UTILIZATION, pcmk__str_none)) {
options.attr_options |= pcmk__node_attr_utilization;
}
if (try_ipc_update() &&
(send_attrd_update(options.command, options.dest_uname, options.attr_name,
options.attr_value, options.set_name, NULL, options.attr_options) == pcmk_rc_ok)) {
+
+ const char *update = options.attr_value;
+
+ if (options.command == attr_cmd_delete) {
+ update = "<none>";
+ }
crm_info("Update %s=%s sent via pacemaker-attrd",
- options.attr_name, ((options.command == 'D')? "<none>" : options.attr_value));
+ options.attr_name, update);
- } else if (options.command == 'D') {
+ } else if (options.command == attr_cmd_delete) {
rc = command_delete(out, the_cib);
- } else if (options.command == 'u') {
+ } else if (options.command == attr_cmd_update) {
rc = command_update(out, the_cib, is_remote_node);
} else {
diff --git a/tools/crm_diff.c b/tools/crm_diff.c
index 9925ea7..09e24c1 100644
--- a/tools/crm_diff.c
+++ b/tools/crm_diff.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2023 the Pacemaker project contributors
+ * Copyright 2005-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <crm/crm.h>
-#include <crm/msg_xml.h>
#include <crm/common/cmdline_internal.h>
#include <crm/common/output_internal.h>
#include <crm/common/xml.h>
@@ -106,10 +105,12 @@ patch_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **
static void
print_patch(xmlNode *patch)
{
- char *buffer = dump_xml_formatted(patch);
+ GString *buffer = g_string_sized_new(1024);
- printf("%s", buffer);
- free(buffer);
+ pcmk__xml_string(patch, pcmk__xml_fmt_pretty, buffer, 0);
+
+ printf("%s", buffer->str);
+ g_string_free(buffer, TRUE);
fflush(stdout);
}
@@ -117,7 +118,7 @@ print_patch(xmlNode *patch)
static int
apply_patch(xmlNode *input, xmlNode *patch, gboolean as_cib)
{
- xmlNode *output = copy_xml(input);
+ xmlNode *output = pcmk__xml_copy(NULL, input);
int rc = xml_apply_patchset(output, patch, as_cib);
rc = pcmk_legacy2rc(rc);
@@ -133,7 +134,7 @@ apply_patch(xmlNode *input, xmlNode *patch, gboolean as_cib)
print_patch(output);
- version = crm_element_value(output, XML_ATTR_CRM_VERSION);
+ version = crm_element_value(output, PCMK_XA_CRM_FEATURE_SET);
buffer = calculate_xml_versioned_digest(output, FALSE, TRUE, version);
crm_trace("Digest: %s", pcmk__s(buffer, "<null>\n"));
free(buffer);
@@ -153,7 +154,7 @@ log_patch_cib_versions(xmlNode *patch)
xml_patch_versions(patch, add, del);
fmt = crm_element_value(patch, PCMK_XA_FORMAT);
- digest = crm_element_value(patch, XML_ATTR_DIGEST);
+ digest = crm_element_value(patch, PCMK__XA_DIGEST);
if (add[2] != del[2] || add[1] != del[1] || add[0] != del[0]) {
crm_info("Patch: --- %d.%d.%d %s", del[0], del[1], del[2], fmt);
@@ -168,7 +169,8 @@ strip_patch_cib_version(xmlNode *patch, const char **vfields, size_t nvfields)
crm_element_value_int(patch, PCMK_XA_FORMAT, &format);
if (format == 2) {
- xmlNode *version_xml = find_xml_node(patch, "version", FALSE);
+ xmlNode *version_xml = pcmk__xe_first_child(patch, PCMK_XE_VERSION,
+ NULL, NULL);
if (version_xml) {
free_xml(version_xml);
@@ -178,24 +180,24 @@ strip_patch_cib_version(xmlNode *patch, const char **vfields, size_t nvfields)
int i = 0;
const char *tags[] = {
- XML_TAG_DIFF_REMOVED,
- XML_TAG_DIFF_ADDED,
+ PCMK__XE_DIFF_REMOVED,
+ PCMK__XE_DIFF_ADDED,
};
for (i = 0; i < PCMK__NELEM(tags); i++) {
xmlNode *tmp = NULL;
int lpc;
- tmp = find_xml_node(patch, tags[i], FALSE);
+ tmp = pcmk__xe_first_child(patch, tags[i], NULL, NULL);
if (tmp) {
for (lpc = 0; lpc < nvfields; lpc++) {
- xml_remove_prop(tmp, vfields[lpc]);
+ pcmk__xe_remove_attr(tmp, vfields[lpc]);
}
- tmp = find_xml_node(tmp, XML_TAG_CIB, FALSE);
+ tmp = pcmk__xe_first_child(tmp, PCMK_XE_CIB, NULL, NULL);
if (tmp) {
for (lpc = 0; lpc < nvfields; lpc++) {
- xml_remove_prop(tmp, vfields[lpc]);
+ pcmk__xe_remove_attr(tmp, vfields[lpc]);
}
}
}
@@ -209,9 +211,9 @@ generate_patch(xmlNode *object_1, xmlNode *object_2, const char *xml_file_2,
gboolean as_cib, gboolean no_version)
{
const char *vfields[] = {
- XML_ATTR_GENERATION_ADMIN,
- XML_ATTR_GENERATION,
- XML_ATTR_NUMUPDATES,
+ PCMK_XA_ADMIN_EPOCH,
+ PCMK_XA_EPOCH,
+ PCMK_XA_NUM_UPDATES,
};
xmlNode *output = NULL;
@@ -328,25 +330,25 @@ main(int argc, char **argv)
}
if (options.raw_1) {
- object_1 = string2xml(options.xml_file_1);
+ object_1 = pcmk__xml_parse(options.xml_file_1);
} else if (options.use_stdin) {
fprintf(stderr, "Input first XML fragment:");
- object_1 = stdin2xml();
+ object_1 = pcmk__xml_read(NULL);
} else if (options.xml_file_1 != NULL) {
- object_1 = filename2xml(options.xml_file_1);
+ object_1 = pcmk__xml_read(options.xml_file_1);
}
if (options.raw_2) {
- object_2 = string2xml(options.xml_file_2);
+ object_2 = pcmk__xml_parse(options.xml_file_2);
} else if (options.use_stdin) {
fprintf(stderr, "Input second XML fragment:");
- object_2 = stdin2xml();
+ object_2 = pcmk__xml_read(NULL);
} else if (options.xml_file_2 != NULL) {
- object_2 = filename2xml(options.xml_file_2);
+ object_2 = pcmk__xml_read(options.xml_file_2);
}
if (object_1 == NULL) {
diff --git a/tools/crm_error.c b/tools/crm_error.c
index 8911eae..51a0051 100644
--- a/tools/crm_error.c
+++ b/tools/crm_error.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.
*
@@ -8,7 +8,7 @@
*/
#include <crm_internal.h>
-#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
#include <crm/common/cmdline_internal.h>
#include <crm/common/output_internal.h>
#include <crm/common/strings_internal.h>
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
index dbe76fc..85be8dc 100644
--- a/tools/crm_mon.c
+++ b/tools/crm_mon.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2023 the Pacemaker project contributors
+ * Copyright 2004-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -26,7 +26,6 @@
#include <signal.h>
#include <sys/utsname.h>
-#include <crm/msg_xml.h>
#include <crm/services.h>
#include <crm/lrmd.h>
#include <crm/common/cmdline_internal.h>
@@ -45,7 +44,7 @@
#include <crm/pengine/internal.h>
#include <pacemaker-internal.h>
#include <crm/stonith-ng.h>
-#include <crm/fencing/internal.h>
+#include <crm/fencing/internal.h> // stonith__*
#include "crm_mon.h"
@@ -121,19 +120,20 @@ crm_mon_disconnected_html(pcmk__output_t *out, va_list args)
out->reset(out);
}
- pcmk__output_create_xml_text_node(out, "span", "Not connected to CIB");
+ pcmk__output_create_xml_text_node(out, PCMK__XE_SPAN,
+ "Not connected to CIB");
if (desc != NULL) {
- pcmk__output_create_xml_text_node(out, "span", ": ");
- pcmk__output_create_xml_text_node(out, "span", desc);
+ pcmk__output_create_xml_text_node(out, PCMK__XE_SPAN, ": ");
+ pcmk__output_create_xml_text_node(out, PCMK__XE_SPAN, desc);
}
if (state != pcmk_pacemakerd_state_invalid) {
const char *state_s = pcmk__pcmkd_state_enum2friendly(state);
- pcmk__output_create_xml_text_node(out, "span", " (");
- pcmk__output_create_xml_text_node(out, "span", state_s);
- pcmk__output_create_xml_text_node(out, "span", ")");
+ pcmk__output_create_xml_text_node(out, PCMK__XE_SPAN, " (");
+ pcmk__output_create_xml_text_node(out, PCMK__XE_SPAN, state_s);
+ pcmk__output_create_xml_text_node(out, PCMK__XE_SPAN, ")");
}
out->finish(out, CRM_EX_DISCONNECT, true, NULL);
@@ -185,9 +185,9 @@ crm_mon_disconnected_xml(pcmk__output_t *out, va_list args)
state_s = pcmk_pacemakerd_api_daemon_state_enum2text(state);
}
- pcmk__output_create_xml_node(out, "crm-mon-disconnected",
- XML_ATTR_DESC, desc,
- "pacemakerd-state", state_s,
+ pcmk__output_create_xml_node(out, PCMK_XE_CRM_MON_DISCONNECTED,
+ PCMK_XA_DESCRIPTION, desc,
+ PCMK_XA_PACEMAKERD_STATE, state_s,
NULL);
out->finish(out, CRM_EX_DISCONNECT, true, NULL);
@@ -284,7 +284,7 @@ struct {
{ "dc", pcmk_section_dc },
{ "failcounts", pcmk_section_failcounts },
{ "failures", pcmk_section_failures },
- { PCMK__VALUE_FENCING, pcmk_section_fencing_all },
+ { PCMK_VALUE_FENCING, pcmk_section_fencing_all },
{ "fencing-failed", pcmk_section_fence_failed },
{ "fencing-pending", pcmk_section_fence_pending },
{ "fencing-succeeded", pcmk_section_fence_worked },
@@ -322,7 +322,7 @@ apply_exclude(const gchar *excludes, GError **error) {
if (pcmk__str_eq(*s, "all", pcmk__str_none)) {
show = 0;
- } else if (pcmk__str_eq(*s, PCMK__VALUE_NONE, pcmk__str_none)) {
+ } else if (pcmk__str_eq(*s, PCMK_VALUE_NONE, pcmk__str_none)) {
show = all_includes(output_format);
} else if (bit != 0) {
show &= ~bit;
@@ -331,7 +331,7 @@ apply_exclude(const gchar *excludes, GError **error) {
"--exclude options: all, attributes, bans, counts, dc, "
"failcounts, failures, fencing, fencing-failed, "
"fencing-pending, fencing-succeeded, maint-mode, nodes, "
- PCMK__VALUE_NONE ", operations, options, resources, "
+ PCMK_VALUE_NONE ", operations, options, resources, "
"stack, summary, tickets, times");
result = FALSE;
break;
@@ -362,19 +362,19 @@ apply_include(const gchar *includes, GError **error) {
if (strlen(*s) > 4 && (*s)[4] == ':') {
options.neg_location_prefix = strdup(*s+5);
}
- } else if (pcmk__str_any_of(*s, "default", "defaults", NULL)) {
+ } else if (pcmk__str_any_of(*s, PCMK_VALUE_DEFAULT, "defaults", NULL)) {
show |= default_includes(output_format);
- } else if (pcmk__str_eq(*s, PCMK__VALUE_NONE, pcmk__str_none)) {
+ } else if (pcmk__str_eq(*s, PCMK_VALUE_NONE, pcmk__str_none)) {
show = 0;
} else if (bit != 0) {
show |= bit;
} else {
g_set_error(error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
"--include options: all, attributes, bans[:PREFIX], counts, dc, "
- "default, failcounts, failures, fencing, fencing-failed, "
- "fencing-pending, fencing-succeeded, maint-mode, nodes, "
- PCMK__VALUE_NONE ", operations, options, resources, "
- "stack, summary, tickets, times");
+ PCMK_VALUE_DEFAULT ", failcounts, failures, fencing, "
+ "fencing-failed, fencing-pending, fencing-succeeded, "
+ "maint-mode, nodes, " PCMK_VALUE_NONE ", operations, "
+ "options, resources, stack, summary, tickets, times");
result = FALSE;
break;
}
@@ -471,13 +471,13 @@ fence_history_cb(const gchar *option_name, const gchar *optarg, gpointer data, G
case 3:
options.fence_connect = TRUE;
fence_history = pcmk__fence_history_full;
- return include_exclude_cb("--include", PCMK__VALUE_FENCING, data,
+ return include_exclude_cb("--include", PCMK_VALUE_FENCING, data,
err);
case 2:
options.fence_connect = TRUE;
fence_history = pcmk__fence_history_full;
- return include_exclude_cb("--include", PCMK__VALUE_FENCING, data,
+ return include_exclude_cb("--include", PCMK_VALUE_FENCING, data,
err);
case 1:
@@ -488,7 +488,7 @@ fence_history_cb(const gchar *option_name, const gchar *optarg, gpointer data, G
case 0:
options.fence_connect = FALSE;
fence_history = pcmk__fence_history_none;
- return include_exclude_cb("--exclude", PCMK__VALUE_FENCING, data,
+ return include_exclude_cb("--exclude", PCMK_VALUE_FENCING, data,
err);
default:
@@ -553,7 +553,7 @@ reconnect_cb(const gchar *option_name, const gchar *optarg, gpointer data, GErro
g_set_error(err, PCMK__EXITC_ERROR, CRM_EX_INVALID_PARAM, "Invalid value for -i: %s", optarg);
return FALSE;
} else {
- options.reconnect_ms = crm_parse_interval_spec(optarg);
+ pcmk_parse_interval_spec(optarg, &options.reconnect_ms);
if (options.exec_mode != mon_exec_daemonized) {
// Reconnect interval applies to daemonized too, so don't override
@@ -756,7 +756,7 @@ static GOptionEntry display_entries[] = {
NULL },
{ "pending", 'j', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &options.print_pending,
- "Display pending state if 'record-pending' is enabled",
+ "Display pending state if '" PCMK_META_RECORD_PENDING "' is enabled",
NULL },
{ NULL }
@@ -854,8 +854,12 @@ mon_cib_connection_destroy(gpointer user_data)
/* the client API won't properly reconnect notifications if they are still
* in the table - so remove them
*/
- stonith_api_delete(st);
- st = NULL;
+ if (st != NULL) {
+ if (st->state != stonith_disconnected) {
+ st->cmds->disconnect(st);
+ }
+ st->cmds->remove_notification(st, NULL);
+ }
if (cib) {
cib->cmds->signoff(cib);
@@ -918,13 +922,17 @@ setup_fencer_connection(void)
if (rc == pcmk_ok) {
crm_trace("Setting up stonith callbacks");
if (options.watch_fencing) {
- st->cmds->register_notification(st, T_STONITH_NOTIFY_DISCONNECT,
+ st->cmds->register_notification(st,
+ PCMK__VALUE_ST_NOTIFY_DISCONNECT,
+ mon_st_callback_event);
+ st->cmds->register_notification(st, PCMK__VALUE_ST_NOTIFY_FENCE,
mon_st_callback_event);
- st->cmds->register_notification(st, T_STONITH_NOTIFY_FENCE, mon_st_callback_event);
} else {
- st->cmds->register_notification(st, T_STONITH_NOTIFY_DISCONNECT,
+ st->cmds->register_notification(st,
+ PCMK__VALUE_ST_NOTIFY_DISCONNECT,
+ mon_st_callback_display);
+ st->cmds->register_notification(st, PCMK__VALUE_ST_NOTIFY_HISTORY,
mon_st_callback_display);
- st->cmds->register_notification(st, T_STONITH_NOTIFY_HISTORY, mon_st_callback_display);
}
} else {
stonith_api_delete(st);
@@ -960,10 +968,11 @@ setup_cib_connection(void)
}
if (rc == pcmk_rc_ok) {
- cib->cmds->del_notify_callback(cib, T_CIB_DIFF_NOTIFY,
+ cib->cmds->del_notify_callback(cib, PCMK__VALUE_CIB_DIFF_NOTIFY,
crm_diff_update);
- rc = pcmk_legacy2rc(cib->cmds->add_notify_callback(cib,
- T_CIB_DIFF_NOTIFY, crm_diff_update));
+ rc = cib->cmds->add_notify_callback(cib, PCMK__VALUE_CIB_DIFF_NOTIFY,
+ crm_diff_update);
+ rc = pcmk_legacy2rc(rc);
}
if (rc != pcmk_rc_ok) {
@@ -1088,6 +1097,28 @@ detect_user_input(GIOChannel *channel, GIOCondition condition, gpointer user_dat
{
int c;
gboolean config_mode = FALSE;
+ gboolean rc = G_SOURCE_CONTINUE;
+
+ /* If the attached pty device (pseudo-terminal) has been closed/deleted,
+ * the condition (G_IO_IN | G_IO_ERR | G_IO_HUP) occurs.
+ * Exit with an error, otherwise the process would persist in the
+ * background and significantly raise the CPU usage.
+ */
+ if ((condition & G_IO_ERR) && (condition & G_IO_HUP)) {
+ rc = G_SOURCE_REMOVE;
+ clean_up(CRM_EX_IOERR);
+ }
+
+ /* The connection/fd has been closed. Refresh the screen and remove this
+ * event source hence ignore stdin.
+ */
+ if (condition & (G_IO_HUP | G_IO_NVAL)) {
+ rc = G_SOURCE_REMOVE;
+ }
+
+ if ((condition & G_IO_IN) == 0) {
+ return rc;
+ }
while (1) {
@@ -1194,7 +1225,7 @@ detect_user_input(GIOChannel *channel, GIOCondition condition, gpointer user_dat
refresh:
refresh_after_event(FALSE, TRUE);
- return TRUE;
+ return rc;
}
#endif // CURSES_ENABLED
@@ -1313,27 +1344,11 @@ static void
add_output_args(void) {
GError *err = NULL;
- if (output_format == mon_output_plain) {
- if (!pcmk__force_args(context, &err, "%s --text-fancy", g_get_prgname())) {
- g_propagate_error(&error, err);
- clean_up(CRM_EX_USAGE);
- }
- } else if (output_format == mon_output_cgi) {
+ if (output_format == mon_output_cgi) {
if (!pcmk__force_args(context, &err, "%s --html-cgi", g_get_prgname())) {
g_propagate_error(&error, err);
clean_up(CRM_EX_USAGE);
}
- } else if (output_format == mon_output_xml) {
- if (!pcmk__force_args(context, &err, "%s --xml-simple-list --xml-substitute", g_get_prgname())) {
- g_propagate_error(&error, err);
- clean_up(CRM_EX_USAGE);
- }
- } else if (output_format == mon_output_legacy_xml) {
- output_format = mon_output_xml;
- if (!pcmk__force_args(context, &err, "%s --xml-legacy --xml-substitute", g_get_prgname())) {
- g_propagate_error(&error, err);
- clean_up(CRM_EX_USAGE);
- }
}
}
@@ -1359,7 +1374,7 @@ reconcile_output_format(pcmk__common_args_t *args)
return;
}
- if (pcmk__str_eq(args->output_ty, "none", pcmk__str_none)) {
+ if (pcmk__str_eq(args->output_ty, PCMK_VALUE_NONE, pcmk__str_none)) {
output_format = mon_output_none;
} else if (pcmk__str_eq(args->output_ty, "html", pcmk__str_none)) {
@@ -1582,8 +1597,6 @@ main(int argc, char **argv)
set_default_exec_mode(args);
add_output_args();
- /* output_format MUST NOT BE CHANGED AFTER THIS POINT. */
-
rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
if (rc != pcmk_rc_ok) {
g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_ERROR, "Error creating output format %s: %s",
@@ -1591,11 +1604,22 @@ main(int argc, char **argv)
return clean_up(CRM_EX_ERROR);
}
+ if (output_format == mon_output_legacy_xml) {
+ output_format = mon_output_xml;
+ pcmk__output_set_legacy_xml(out);
+ }
+
+ /* output_format MUST NOT BE CHANGED AFTER THIS POINT. */
+
/* If we had a valid format for pcmk__output_new(), output_format should be
* set by now.
*/
CRM_ASSERT(output_format != mon_output_unset);
+ if (output_format == mon_output_plain) {
+ pcmk__output_text_set_fancy(out, true);
+ }
+
if (options.exec_mode == mon_exec_daemonized) {
if (!options.external_agent && (output_format == mon_output_none)) {
g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
@@ -1670,10 +1694,16 @@ main(int argc, char **argv)
show_opts |= pcmk_show_inactive_rscs | pcmk_show_timing;
}
- if ((output_format == mon_output_html || output_format == mon_output_cgi) &&
- out->dest != stdout) {
- pcmk__html_add_header("meta", "http-equiv", "refresh", "content",
- pcmk__itoa(options.reconnect_ms / 1000), NULL);
+ if ((output_format == mon_output_html || output_format == mon_output_cgi)
+ && (out->dest != stdout)) {
+
+ char *content = pcmk__itoa(options.reconnect_ms / 1000);
+
+ pcmk__html_add_header(PCMK__XE_META,
+ PCMK__XA_HTTP_EQUIV, PCMK__VALUE_REFRESH,
+ PCMK__XA_CONTENT, content,
+ NULL);
+ free(content);
}
#ifdef PCMK__COMPAT_2_0
@@ -1731,7 +1761,8 @@ main(int argc, char **argv)
ncurses_winch_handler = NULL;
io_channel = g_io_channel_unix_new(STDIN_FILENO);
- g_io_add_watch(io_channel, G_IO_IN, detect_user_input, NULL);
+ g_io_add_watch(io_channel, (G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL),
+ detect_user_input, NULL);
}
#endif
@@ -1743,10 +1774,6 @@ main(int argc, char **argv)
g_main_loop_run(mainloop);
g_main_loop_unref(mainloop);
- if (io_channel != NULL) {
- g_io_channel_shutdown(io_channel, TRUE, NULL);
- }
-
crm_info("Exiting %s", crm_system_name);
return clean_up(CRM_EX_OK);
@@ -1785,7 +1812,7 @@ send_custom_trap(const char *node, const char *rsc, const char *task, int target
if (pid == 0) {
/* crm_debug("notification: I am the child. Executing the nofitication program."); */
execl(options.external_agent, options.external_agent, NULL);
- exit(CRM_EX_ERROR);
+ crm_exit(CRM_EX_ERROR);
}
crm_trace("Finished running custom notification program '%s'.", options.external_agent);
@@ -1814,14 +1841,14 @@ handle_rsc_op(xmlNode *xml, void *userdata)
xmlNode *n = xml;
xmlNode * rsc_op = xml;
- if(strcmp((const char*)xml->name, XML_LRM_TAG_RSC_OP) != 0) {
+ if(strcmp((const char*)xml->name, PCMK__XE_LRM_RSC_OP) != 0) {
pcmk__xe_foreach_child(xml, NULL, handle_rsc_op, (void *) node_id);
return pcmk_rc_ok;
}
- id = pe__xe_history_key(rsc_op);
+ id = pcmk__xe_history_key(rsc_op);
- magic = crm_element_value(rsc_op, XML_ATTR_TRANSITION_MAGIC);
+ magic = crm_element_value(rsc_op, PCMK__XA_TRANSITION_MAGIC);
if (magic == NULL) {
/* non-change */
return pcmk_rc_ok;
@@ -1838,18 +1865,18 @@ handle_rsc_op(xmlNode *xml, void *userdata)
goto bail;
}
- node = crm_element_value(rsc_op, XML_LRM_ATTR_TARGET);
+ node = crm_element_value(rsc_op, PCMK__META_ON_NODE);
- while ((n != NULL) && !pcmk__xe_is(n, XML_CIB_TAG_STATE)) {
+ while ((n != NULL) && !pcmk__xe_is(n, PCMK__XE_NODE_STATE)) {
n = n->parent;
}
if(node == NULL && n) {
- node = crm_element_value(n, XML_ATTR_UNAME);
+ node = crm_element_value(n, PCMK_XA_UNAME);
}
if (node == NULL && n) {
- node = ID(n);
+ node = pcmk__xe_id(n);
}
if (node == NULL) {
@@ -1902,101 +1929,107 @@ mon_trigger_refresh(gpointer user_data)
static int
handle_op_for_node(xmlNode *xml, void *userdata)
{
- const char *node = crm_element_value(xml, XML_ATTR_UNAME);
+ const char *node = crm_element_value(xml, PCMK_XA_UNAME);
if (node == NULL) {
- node = ID(xml);
+ node = pcmk__xe_id(xml);
}
handle_rsc_op(xml, (void *) node);
return pcmk_rc_ok;
}
-static void
-crm_diff_update_v2(const char *event, xmlNode * msg)
+static int
+crm_diff_update_element_v2(xmlNode *change, void *userdata)
{
- xmlNode *change = NULL;
- xmlNode *diff = get_message_xml(msg, F_CIB_UPDATE_RESULT);
-
- for (change = pcmk__xml_first_child(diff); change != NULL;
- change = pcmk__xml_next(change)) {
- const char *name = NULL;
- const char *op = crm_element_value(change, XML_DIFF_OP);
- const char *xpath = crm_element_value(change, XML_DIFF_PATH);
- xmlNode *match = NULL;
- const char *node = NULL;
-
- if(op == NULL) {
- continue;
-
- } else if(strcmp(op, "create") == 0) {
- match = change->children;
+ const char *name = NULL;
+ const char *op = crm_element_value(change, PCMK_XA_OPERATION);
+ const char *xpath = crm_element_value(change, PCMK_XA_PATH);
+ xmlNode *match = NULL;
+ const char *node = NULL;
- } else if(strcmp(op, "move") == 0) {
- continue;
+ if (op == NULL) {
+ return pcmk_rc_ok;
- } else if(strcmp(op, "delete") == 0) {
- continue;
+ } else if (strcmp(op, PCMK_VALUE_CREATE) == 0) {
+ match = change->children;
- } else if(strcmp(op, "modify") == 0) {
- match = first_named_child(change, XML_DIFF_RESULT);
- if(match) {
- match = match->children;
- }
- }
+ } else if (pcmk__str_any_of(op, PCMK_VALUE_MOVE, PCMK_VALUE_DELETE,
+ NULL)) {
+ return pcmk_rc_ok;
+ } else if (strcmp(op, PCMK_VALUE_MODIFY) == 0) {
+ match = pcmk__xe_first_child(change, PCMK_XE_CHANGE_RESULT, NULL, NULL);
if(match) {
- name = (const char *)match->name;
+ match = match->children;
}
+ }
- crm_trace("Handling %s operation for %s %p, %s", op, xpath, match, name);
- if(xpath == NULL) {
- /* Version field, ignore */
+ if(match) {
+ name = (const char *)match->name;
+ }
- } else if(name == NULL) {
- crm_debug("No result for %s operation to %s", op, xpath);
- CRM_ASSERT(strcmp(op, "delete") == 0 || strcmp(op, "move") == 0);
+ crm_trace("Handling %s operation for %s %p, %s", op, xpath, match, name);
+ if(xpath == NULL) {
+ /* Version field, ignore */
- } else if(strcmp(name, XML_TAG_CIB) == 0) {
- pcmk__xe_foreach_child(first_named_child(match, XML_CIB_TAG_STATUS),
- NULL, handle_op_for_node, NULL);
+ } else if(name == NULL) {
+ crm_debug("No result for %s operation to %s", op, xpath);
+ CRM_ASSERT(pcmk__str_any_of(op, PCMK_VALUE_MOVE, PCMK_VALUE_DELETE,
+ NULL));
- } else if(strcmp(name, XML_CIB_TAG_STATUS) == 0) {
- pcmk__xe_foreach_child(match, NULL, handle_op_for_node, NULL);
+ } else if (strcmp(name, PCMK_XE_CIB) == 0) {
+ pcmk__xe_foreach_child(pcmk__xe_first_child(match, PCMK_XE_STATUS, NULL,
+ NULL),
+ NULL, handle_op_for_node, NULL);
- } else if(strcmp(name, XML_CIB_TAG_STATE) == 0) {
- node = crm_element_value(match, XML_ATTR_UNAME);
- if (node == NULL) {
- node = ID(match);
- }
- handle_rsc_op(match, (void *) node);
+ } else if (strcmp(name, PCMK_XE_STATUS) == 0) {
+ pcmk__xe_foreach_child(match, NULL, handle_op_for_node, NULL);
- } else if(strcmp(name, XML_CIB_TAG_LRM) == 0) {
- node = ID(match);
- handle_rsc_op(match, (void *) node);
+ } else if (strcmp(name, PCMK__XE_NODE_STATE) == 0) {
+ node = crm_element_value(match, PCMK_XA_UNAME);
+ if (node == NULL) {
+ node = pcmk__xe_id(match);
+ }
+ handle_rsc_op(match, (void *) node);
- } else if(strcmp(name, XML_LRM_TAG_RESOURCES) == 0) {
- char *local_node = pcmk__xpath_node_id(xpath, "lrm");
+ } else if (strcmp(name, PCMK__XE_LRM) == 0) {
+ node = pcmk__xe_id(match);
+ handle_rsc_op(match, (void *) node);
- handle_rsc_op(match, local_node);
- free(local_node);
+ } else if (strcmp(name, PCMK__XE_LRM_RESOURCES) == 0) {
+ char *local_node = pcmk__xpath_node_id(xpath, PCMK__XE_LRM);
- } else if(strcmp(name, XML_LRM_TAG_RESOURCE) == 0) {
- char *local_node = pcmk__xpath_node_id(xpath, "lrm");
+ handle_rsc_op(match, local_node);
+ free(local_node);
- handle_rsc_op(match, local_node);
- free(local_node);
+ } else if (strcmp(name, PCMK__XE_LRM_RESOURCE) == 0) {
+ char *local_node = pcmk__xpath_node_id(xpath, PCMK__XE_LRM);
- } else if(strcmp(name, XML_LRM_TAG_RSC_OP) == 0) {
- char *local_node = pcmk__xpath_node_id(xpath, "lrm");
+ handle_rsc_op(match, local_node);
+ free(local_node);
- handle_rsc_op(match, local_node);
- free(local_node);
+ } else if (strcmp(name, PCMK__XE_LRM_RSC_OP) == 0) {
+ char *local_node = pcmk__xpath_node_id(xpath, PCMK__XE_LRM);
- } else {
- crm_trace("Ignoring %s operation for %s %p, %s", op, xpath, match, name);
- }
+ handle_rsc_op(match, local_node);
+ free(local_node);
+
+ } else {
+ crm_trace("Ignoring %s operation for %s %p, %s", op, xpath, match, name);
}
+
+ return pcmk_rc_ok;
+}
+
+static void
+crm_diff_update_v2(const char *event, xmlNode * msg)
+{
+ xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_CIB_UPDATE_RESULT,
+ NULL, NULL);
+ xmlNode *diff = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
+
+ pcmk__xe_foreach_child(diff, NULL, crm_diff_update_element_v2, NULL);
}
static void
@@ -2004,8 +2037,9 @@ crm_diff_update_v1(const char *event, xmlNode * msg)
{
/* Process operation updates */
xmlXPathObject *xpathObj = xpath_search(msg,
- "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED
- "//" XML_LRM_TAG_RSC_OP);
+ "//" PCMK__XE_CIB_UPDATE_RESULT
+ "//" PCMK__XE_DIFF_ADDED
+ "//" PCMK__XE_LRM_RSC_OP);
int lpc = 0, max = numXpathResults(xpathObj);
for (lpc = 0; lpc < max; lpc++) {
@@ -2022,7 +2056,9 @@ crm_diff_update(const char *event, xmlNode * msg)
int rc = -1;
static bool stale = FALSE;
gboolean cib_updated = FALSE;
- xmlNode *diff = get_message_xml(msg, F_CIB_UPDATE_RESULT);
+ xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_CIB_UPDATE_RESULT,
+ NULL, NULL);
+ xmlNode *diff = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
out->progress(out, false);
@@ -2218,6 +2254,10 @@ clean_up(crm_exit_t exit_code)
/* Quitting crm_mon is much more complicated than it ought to be. */
/* (1) Close connections, free things, etc. */
+ if (io_channel != NULL) {
+ g_io_channel_shutdown(io_channel, TRUE, NULL);
+ }
+
cib__clean_up_connection(&cib);
stonith_api_delete(st);
free(options.neg_location_prefix);
diff --git a/tools/crm_mon.h b/tools/crm_mon.h
index c87432d..2228add 100644
--- a/tools/crm_mon.h
+++ b/tools/crm_mon.h
@@ -71,8 +71,7 @@ void curses_formatted_vprintf(pcmk__output_t *out, const char *format, va_list a
void curses_indented_printf(pcmk__output_t *out, const char *format, ...) G_GNUC_PRINTF(2, 3);
void curses_indented_vprintf(pcmk__output_t *out, const char *format, va_list args) G_GNUC_PRINTF(2, 0);
-extern GOptionEntry crm_mon_curses_output_entries[];
-#define CRM_MON_SUPPORTED_FORMAT_CURSES { "console", crm_mon_mk_curses_output, crm_mon_curses_output_entries }
+#define CRM_MON_SUPPORTED_FORMAT_CURSES { "console", crm_mon_mk_curses_output, NULL }
#endif
#endif
diff --git a/tools/crm_mon_curses.c b/tools/crm_mon_curses.c
index 212a400..4fc09ab 100644
--- a/tools/crm_mon_curses.c
+++ b/tools/crm_mon_curses.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2023 the Pacemaker project contributors
+ * Copyright 2019-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -15,7 +15,7 @@
#include <crm/common/output.h>
#include <crm/common/cmdline_internal.h>
#include <crm/stonith-ng.h>
-#include <crm/fencing/internal.h>
+#include <crm/fencing/internal.h> // stonith__history_description()
#include <crm/pengine/internal.h>
#include <glib.h>
#include <pacemaker-internal.h>
@@ -24,10 +24,6 @@
#if CURSES_ENABLED
-GOptionEntry crm_mon_curses_output_entries[] = {
- { NULL }
-};
-
typedef struct curses_list_data_s {
unsigned int len;
char *singular_noun;
@@ -39,6 +35,14 @@ typedef struct private_data_s {
} private_data_t;
static void
+free_list_data(gpointer data) {
+ curses_list_data_t *list_data = data;
+
+ free(list_data->singular_noun);
+ free(list_data->plural_noun);
+}
+
+static void
curses_free_priv(pcmk__output_t *out) {
private_data_t *priv = NULL;
@@ -48,7 +52,7 @@ curses_free_priv(pcmk__output_t *out) {
priv = out->priv;
- g_queue_free(priv->parent_q);
+ g_queue_free_full(priv->parent_q, free_list_data);
free(priv);
out->priv = NULL;
}
@@ -201,10 +205,10 @@ curses_begin_list(pcmk__output_t *out, const char *singular_noun, const char *pl
va_end(ap);
}
- new_list = calloc(1, sizeof(curses_list_data_t));
+ new_list = pcmk__assert_alloc(1, sizeof(curses_list_data_t));
new_list->len = 0;
- pcmk__str_update(&new_list->singular_noun, singular_noun);
- pcmk__str_update(&new_list->plural_noun, plural_noun);
+ new_list->singular_noun = pcmk__str_copy(singular_noun);
+ new_list->plural_noun = pcmk__str_copy(plural_noun);
g_queue_push_tail(priv->parent_q, new_list);
}
@@ -262,7 +266,7 @@ curses_end_list(pcmk__output_t *out) {
}
}
- free(node);
+ free_list_data(node);
}
static bool
@@ -310,7 +314,7 @@ curses_prompt(const char *prompt, bool do_echo, char **dest)
free(*dest);
}
- *dest = calloc(1, 1024);
+ *dest = pcmk__assert_alloc(1, 1024);
/* On older systems, scanw is defined as taking a char * for its first argument,
* while newer systems rightly want a const char *. Accomodate both here due
* to building with -Werror.
diff --git a/tools/crm_node.c b/tools/crm_node.c
index 1e7ce6c..3a8d2d1 100644
--- a/tools/crm_node.c
+++ b/tools/crm_node.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2023 the Pacemaker project contributors
+ * Copyright 2004-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -19,11 +19,11 @@
#include <crm/common/cmdline_internal.h>
#include <crm/common/output_internal.h>
#include <crm/common/mainloop.h>
-#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
#include <crm/cib.h>
#include <crm/cib/internal.h>
#include <crm/common/ipc_controld.h>
-#include <crm/common/attrd_internal.h>
+#include <crm/common/attrs_internal.h>
#include <pacemaker-internal.h>
@@ -159,17 +159,17 @@ node_id_xml(pcmk__output_t *out, va_list args) {
char *id_s = crm_strdup_printf("%" PRIu32, node_id);
- pcmk__output_create_xml_node(out, "node-info",
- "nodeid", id_s,
+ pcmk__output_create_xml_node(out, PCMK_XE_NODE_INFO,
+ PCMK_XA_NODEID, id_s,
NULL);
free(id_s);
return pcmk_rc_ok;
}
-PCMK__OUTPUT_ARGS("node-list", "GList *")
+PCMK__OUTPUT_ARGS("simple-node-list", "GList *")
static int
-node_list_default(pcmk__output_t *out, va_list args)
+simple_node_list_default(pcmk__output_t *out, va_list args)
{
GList *nodes = va_arg(args, GList *);
@@ -182,22 +182,22 @@ node_list_default(pcmk__output_t *out, va_list args)
return pcmk_rc_ok;
}
-PCMK__OUTPUT_ARGS("node-list", "GList *")
+PCMK__OUTPUT_ARGS("simple-node-list", "GList *")
static int
-node_list_xml(pcmk__output_t *out, va_list args)
+simple_node_list_xml(pcmk__output_t *out, va_list args)
{
GList *nodes = va_arg(args, GList *);
- out->begin_list(out, NULL, NULL, "nodes");
+ out->begin_list(out, NULL, NULL, PCMK_XE_NODES);
for (GList *node_iter = nodes; node_iter != NULL; node_iter = node_iter->next) {
pcmk_controld_api_node_t *node = node_iter->data;
char *id_s = crm_strdup_printf("%" PRIu32, node->id);
- pcmk__output_create_xml_node(out, "node",
- "id", id_s,
- "name", node->uname,
- "state", node->state,
+ pcmk__output_create_xml_node(out, PCMK_XE_NODE,
+ PCMK_XA_ID, id_s,
+ PCMK_XA_NAME, node->uname,
+ PCMK_XA_STATE, node->state,
NULL);
free(id_s);
@@ -226,9 +226,9 @@ node_name_xml(pcmk__output_t *out, va_list args) {
char *id_s = crm_strdup_printf("%" PRIu32, node_id);
- pcmk__output_create_xml_node(out, "node-info",
- "nodeid", id_s,
- XML_ATTR_UNAME, node_name,
+ pcmk__output_create_xml_node(out, PCMK_XE_NODE_INFO,
+ PCMK_XA_NODEID, id_s,
+ PCMK_XA_UNAME, node_name,
NULL);
free(id_s);
@@ -265,7 +265,7 @@ partition_list_xml(pcmk__output_t *out, va_list args)
{
GList *nodes = va_arg(args, GList *);
- out->begin_list(out, NULL, NULL, "nodes");
+ out->begin_list(out, NULL, NULL, PCMK_XE_NODES);
for (GList *node_iter = nodes; node_iter != NULL; node_iter = node_iter->next) {
pcmk_controld_api_node_t *node = node_iter->data;
@@ -273,10 +273,10 @@ partition_list_xml(pcmk__output_t *out, va_list args)
if (pcmk__str_eq(node->state, "member", pcmk__str_none)) {
char *id_s = crm_strdup_printf("%" PRIu32, node->id);
- pcmk__output_create_xml_node(out, "node",
- "id", id_s,
- "name", node->uname,
- "state", node->state,
+ pcmk__output_create_xml_node(out, PCMK_XE_NODE,
+ PCMK_XA_ID, id_s,
+ PCMK_XA_NAME, node->uname,
+ PCMK_XA_STATE, node->state,
NULL);
free(id_s);
}
@@ -300,8 +300,8 @@ static int
quorum_xml(pcmk__output_t *out, va_list args) {
bool have_quorum = va_arg(args, int);
- pcmk__output_create_xml_node(out, "cluster-info",
- "quorum", have_quorum ? "true" : "false",
+ pcmk__output_create_xml_node(out, PCMK_XE_CLUSTER_INFO,
+ PCMK_XA_QUORUM, pcmk__btoa(have_quorum),
NULL);
return pcmk_rc_ok;
}
@@ -309,14 +309,14 @@ quorum_xml(pcmk__output_t *out, va_list args) {
static pcmk__message_entry_t fmt_functions[] = {
{ "node-id", "default", node_id_default },
{ "node-id", "xml", node_id_xml },
- { "node-list", "default", node_list_default },
- { "node-list", "xml", node_list_xml },
{ "node-name", "default", node_name_default },
{ "node-name", "xml", node_name_xml },
- { "quorum", "default", quorum_default },
- { "quorum", "xml", quorum_xml },
{ "partition-list", "default", partition_list_default },
{ "partition-list", "xml", partition_list_xml },
+ { "quorum", "default", quorum_default },
+ { "quorum", "xml", quorum_xml },
+ { "simple-node-list", "default", simple_node_list_default },
+ { "simple-node-list", "xml", simple_node_list_xml },
{ NULL, NULL, NULL }
};
@@ -374,7 +374,7 @@ controller_event_cb(pcmk_ipc_api_t *controld_api,
if (options.command == 'p') {
out->message(out, "partition-list", reply->data.nodes);
} else if (options.command == 'l') {
- out->message(out, "node-list", reply->data.nodes);
+ out->message(out, "simple-node-list", reply->data.nodes);
}
// Success
@@ -465,10 +465,11 @@ print_node_name(uint32_t nodeid)
if (nodeid == 0) {
// Check environment first (i.e. when called by resource agent)
- const char *name = getenv("OCF_RESKEY_" CRM_META "_" XML_LRM_ATTR_TARGET);
+ const char *name = getenv("OCF_RESKEY_" CRM_META "_"
+ PCMK__META_ON_NODE);
if (name != NULL) {
- rc = out->message(out, "node-name", 0, name);
+ rc = out->message(out, "node-name", 0UL, name);
goto done;
}
}
@@ -485,7 +486,7 @@ print_node_name(uint32_t nodeid)
return;
}
- rc = out->message(out, "node-name", 0, node_name);
+ rc = out->message(out, "node-name", 0UL, node_name);
done:
if (node_name != NULL) {
@@ -543,17 +544,14 @@ static int
remove_from_section(cib_t *cib, const char *element, const char *section,
const char *node_name, long node_id)
{
- xmlNode *xml = NULL;
int rc = pcmk_rc_ok;
+ xmlNode *xml = pcmk__xe_create(NULL, element);
- xml = create_xml_node(NULL, element);
- if (xml == NULL) {
- return pcmk_rc_error;
- }
- crm_xml_add(xml, XML_ATTR_UNAME, node_name);
+ crm_xml_add(xml, PCMK_XA_UNAME, node_name);
if (node_id > 0) {
crm_xml_set_id(xml, "%ld", node_id);
}
+
rc = cib->cmds->remove(cib, section, xml, cib_transaction);
free_xml(xml);
return (rc >= 0)? pcmk_rc_ok : pcmk_legacy2rc(rc);
@@ -592,10 +590,10 @@ purge_node_from_cib(const char *node_name, long node_id)
}
// Remove from configuration and status
- rc = remove_from_section(cib, XML_CIB_TAG_NODE, XML_CIB_TAG_NODES,
- node_name, node_id);
+ rc = remove_from_section(cib, PCMK_XE_NODE, PCMK_XE_NODES, node_name,
+ node_id);
if (rc == pcmk_rc_ok) {
- rc = remove_from_section(cib, XML_CIB_TAG_STATE, XML_CIB_TAG_STATUS,
+ rc = remove_from_section(cib, PCMK__XE_NODE_STATE, PCMK_XE_STATUS,
node_name, node_id);
}
@@ -693,7 +691,7 @@ purge_node_from_fencer(const char *node_name, long node_id)
if (node_id > 0) {
crm_xml_set_id(cmd, "%ld", node_id);
}
- crm_xml_add(cmd, XML_ATTR_UNAME, node_name);
+ crm_xml_add(cmd, PCMK_XA_UNAME, node_name);
rc = crm_ipc_send(conn, cmd, 0, 0, NULL);
if (rc >= 0) {
@@ -806,11 +804,6 @@ main(int argc, char **argv)
goto done;
}
- if (!pcmk__force_args(context, &error, "%s --xml-simple-list", g_get_prgname())) {
- exit_code = CRM_EX_SOFTWARE;
- goto done;
- }
-
if (args->version) {
out->version(out, false);
goto done;
diff --git a/tools/crm_resource.c b/tools/crm_resource.c
index 7c4a0a1..c592e86 100644
--- a/tools/crm_resource.c
+++ b/tools/crm_resource.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2023 the Pacemaker project contributors
+ * Copyright 2004-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -18,6 +18,7 @@
#include <pacemaker-internal.h>
#include <sys/param.h>
+#include <stdint.h> // uint32_t
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
@@ -53,14 +54,15 @@ enum rsc_command {
cmd_list_all_ops,
cmd_list_alternatives,
cmd_list_instances,
+ cmd_list_options,
cmd_list_providers,
cmd_list_resources,
cmd_list_standards,
cmd_locate,
cmd_metadata,
cmd_move,
- cmd_query_raw_xml,
cmd_query_xml,
+ cmd_query_xml_raw,
cmd_refresh,
cmd_restart,
cmd_set_param,
@@ -72,18 +74,10 @@ enum rsc_command {
struct {
enum rsc_command rsc_cmd; // crm_resource command to perform
- // Infrastructure that given command needs to work
- gboolean require_cib; // Whether command requires CIB IPC
- int cib_options; // Options to use with CIB IPC calls
- gboolean require_crmd; // Whether command requires controller IPC
- gboolean require_scheduler; // Whether command requires scheduler data
- gboolean require_resource; // Whether command requires resource specified
- gboolean require_node; // Whether command requires node specified
- int find_flags; // Flags to use when searching for resource
-
// Command-line option values
gchar *rsc_id; // Value of --resource
gchar *rsc_type; // Value of --resource-type
+ gboolean all; // --all was given
gboolean force; // --force was given
gboolean clear_expired; // --expired was given
gboolean recursive; // --recursive was given
@@ -92,18 +86,19 @@ struct {
gchar *interval_spec; // Value of --interval
gchar *move_lifetime; // Value of --lifetime
gchar *operation; // Value of --operation
+ enum pcmk__opt_flags opt_list; // Parsed from --list-options
const char *attr_set_type; // Instance, meta, utilization, or element attribute
gchar *prop_id; // --nvpair (attribute XML ID)
char *prop_name; // Attribute name
gchar *prop_set; // --set-name (attribute block XML ID)
gchar *prop_value; // --parameter-value (attribute value)
- int timeout_ms; // Parsed from --timeout value
+ guint timeout_ms; // Parsed from --timeout value
char *agent_spec; // Standard and/or provider and/or agent
gchar *xml_file; // Value of (deprecated) --xml-file
int check_level; // Optional value of --validate or --force-check
// Resource configuration specified via command-line arguments
- gboolean cmdline_config; // Resource configuration was via arguments
+ bool cmdline_config; // Resource configuration was via arguments
char *v_agent; // Value of --agent
char *v_class; // Value of --class
char *v_provider; // Value of --provider
@@ -113,66 +108,17 @@ struct {
gchar **remainder; // Positional arguments as given
GHashTable *override_params; // Resource parameter values that override config
} options = {
- .attr_set_type = XML_TAG_ATTR_SETS,
+ .attr_set_type = PCMK_XE_INSTANCE_ATTRIBUTES,
.check_level = -1,
- .cib_options = cib_sync_call,
- .require_cib = TRUE,
- .require_scheduler = TRUE,
- .require_resource = TRUE,
+ .rsc_cmd = cmd_list_resources, // List all resources if no command given
};
-#if 0
-// @COMPAT @TODO enable this at next backward compatibility break
-#define SET_COMMAND(cmd) do { \
- if (options.rsc_cmd != cmd_none) { \
- g_set_error(error, PCMK__EXITC_ERROR, CRM_EX_USAGE, \
- "Only one command option may be specified"); \
- return FALSE; \
- } \
- options.rsc_cmd = (cmd); \
- } while (0)
-#else
-#define SET_COMMAND(cmd) do { \
- if (options.rsc_cmd != cmd_none) { \
- reset_options(); \
- } \
- options.rsc_cmd = (cmd); \
- } while (0)
-#endif
-
-gboolean agent_provider_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
gboolean attr_set_type_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
-gboolean class_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
-gboolean cleanup_refresh_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
-gboolean delete_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
-gboolean expired_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
-gboolean list_agents_cb(const gchar *option_name, const gchar *optarg,
- gpointer data, GError **error);
-gboolean list_providers_cb(const gchar *option_name, const gchar *optarg,
- gpointer data, GError **error);
-gboolean list_standards_cb(const gchar *option_name, const gchar *optarg,
+gboolean cmdline_config_cb(const gchar *option_name, const gchar *optarg,
gpointer data, GError **error);
-gboolean list_alternatives_cb(const gchar *option_name, const gchar *optarg,
- gpointer data, GError **error);
-gboolean metadata_cb(const gchar *option_name, const gchar *optarg,
- gpointer data, GError **error);
gboolean option_cb(const gchar *option_name, const gchar *optarg,
gpointer data, GError **error);
-gboolean fail_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
-gboolean flag_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
-gboolean get_param_prop_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
-gboolean list_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
-gboolean set_delete_param_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
-gboolean set_prop_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
gboolean timeout_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
-gboolean validate_or_force_cb(const gchar *option_name, const gchar *optarg,
- gpointer data, GError **error);
-gboolean restart_cb(const gchar *option_name, const gchar *optarg,
- gpointer data, GError **error);
-gboolean digests_cb(const gchar *option_name, const gchar *optarg,
- gpointer data, GError **error);
-gboolean wait_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
-gboolean why_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
static crm_exit_t exit_code = CRM_EX_OK;
static pcmk__output_t *out = NULL;
@@ -326,77 +272,266 @@ build_constraint_list(xmlNode *root)
xmlXPathObjectPtr xpathObj = NULL;
int ndx = 0;
- cib_constraints = pcmk_find_cib_element(root, XML_CIB_TAG_CONSTRAINTS);
- xpathObj = xpath_search(cib_constraints, "//" XML_CONS_TAG_RSC_LOCATION);
+ cib_constraints = pcmk_find_cib_element(root, PCMK_XE_CONSTRAINTS);
+ xpathObj = xpath_search(cib_constraints, "//" PCMK_XE_RSC_LOCATION);
for (ndx = 0; ndx < numXpathResults(xpathObj); ndx++) {
xmlNode *match = getXpathResult(xpathObj, ndx);
- retval = g_list_insert_sorted(retval, (gpointer) ID(match), compare_id);
+ retval = g_list_insert_sorted(retval, (gpointer) pcmk__xe_id(match),
+ compare_id);
}
freeXpathObject(xpathObj);
return retval;
}
+static gboolean
+validate_opt_list(const gchar *optarg)
+{
+ if (pcmk__str_eq(optarg, PCMK_VALUE_FENCING, pcmk__str_none)) {
+ options.opt_list = pcmk__opt_fencing;
+
+ } else if (pcmk__str_eq(optarg, PCMK__VALUE_PRIMITIVE, pcmk__str_none)) {
+ options.opt_list = pcmk__opt_primitive;
+
+ } else {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*!
+ * \internal
+ * \brief Process options that set the command
+ *
+ * Nothing else should set \c options.rsc_cmd.
+ *
+ * \param[in] option_name Name of the option being parsed
+ * \param[in] optarg Value to be parsed
+ * \param[in] data Ignored
+ * \param[out] error Where to store recoverable error, if any
+ *
+ * \return \c TRUE if the option was successfully parsed, or \c FALSE if an
+ * error occurred, in which case \p *error is set
+ */
+static gboolean
+command_cb(const gchar *option_name, const gchar *optarg, gpointer data,
+ GError **error)
+{
+ // Sorted by enum rsc_command name
+ if (pcmk__str_any_of(option_name, "-B", "--ban", NULL)) {
+ options.rsc_cmd = cmd_ban;
+
+ } else if (pcmk__str_any_of(option_name, "-C", "--cleanup", NULL)) {
+ options.rsc_cmd = cmd_cleanup;
+
+ } else if (pcmk__str_any_of(option_name, "-U", "--clear", NULL)) {
+ options.rsc_cmd = cmd_clear;
+
+ } else if (pcmk__str_any_of(option_name, "-a", "--constraints", NULL)) {
+ options.rsc_cmd = cmd_colocations;
+
+ } else if (pcmk__str_any_of(option_name, "-A", "--stack", NULL)) {
+ options.rsc_cmd = cmd_colocations;
+ options.recursive = TRUE;
+
+ } else if (pcmk__str_any_of(option_name, "-c", "--list-cts", NULL)) {
+ options.rsc_cmd = cmd_cts;
+
+ } else if (pcmk__str_any_of(option_name, "-D", "--delete", NULL)) {
+ options.rsc_cmd = cmd_delete;
+
+ } else if (pcmk__str_any_of(option_name, "-d", "--delete-parameter",
+ NULL)) {
+ options.rsc_cmd = cmd_delete_param;
+ pcmk__str_update(&options.prop_name, optarg);
+
+ } else if (pcmk__str_eq(option_name, "--digests", pcmk__str_none)) {
+ options.rsc_cmd = cmd_digests;
+
+ if (options.override_params == NULL) {
+ options.override_params = pcmk__strkey_table(free, free);
+ }
+
+ } else if (pcmk__str_any_of(option_name,
+ "--force-demote", "--force-promote",
+ "--force-start", "--force-stop",
+ "--force-check", "--validate", NULL)) {
+ options.rsc_cmd = cmd_execute_agent;
+
+ g_free(options.operation);
+ options.operation = g_strdup(option_name + 2); // skip "--"
+
+ if (options.override_params == NULL) {
+ options.override_params = pcmk__strkey_table(free, free);
+ }
+
+ if (optarg != NULL) {
+ if (pcmk__scan_min_int(optarg, &options.check_level,
+ 0) != pcmk_rc_ok) {
+ g_set_error(error, G_OPTION_ERROR, CRM_EX_INVALID_PARAM,
+ _("Invalid check level setting: %s"), optarg);
+ return FALSE;
+ }
+ }
+
+ } else if (pcmk__str_any_of(option_name, "-F", "--fail", NULL)) {
+ options.rsc_cmd = cmd_fail;
+
+ } else if (pcmk__str_any_of(option_name, "-g", "--get-parameter", NULL)) {
+ options.rsc_cmd = cmd_get_param;
+ pcmk__str_update(&options.prop_name, optarg);
+
+ } else if (pcmk__str_any_of(option_name, "-G", "--get-property", NULL)) {
+ options.rsc_cmd = cmd_get_property;
+ pcmk__str_update(&options.prop_name, optarg);
+
+ } else if (pcmk__str_any_of(option_name, "-O", "--list-operations", NULL)) {
+ options.rsc_cmd = cmd_list_active_ops;
+
+ } else if (pcmk__str_eq(option_name, "--list-agents", pcmk__str_none)) {
+ options.rsc_cmd = cmd_list_agents;
+ pcmk__str_update(&options.agent_spec, optarg);
+
+ } else if (pcmk__str_any_of(option_name, "-o", "--list-all-operations",
+ NULL)) {
+ options.rsc_cmd = cmd_list_all_ops;
+
+ } else if (pcmk__str_eq(option_name, "--list-ocf-alternatives",
+ pcmk__str_none)) {
+ options.rsc_cmd = cmd_list_alternatives;
+ pcmk__str_update(&options.agent_spec, optarg);
+
+ } else if (pcmk__str_eq(option_name, "--list-options", pcmk__str_none)) {
+ options.rsc_cmd = cmd_list_options;
+ return validate_opt_list(optarg);
+
+ } else if (pcmk__str_any_of(option_name, "-l", "--list-raw", NULL)) {
+ options.rsc_cmd = cmd_list_instances;
+
+ } else if (pcmk__str_eq(option_name, "--list-ocf-providers",
+ pcmk__str_none)) {
+ options.rsc_cmd = cmd_list_providers;
+ pcmk__str_update(&options.agent_spec, optarg);
+
+ } else if (pcmk__str_any_of(option_name, "-L", "--list", NULL)) {
+ options.rsc_cmd = cmd_list_resources;
+
+ } else if (pcmk__str_eq(option_name, "--list-standards", pcmk__str_none)) {
+ options.rsc_cmd = cmd_list_standards;
+
+ } else if (pcmk__str_any_of(option_name, "-W", "--locate", NULL)) {
+ options.rsc_cmd = cmd_locate;
+
+ } else if (pcmk__str_eq(option_name, "--show-metadata", pcmk__str_none)) {
+ options.rsc_cmd = cmd_metadata;
+ pcmk__str_update(&options.agent_spec, optarg);
+
+ } else if (pcmk__str_any_of(option_name, "-M", "--move", NULL)) {
+ options.rsc_cmd = cmd_move;
+
+ } else if (pcmk__str_any_of(option_name, "-q", "--query-xml", NULL)) {
+ options.rsc_cmd = cmd_query_xml;
+
+ } else if (pcmk__str_any_of(option_name, "-w", "--query-xml-raw", NULL)) {
+ options.rsc_cmd = cmd_query_xml_raw;
+
+ } else if (pcmk__str_any_of(option_name, "-R", "--refresh", NULL)) {
+ options.rsc_cmd = cmd_refresh;
+
+ } else if (pcmk__str_eq(option_name, "--restart", pcmk__str_none)) {
+ options.rsc_cmd = cmd_restart;
+
+ } else if (pcmk__str_any_of(option_name, "-p", "--set-parameter", NULL)) {
+ options.rsc_cmd = cmd_set_param;
+ pcmk__str_update(&options.prop_name, optarg);
+
+ } else if (pcmk__str_any_of(option_name, "-S", "--set-property", NULL)) {
+ options.rsc_cmd = cmd_set_property;
+ pcmk__str_update(&options.prop_name, optarg);
+
+ } else if (pcmk__str_eq(option_name, "--wait", pcmk__str_none)) {
+ options.rsc_cmd = cmd_wait;
+
+ } else if (pcmk__str_any_of(option_name, "-Y", "--why", NULL)) {
+ options.rsc_cmd = cmd_why;
+ }
+
+ return TRUE;
+}
+
/* short option letters still available: eEJkKXyYZ */
static GOptionEntry query_entries[] = {
- { "list", 'L', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, list_cb,
+ { "list", 'L', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"List all cluster resources with status",
NULL },
- { "list-raw", 'l', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, list_cb,
+ { "list-raw", 'l', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"List IDs of all instantiated resources (individual members\n"
INDENT "rather than groups etc.)",
NULL },
- { "list-cts", 'c', G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, list_cb,
+ { "list-cts", 'c', G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK, command_cb,
NULL,
NULL },
- { "list-operations", 'O', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, list_cb,
+ { "list-operations", 'O', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
+ command_cb,
"List active resource operations, optionally filtered by\n"
INDENT "--resource and/or --node",
NULL },
- { "list-all-operations", 'o', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, list_cb,
+ { "list-all-operations", 'o', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
+ command_cb,
"List all resource operations, optionally filtered by\n"
INDENT "--resource and/or --node",
NULL },
+ { "list-options", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, command_cb,
+ "List all available options of the given type\n"
+ INDENT "Allowed values:\n"
+ INDENT PCMK__VALUE_PRIMITIVE "(primitive resource meta-attributes), "
+ INDENT PCMK_VALUE_FENCING " (parameters common to all fencing resources)",
+ "TYPE" },
{ "list-standards", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
- list_standards_cb,
+ command_cb,
"List supported standards",
NULL },
{ "list-ocf-providers", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
- list_providers_cb,
+ command_cb,
"List all available OCF providers",
NULL },
{ "list-agents", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK,
- list_agents_cb,
+ command_cb,
"List all agents available for the named standard and/or provider",
"STD:PROV" },
{ "list-ocf-alternatives", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK,
- list_alternatives_cb,
+ command_cb,
"List all available providers for the named OCF agent",
"AGENT" },
- { "show-metadata", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK,
- metadata_cb,
+ { "show-metadata", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, command_cb,
"Show the metadata for the named class:provider:agent",
"SPEC" },
- { "query-xml", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
+ { "query-xml", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Show XML configuration of resource (after any template expansion)",
NULL },
- { "query-xml-raw", 'w', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
+ { "query-xml-raw", 'w', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
+ command_cb,
"Show XML configuration of resource (before any template expansion)",
NULL },
- { "get-parameter", 'g', G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, get_param_prop_cb,
+ { "get-parameter", 'g', G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK,
+ command_cb,
"Display named parameter for resource (use instance attribute\n"
INDENT "unless --element, --meta, or --utilization is specified)",
"PARAM" },
- { "get-property", 'G', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, get_param_prop_cb,
+ { "get-property", 'G', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK,
+ command_cb,
"Display named property of resource ('class', 'type', or 'provider') "
"(requires --resource)",
"PROPERTY" },
- { "locate", 'W', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
+ { "locate", 'W', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Show node(s) currently running resource",
NULL },
- { "constraints", 'a', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
+ { "constraints", 'a', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
+ command_cb,
"Display the location and colocation constraints that apply to a\n"
INDENT "resource, and if --recursive is specified, to the resources\n"
INDENT "directly or indirectly involved in those colocations.\n"
@@ -404,10 +539,10 @@ static GOptionEntry query_entries[] = {
INDENT "bundle instance, constraints for the collective resource\n"
INDENT "will be shown unless --force is given.",
NULL },
- { "stack", 'A', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
+ { "stack", 'A', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Equivalent to --constraints --recursive",
NULL },
- { "why", 'Y', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, why_cb,
+ { "why", 'Y', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Show why resources are not running, optionally filtered by\n"
INDENT "--resource and/or --node",
NULL },
@@ -417,7 +552,7 @@ static GOptionEntry query_entries[] = {
static GOptionEntry command_entries[] = {
{ "validate", 0, G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
- validate_or_force_cb,
+ command_cb,
"Validate resource configuration by calling agent's validate-all\n"
INDENT "action. The configuration may be specified either by giving an\n"
INDENT "existing resource name with -r, or by specifying --class,\n"
@@ -425,7 +560,7 @@ static GOptionEntry command_entries[] = {
INDENT "--option arguments. An optional LEVEL argument can be given\n"
INDENT "to control the level of checking performed.",
"LEVEL" },
- { "cleanup", 'C', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, cleanup_refresh_cb,
+ { "cleanup", 'C', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"If resource has any past failures, clear its history and fail\n"
INDENT "count. Optionally filtered by --resource, --node, --operation\n"
INDENT "and --interval (otherwise all). --operation and --interval\n"
@@ -435,23 +570,26 @@ static GOptionEntry command_entries[] = {
INDENT "resource, the clean-up applies to the whole collective resource\n"
INDENT "unless --force is given.",
NULL },
- { "refresh", 'R', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, cleanup_refresh_cb,
+ { "refresh", 'R', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Delete resource's history (including failures) so its current state\n"
INDENT "is rechecked. Optionally filtered by --resource and --node\n"
INDENT "(otherwise all). If the named resource is part of a group, or one\n"
INDENT "numbered instance of a clone or bundled resource, the refresh\n"
INDENT "applies to the whole collective resource unless --force is given.",
NULL },
- { "set-parameter", 'p', G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, set_delete_param_cb,
+ { "set-parameter", 'p', G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK,
+ command_cb,
"Set named parameter for resource (requires -v). Use instance\n"
INDENT "attribute unless --element, --meta, or --utilization is "
"specified.",
"PARAM" },
- { "delete-parameter", 'd', G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, set_delete_param_cb,
+ { "delete-parameter", 'd', G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK,
+ command_cb,
"Delete named parameter for resource. Use instance attribute\n"
INDENT "unless --element, --meta or, --utilization is specified.",
"PARAM" },
- { "set-property", 'S', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, set_prop_cb,
+ { "set-property", 'S', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK,
+ command_cb,
"Set named property of resource ('class', 'type', or 'provider') "
"(requires -r, -t, -v)",
"PROPERTY" },
@@ -460,7 +598,7 @@ static GOptionEntry command_entries[] = {
};
static GOptionEntry location_entries[] = {
- { "move", 'M', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
+ { "move", 'M', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Create a constraint to move resource. If --node is specified,\n"
INDENT "the constraint will be to move to that node, otherwise it\n"
INDENT "will be to ban the current node. Unless --force is specified\n"
@@ -471,7 +609,7 @@ static GOptionEntry location_entries[] = {
INDENT "resource from running on its previous location until the\n"
INDENT "implicit constraint expires or is removed with --clear.",
NULL },
- { "ban", 'B', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
+ { "ban", 'B', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Create a constraint to keep resource off a node.\n"
INDENT "Optional: --node, --lifetime, --promoted.\n"
INDENT "NOTE: This will prevent the resource from running on the\n"
@@ -479,10 +617,10 @@ static GOptionEntry location_entries[] = {
INDENT "removed with --clear. If --node is not specified, it defaults\n"
INDENT "to the node currently running the resource for primitives\n"
INDENT "and groups, or the promoted instance of promotable clones with\n"
- INDENT "promoted-max=1 (all other situations result in an error as\n"
- INDENT "there is no sane default).",
+ INDENT PCMK_META_PROMOTED_MAX "=1 (all other situations result in an\n"
+ INDENT "error as there is no sane default).",
NULL },
- { "clear", 'U', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
+ { "clear", 'U', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Remove all constraints created by the --ban and/or --move\n"
INDENT "commands. Requires: --resource. Optional: --node, --promoted,\n"
INDENT "--expired. If --node is not specified, all constraints created\n"
@@ -492,7 +630,8 @@ static GOptionEntry location_entries[] = {
INDENT "node. If --expired is specified, only those constraints whose\n"
INDENT "lifetimes have expired will be removed.",
NULL },
- { "expired", 'e', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, expired_cb,
+ { "expired", 'e', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE,
+ &options.clear_expired,
"Modifies the --clear argument to remove constraints with\n"
INDENT "expired lifetimes.",
NULL },
@@ -516,20 +655,20 @@ static GOptionEntry location_entries[] = {
};
static GOptionEntry advanced_entries[] = {
- { "delete", 'D', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, delete_cb,
+ { "delete", 'D', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"(Advanced) Delete a resource from the CIB. Required: -t",
NULL },
- { "fail", 'F', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, fail_cb,
+ { "fail", 'F', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"(Advanced) Tell the cluster this resource has failed",
NULL },
- { "restart", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, restart_cb,
+ { "restart", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"(Advanced) Tell the cluster to restart this resource and\n"
INDENT "anything that depends on it",
NULL },
- { "wait", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, wait_cb,
+ { "wait", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"(Advanced) Wait until the cluster settles into a stable state",
NULL },
- { "digests", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, digests_cb,
+ { "digests", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"(Advanced) Show parameter hashes that Pacemaker uses to detect\n"
INDENT "configuration changes (only accurate if there is resource\n"
INDENT "history on the specified node). Required: --resource, --node.\n"
@@ -538,32 +677,30 @@ static GOptionEntry advanced_entries[] = {
INDENT "changes).",
NULL },
{ "force-demote", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
- validate_or_force_cb,
+ command_cb,
"(Advanced) Bypass the cluster and demote a resource on the local\n"
INDENT "node. Unless --force is specified, this will refuse to do so if\n"
INDENT "the cluster believes the resource is a clone instance already\n"
INDENT "running on the local node.",
NULL },
- { "force-stop", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
- validate_or_force_cb,
+ { "force-stop", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"(Advanced) Bypass the cluster and stop a resource on the local node",
NULL },
- { "force-start", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
- validate_or_force_cb,
+ { "force-start", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"(Advanced) Bypass the cluster and start a resource on the local\n"
INDENT "node. Unless --force is specified, this will refuse to do so if\n"
INDENT "the cluster believes the resource is a clone instance already\n"
INDENT "running on the local node.",
NULL },
{ "force-promote", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
- validate_or_force_cb,
+ command_cb,
"(Advanced) Bypass the cluster and promote a resource on the local\n"
INDENT "node. Unless --force is specified, this will refuse to do so if\n"
INDENT "the cluster believes the resource is a clone instance already\n"
INDENT "running on the local node.",
NULL },
{ "force-check", 0, G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
- validate_or_force_cb,
+ command_cb,
"(Advanced) Bypass the cluster and check the state of a resource on\n"
INDENT "the local node. An optional LEVEL argument can be given\n"
INDENT "to control the level of checking performed.",
@@ -603,15 +740,16 @@ static GOptionEntry addl_entries[] = {
{ "interval", 'I', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &options.interval_spec,
"Interval of operation to clear (default 0) (with -C -r -n)",
"N" },
- { "class", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, class_cb,
+ { "class", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, cmdline_config_cb,
"The standard the resource agent conforms to (for example, ocf).\n"
INDENT "Use with --agent, --provider, --option, and --validate.",
"CLASS" },
- { "agent", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, agent_provider_cb,
+ { "agent", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, cmdline_config_cb,
"The agent to use (for example, IPaddr). Use with --class,\n"
INDENT "--provider, --option, and --validate.",
"AGENT" },
- { "provider", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, agent_provider_cb,
+ { "provider", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK,
+ cmdline_config_cb,
"The vendor that supplies the resource agent (for example,\n"
INDENT "heartbeat). Use with --class, --agent, --option, and --validate.",
"PROVIDER" },
@@ -630,6 +768,10 @@ static GOptionEntry addl_entries[] = {
"(Advanced) Abort if command does not finish in this time (with\n"
INDENT "--restart, --wait, --force-*)",
"N" },
+ { "all", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &options.all,
+ "List all options, including advanced and deprecated (with\n"
+ INDENT "--list-options)",
+ NULL },
{ "force", 'f', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &options.force,
"Force the action to be performed. See help for individual commands for\n"
INDENT "additional behavior.",
@@ -644,136 +786,33 @@ static GOptionEntry addl_entries[] = {
{ NULL }
};
-static void
-reset_options(void) {
- options.require_crmd = FALSE;
- options.require_node = FALSE;
-
- options.require_cib = TRUE;
- options.require_scheduler = TRUE;
- options.require_resource = TRUE;
-
- options.find_flags = 0;
-}
-
-gboolean
-agent_provider_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- options.cmdline_config = TRUE;
- options.require_resource = FALSE;
-
- if (pcmk__str_eq(option_name, "--provider", pcmk__str_casei)) {
- pcmk__str_update(&options.v_provider, optarg);
- } else {
- pcmk__str_update(&options.v_agent, optarg);
- }
-
- return TRUE;
-}
-
gboolean
attr_set_type_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
if (pcmk__str_any_of(option_name, "-m", "--meta", NULL)) {
- options.attr_set_type = XML_TAG_META_SETS;
+ options.attr_set_type = PCMK_XE_META_ATTRIBUTES;
} else if (pcmk__str_any_of(option_name, "-z", "--utilization", NULL)) {
- options.attr_set_type = XML_TAG_UTILIZATION;
- } else if (pcmk__str_eq(option_name, "--element", pcmk__str_casei)) {
+ options.attr_set_type = PCMK_XE_UTILIZATION;
+ } else if (pcmk__str_eq(option_name, "--element", pcmk__str_none)) {
options.attr_set_type = ATTR_SET_ELEMENT;
}
return TRUE;
}
gboolean
-class_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- pcmk__str_update(&options.v_class, optarg);
- options.cmdline_config = TRUE;
- options.require_resource = FALSE;
- return TRUE;
-}
-
-gboolean
-cleanup_refresh_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- if (pcmk__str_any_of(option_name, "-C", "--cleanup", NULL)) {
- SET_COMMAND(cmd_cleanup);
- } else {
- SET_COMMAND(cmd_refresh);
- }
-
- options.require_resource = FALSE;
- if (getenv("CIB_file") == NULL) {
- options.require_crmd = TRUE;
- }
- options.find_flags = pcmk_rsc_match_history|pcmk_rsc_match_anon_basename;
- return TRUE;
-}
-
-gboolean
-delete_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- SET_COMMAND(cmd_delete);
- options.require_scheduler = FALSE;
- options.find_flags = pcmk_rsc_match_history|pcmk_rsc_match_basename;
- return TRUE;
-}
-
-gboolean
-expired_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- options.clear_expired = TRUE;
- options.require_resource = FALSE;
- return TRUE;
-}
-
-static void
-get_agent_spec(const gchar *optarg)
-{
- options.require_cib = FALSE;
- options.require_scheduler = FALSE;
- options.require_resource = FALSE;
- pcmk__str_update(&options.agent_spec, optarg);
-}
-
-gboolean
-list_agents_cb(const gchar *option_name, const gchar *optarg, gpointer data,
- GError **error)
-{
- SET_COMMAND(cmd_list_agents);
- get_agent_spec(optarg);
- return TRUE;
-}
-
-gboolean
-list_providers_cb(const gchar *option_name, const gchar *optarg, gpointer data,
+cmdline_config_cb(const gchar *option_name, const gchar *optarg, gpointer data,
GError **error)
{
- SET_COMMAND(cmd_list_providers);
- get_agent_spec(optarg);
- return TRUE;
-}
+ options.cmdline_config = true;
-gboolean
-list_standards_cb(const gchar *option_name, const gchar *optarg, gpointer data,
- GError **error)
-{
- SET_COMMAND(cmd_list_standards);
- options.require_cib = FALSE;
- options.require_scheduler = FALSE;
- options.require_resource = FALSE;
- return TRUE;
-}
+ if (pcmk__str_eq(option_name, "--class", pcmk__str_none)) {
+ pcmk__str_update(&options.v_class, optarg);
-gboolean
-list_alternatives_cb(const gchar *option_name, const gchar *optarg,
- gpointer data, GError **error)
-{
- SET_COMMAND(cmd_list_alternatives);
- get_agent_spec(optarg);
- return TRUE;
-}
+ } else if (pcmk__str_eq(option_name, "--provider", pcmk__str_none)) {
+ pcmk__str_update(&options.v_provider, optarg);
-gboolean
-metadata_cb(const gchar *option_name, const gchar *optarg, gpointer data,
- GError **error)
-{
- SET_COMMAND(cmd_metadata);
- get_agent_spec(optarg);
+ } else { // --agent
+ pcmk__str_update(&options.v_agent, optarg);
+ }
return TRUE;
}
@@ -795,173 +834,16 @@ option_cb(const gchar *option_name, const gchar *optarg, gpointer data,
}
gboolean
-fail_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- SET_COMMAND(cmd_fail);
- options.require_crmd = TRUE;
- options.require_node = TRUE;
- return TRUE;
-}
-
-gboolean
-flag_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- if (pcmk__str_any_of(option_name, "-U", "--clear", NULL)) {
- SET_COMMAND(cmd_clear);
- options.find_flags = pcmk_rsc_match_history
- |pcmk_rsc_match_anon_basename;
- } else if (pcmk__str_any_of(option_name, "-B", "--ban", NULL)) {
- SET_COMMAND(cmd_ban);
- options.find_flags = pcmk_rsc_match_history
- |pcmk_rsc_match_anon_basename;
- } else if (pcmk__str_any_of(option_name, "-M", "--move", NULL)) {
- SET_COMMAND(cmd_move);
- options.find_flags = pcmk_rsc_match_history
- |pcmk_rsc_match_anon_basename;
- } else if (pcmk__str_any_of(option_name, "-q", "--query-xml", NULL)) {
- SET_COMMAND(cmd_query_xml);
- options.find_flags = pcmk_rsc_match_history|pcmk_rsc_match_basename;
- } else if (pcmk__str_any_of(option_name, "-w", "--query-xml-raw", NULL)) {
- SET_COMMAND(cmd_query_raw_xml);
- options.find_flags = pcmk_rsc_match_history|pcmk_rsc_match_basename;
- } else if (pcmk__str_any_of(option_name, "-W", "--locate", NULL)) {
- SET_COMMAND(cmd_locate);
- options.find_flags = pcmk_rsc_match_history
- |pcmk_rsc_match_anon_basename;
-
- } else if (pcmk__str_any_of(option_name, "-a", "--constraints", NULL)) {
- SET_COMMAND(cmd_colocations);
- options.find_flags = pcmk_rsc_match_history
- |pcmk_rsc_match_anon_basename;
-
- } else if (pcmk__str_any_of(option_name, "-A", "--stack", NULL)) {
- SET_COMMAND(cmd_colocations);
- options.find_flags = pcmk_rsc_match_history
- |pcmk_rsc_match_anon_basename;
- options.recursive = TRUE;
- }
-
- return TRUE;
-}
-
-gboolean
-get_param_prop_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- if (pcmk__str_any_of(option_name, "-g", "--get-parameter", NULL)) {
- SET_COMMAND(cmd_get_param);
- } else {
- SET_COMMAND(cmd_get_property);
- }
-
- pcmk__str_update(&options.prop_name, optarg);
- options.find_flags = pcmk_rsc_match_history|pcmk_rsc_match_basename;
- return TRUE;
-}
-
-gboolean
-list_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- if (pcmk__str_any_of(option_name, "-c", "--list-cts", NULL)) {
- SET_COMMAND(cmd_cts);
- } else if (pcmk__str_any_of(option_name, "-L", "--list", NULL)) {
- SET_COMMAND(cmd_list_resources);
- } else if (pcmk__str_any_of(option_name, "-l", "--list-raw", NULL)) {
- SET_COMMAND(cmd_list_instances);
- } else if (pcmk__str_any_of(option_name, "-O", "--list-operations", NULL)) {
- SET_COMMAND(cmd_list_active_ops);
- } else {
- SET_COMMAND(cmd_list_all_ops);
- }
-
- options.require_resource = FALSE;
- return TRUE;
-}
-
-gboolean
-set_delete_param_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- if (pcmk__str_any_of(option_name, "-p", "--set-parameter", NULL)) {
- SET_COMMAND(cmd_set_param);
- } else {
- SET_COMMAND(cmd_delete_param);
- }
-
- pcmk__str_update(&options.prop_name, optarg);
- options.find_flags = pcmk_rsc_match_history|pcmk_rsc_match_basename;
- return TRUE;
-}
-
-gboolean
-set_prop_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- SET_COMMAND(cmd_set_property);
- options.require_scheduler = FALSE;
- pcmk__str_update(&options.prop_name, optarg);
- options.find_flags = pcmk_rsc_match_history|pcmk_rsc_match_basename;
- return TRUE;
-}
-
-gboolean
timeout_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- options.timeout_ms = crm_get_msec(optarg);
- return TRUE;
-}
-
-gboolean
-validate_or_force_cb(const gchar *option_name, const gchar *optarg,
- gpointer data, GError **error)
-{
- SET_COMMAND(cmd_execute_agent);
- if (options.operation) {
- g_free(options.operation);
- }
- options.operation = g_strdup(option_name + 2); // skip "--"
- options.find_flags = pcmk_rsc_match_history|pcmk_rsc_match_anon_basename;
- if (options.override_params == NULL) {
- options.override_params = pcmk__strkey_table(free, free);
- }
-
- if (optarg != NULL) {
- if (pcmk__scan_min_int(optarg, &options.check_level, 0) != pcmk_rc_ok) {
- g_set_error(error, G_OPTION_ERROR, CRM_EX_INVALID_PARAM,
- _("Invalid check level setting: %s"), optarg);
- return FALSE;
- }
- }
-
- return TRUE;
-}
+ long long timeout_ms = crm_get_msec(optarg);
-gboolean
-restart_cb(const gchar *option_name, const gchar *optarg, gpointer data,
- GError **error)
-{
- SET_COMMAND(cmd_restart);
- options.find_flags = pcmk_rsc_match_history|pcmk_rsc_match_anon_basename;
- return TRUE;
-}
-
-gboolean
-digests_cb(const gchar *option_name, const gchar *optarg, gpointer data,
- GError **error)
-{
- SET_COMMAND(cmd_digests);
- options.find_flags = pcmk_rsc_match_history|pcmk_rsc_match_anon_basename;
- if (options.override_params == NULL) {
- options.override_params = pcmk__strkey_table(free, free);
+ if (timeout_ms < 0) {
+ // @COMPAT When we can break backward compatibilty, return FALSE
+ crm_warn("Ignoring invalid timeout '%s'", optarg);
+ options.timeout_ms = 0U;
+ } else {
+ options.timeout_ms = (guint) QB_MIN(timeout_ms, UINT_MAX);
}
- options.require_node = TRUE;
- options.require_scheduler = TRUE;
- return TRUE;
-}
-
-gboolean
-wait_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- SET_COMMAND(cmd_wait);
- options.require_resource = FALSE;
- options.require_scheduler = FALSE;
- return TRUE;
-}
-
-gboolean
-why_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- SET_COMMAND(cmd_why);
- options.require_resource = FALSE;
- options.find_flags = pcmk_rsc_match_history|pcmk_rsc_match_anon_basename;
return TRUE;
}
@@ -979,8 +861,8 @@ ban_or_move(pcmk__output_t *out, pcmk_resource_t *rsc,
if (nactive == 1) {
rc = cli_resource_ban(out, options.rsc_id, current->details->uname, move_lifetime,
- cib_conn, options.cib_options, options.promoted_role_only,
- PCMK__ROLE_PROMOTED);
+ cib_conn, cib_sync_call,
+ options.promoted_role_only, PCMK_ROLE_PROMOTED);
} else if (pcmk_is_set(rsc->flags, pcmk_rsc_promotable)) {
int count = 0;
@@ -993,14 +875,15 @@ ban_or_move(pcmk__output_t *out, pcmk_resource_t *rsc,
if (child_role == pcmk_role_promoted) {
count++;
- current = pe__current_node(child);
+ current = pcmk__current_node(child);
}
}
if(count == 1 && current) {
rc = cli_resource_ban(out, options.rsc_id, current->details->uname, move_lifetime,
- cib_conn, options.cib_options, options.promoted_role_only,
- PCMK__ROLE_PROMOTED);
+ cib_conn, cib_sync_call,
+ options.promoted_role_only,
+ PCMK_ROLE_PROMOTED);
} else {
rc = EINVAL;
@@ -1066,12 +949,12 @@ clear_constraints(pcmk__output_t *out, xmlNodePtr *cib_xml_copy)
if (options.clear_expired) {
rc = cli_resource_clear_all_expired(scheduler->input, cib_conn,
- options.cib_options, options.rsc_id,
+ cib_sync_call, options.rsc_id,
options.host_uname,
options.promoted_role_only);
} else if (options.host_uname) {
- dest = pe_find_node(scheduler->nodes, options.host_uname);
+ dest = pcmk_find_node(scheduler, options.host_uname);
if (dest == NULL) {
rc = pcmk_rc_node_unknown;
if (!out->is_quiet(out)) {
@@ -1080,11 +963,11 @@ clear_constraints(pcmk__output_t *out, xmlNodePtr *cib_xml_copy)
return rc;
}
rc = cli_resource_clear(options.rsc_id, dest->details->uname, NULL,
- cib_conn, options.cib_options, TRUE, options.force);
+ cib_conn, cib_sync_call, true, options.force);
} else {
rc = cli_resource_clear(options.rsc_id, NULL, scheduler->nodes,
- cib_conn, options.cib_options, TRUE, options.force);
+ cib_conn, cib_sync_call, true, options.force);
}
if (!out->is_quiet(out)) {
@@ -1119,35 +1002,12 @@ clear_constraints(pcmk__output_t *out, xmlNodePtr *cib_xml_copy)
}
static int
-delete(void)
-{
- int rc = pcmk_rc_ok;
- xmlNode *msg_data = NULL;
-
- if (options.rsc_type == NULL) {
- rc = ENXIO;
- g_set_error(&error, PCMK__RC_ERROR, rc,
- _("You need to specify a resource type with -t"));
- return rc;
- }
-
- msg_data = create_xml_node(NULL, options.rsc_type);
- crm_xml_add(msg_data, XML_ATTR_ID, options.rsc_id);
-
- rc = cib_conn->cmds->remove(cib_conn, XML_CIB_TAG_RESOURCES, msg_data,
- options.cib_options);
- rc = pcmk_legacy2rc(rc);
- free_xml(msg_data);
- return rc;
-}
-
-static int
initialize_scheduler_data(xmlNodePtr *cib_xml_copy)
{
int rc = pcmk_rc_ok;
if (options.xml_file != NULL) {
- *cib_xml_copy = filename2xml(options.xml_file);
+ *cib_xml_copy = pcmk__xml_read(options.xml_file);
if (*cib_xml_copy == NULL) {
rc = pcmk_rc_cib_corrupt;
}
@@ -1161,7 +1021,7 @@ initialize_scheduler_data(xmlNodePtr *cib_xml_copy)
if (scheduler == NULL) {
rc = ENOMEM;
} else {
- pe__set_working_set_flags(scheduler,
+ pcmk__set_scheduler_flags(scheduler,
pcmk_sched_no_counts
|pcmk_sched_no_compat);
scheduler->priv = out;
@@ -1179,6 +1039,26 @@ initialize_scheduler_data(xmlNodePtr *cib_xml_copy)
return pcmk_rc_ok;
}
+static void
+list_options(void)
+{
+ switch (options.opt_list) {
+ case pcmk__opt_fencing:
+ exit_code = pcmk_rc2exitc(pcmk__list_fencing_params(out,
+ options.all));
+ break;
+ case pcmk__opt_primitive:
+ exit_code = pcmk_rc2exitc(pcmk__list_primitive_meta(out,
+ options.all));
+ break;
+ default:
+ exit_code = CRM_EX_SOFTWARE;
+ g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
+ "BUG: Invalid option list type");
+ break;
+ }
+}
+
static int
refresh(pcmk__output_t *out)
{
@@ -1187,10 +1067,10 @@ refresh(pcmk__output_t *out)
int attr_options = pcmk__node_attr_none;
if (options.host_uname) {
- pcmk_node_t *node = pe_find_node(scheduler->nodes, options.host_uname);
+ pcmk_node_t *node = pcmk_find_node(scheduler, options.host_uname);
- if (pe__is_guest_or_remote_node(node)) {
- node = pe__current_node(node->details->remote_rsc);
+ if (pcmk__is_pacemaker_remote_node(node)) {
+ node = pcmk__current_node(node->details->remote_rsc);
if (node == NULL) {
rc = ENXIO;
g_set_error(&error, PCMK__RC_ERROR, rc,
@@ -1268,12 +1148,12 @@ set_property(void)
CRM_LOG_ASSERT(options.prop_name != NULL);
- msg_data = create_xml_node(NULL, options.rsc_type);
- crm_xml_add(msg_data, XML_ATTR_ID, options.rsc_id);
+ msg_data = pcmk__xe_create(NULL, options.rsc_type);
+ crm_xml_add(msg_data, PCMK_XA_ID, options.rsc_id);
crm_xml_add(msg_data, options.prop_name, options.prop_value);
- rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_RESOURCES, msg_data,
- options.cib_options);
+ rc = cib_conn->cmds->modify(cib_conn, PCMK_XE_RESOURCES, msg_data,
+ cib_sync_call);
rc = pcmk_legacy2rc(rc);
free_xml(msg_data);
@@ -1308,7 +1188,7 @@ show_metadata(pcmk__output_t *out, const char *agent_spec)
rc = pcmk_legacy2rc(rc);
if (metadata) {
- out->output_xml(out, "metadata", metadata);
+ out->output_xml(out, PCMK_XE_METADATA, metadata);
free(metadata);
} else {
/* We were given a validly formatted spec, but it doesn't necessarily
@@ -1366,16 +1246,209 @@ validate_cmdline_config(void)
options.v_agent ? options.v_agent : "");
}
- if (error != NULL) {
- return;
+ if ((error == NULL) && (options.cmdline_params == NULL)) {
+ options.cmdline_params = pcmk__strkey_table(free, free);
}
+}
- if (options.cmdline_params == NULL) {
- options.cmdline_params = pcmk__strkey_table(free, free);
+/*!
+ * \internal
+ * \brief Get the <tt>enum pe_find</tt> flags for a given command
+ *
+ * \return <tt>enum pe_find</tt> flag group appropriate for \c options.rsc_cmd.
+ */
+static uint32_t
+get_find_flags(void)
+{
+ switch (options.rsc_cmd) {
+ case cmd_ban:
+ case cmd_cleanup:
+ case cmd_clear:
+ case cmd_colocations:
+ case cmd_digests:
+ case cmd_execute_agent:
+ case cmd_locate:
+ case cmd_move:
+ case cmd_refresh:
+ case cmd_restart:
+ case cmd_why:
+ return pcmk_rsc_match_history|pcmk_rsc_match_anon_basename;
+
+ // @COMPAT See note in is_scheduler_required()
+ case cmd_delete:
+ case cmd_delete_param:
+ case cmd_get_param:
+ case cmd_get_property:
+ case cmd_query_xml_raw:
+ case cmd_query_xml:
+ case cmd_set_param:
+ case cmd_set_property:
+ return pcmk_rsc_match_history|pcmk_rsc_match_basename;
+
+ default:
+ return 0;
+ }
+}
+
+/*!
+ * \internal
+ * \brief Check whether a node argument is required
+ *
+ * \return \c true if a \c --node argument is required, or \c false otherwise
+ */
+static bool
+is_node_required(void)
+{
+ switch (options.rsc_cmd) {
+ case cmd_digests:
+ case cmd_fail:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*!
+ * \internal
+ * \brief Check whether a resource argument is required
+ *
+ * \return \c true if a \c --resource argument is required, or \c false
+ * otherwise
+ */
+static bool
+is_resource_required(void)
+{
+ if (options.cmdline_config) {
+ return false;
+ }
+
+ switch (options.rsc_cmd) {
+ case cmd_clear:
+ return !options.clear_expired;
+
+ case cmd_cleanup:
+ case cmd_cts:
+ case cmd_list_active_ops:
+ case cmd_list_agents:
+ case cmd_list_all_ops:
+ case cmd_list_alternatives:
+ case cmd_list_instances:
+ case cmd_list_options:
+ case cmd_list_providers:
+ case cmd_list_resources:
+ case cmd_list_standards:
+ case cmd_metadata:
+ case cmd_refresh:
+ case cmd_wait:
+ case cmd_why:
+ return false;
+
+ default:
+ return true;
+ }
+}
+
+/*!
+ * \internal
+ * \brief Check whether a CIB connection is required
+ *
+ * \return \c true if a CIB connection is required, or \c false otherwise
+ */
+static bool
+is_cib_required(void)
+{
+ if (options.cmdline_config) {
+ return false;
+ }
+
+ switch (options.rsc_cmd) {
+ case cmd_list_agents:
+ case cmd_list_alternatives:
+ case cmd_list_options:
+ case cmd_list_providers:
+ case cmd_list_standards:
+ case cmd_metadata:
+ return false;
+ default:
+ return true;
+ }
+}
+
+/*!
+ * \internal
+ * \brief Check whether a controller IPC connection is required
+ *
+ * \return \c true if a controller connection is required, or \c false otherwise
+ */
+static bool
+is_controller_required(void)
+{
+ switch (options.rsc_cmd) {
+ case cmd_cleanup:
+ case cmd_refresh:
+ return getenv("CIB_file") == NULL;
+
+ case cmd_fail:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/*!
+ * \internal
+ * \brief Check whether a scheduler IPC connection is required
+ *
+ * \return \c true if a scheduler connection is required, or \c false otherwise
+ */
+static bool
+is_scheduler_required(void)
+{
+ if (options.cmdline_config) {
+ return false;
+ }
+
+ /* @COMPAT cmd_delete does not actually need the scheduler and should not
+ * set find_flags. However, crm_resource --delete currently throws a
+ * "resource not found" error if the resource doesn't exist. This is
+ * incorrect behavior (deleting a nonexistent resource should be considered
+ * success); however, we shouldn't change it until 3.0.0.
+ */
+ switch (options.rsc_cmd) {
+ case cmd_list_agents:
+ case cmd_list_alternatives:
+ case cmd_list_options:
+ case cmd_list_providers:
+ case cmd_list_standards:
+ case cmd_metadata:
+ case cmd_wait:
+ return false;
+ default:
+ return true;
+ }
+}
+
+/*!
+ * \internal
+ * \brief Check whether the chosen command accepts clone instances
+ *
+ * \return \c true if \p options.rsc_cmd accepts or ignores clone instances, or
+ * \c false otherwise
+ */
+static bool
+accept_clone_instance(void)
+{
+ // @COMPAT At 3.0.0, add cmd_delete; for now, don't throw error
+ switch (options.rsc_cmd) {
+ case cmd_ban:
+ case cmd_clear:
+ case cmd_move:
+ case cmd_restart:
+ return false;
+ default:
+ return true;
}
- options.require_resource = FALSE;
- options.require_scheduler = FALSE;
- options.require_cib = FALSE;
}
static GOptionContext *
@@ -1407,14 +1480,14 @@ build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
"location:\n\n"
"\t# crm_resource --resource myResource --clear\n\n"
"Stop 'myResource' (and anything that depends on it):\n\n"
- "\t# crm_resource --resource myResource --set-parameter target-role "
- "--meta --parameter-value Stopped\n\n"
+ "\t# crm_resource --resource myResource --set-parameter "
+ PCMK_META_TARGET_ROLE "--meta --parameter-value Stopped\n\n"
"Tell the cluster not to manage 'myResource' (the cluster will not "
"attempt to start or stop the\n"
"resource under any circumstances; useful when performing maintenance "
"tasks on a resource):\n\n"
- "\t# crm_resource --resource myResource --set-parameter is-managed "
- "--meta --parameter-value false\n\n"
+ "\t# crm_resource --resource myResource --set-parameter "
+ PCMK_META_IS_MANAGED "--meta --parameter-value false\n\n"
"Erase the operation history of 'myResource' on 'aNode' (the cluster "
"will 'forget' the existing\n"
"resource state, including any errors, and attempt to recover the"
@@ -1449,6 +1522,7 @@ main(int argc, char **argv)
xmlNode *cib_xml_copy = NULL;
pcmk_resource_t *rsc = NULL;
pcmk_node_t *node = NULL;
+ uint32_t find_flags = 0;
int rc = pcmk_rc_ok;
GOptionGroup *output_group = NULL;
@@ -1492,12 +1566,6 @@ main(int argc, char **argv)
* Validate option combinations
*/
- // If the user didn't explicitly specify a command, list resources
- if (options.rsc_cmd == cmd_none) {
- options.rsc_cmd = cmd_list_resources;
- options.require_resource = FALSE;
- }
-
// --expired without --clear/-U doesn't make sense
if (options.clear_expired && (options.rsc_cmd != cmd_clear)) {
exit_code = CRM_EX_USAGE;
@@ -1508,8 +1576,8 @@ main(int argc, char **argv)
if ((options.remainder != NULL) && (options.override_params != NULL)) {
// Commands that use positional arguments will create override_params
for (gchar **s = options.remainder; *s; s++) {
- char *name = calloc(1, strlen(*s));
- char *value = calloc(1, strlen(*s));
+ char *name = pcmk__assert_alloc(1, strlen(*s));
+ char *value = pcmk__assert_alloc(1, strlen(*s));
int rc = sscanf(*s, "%[^=]=%s", name, value);
if (rc == 2) {
@@ -1541,7 +1609,7 @@ main(int argc, char **argv)
/* Add 1 for the strv[0] string below, and add another 1 for the NULL
* at the end of the array so g_strjoinv knows when to stop.
*/
- strv = calloc(len+2, sizeof(char *));
+ strv = pcmk__assert_alloc(len+2, sizeof(char *));
strv[0] = strdup("non-option ARGV-elements:\n");
for (gchar **s = options.remainder; *s; s++) {
@@ -1566,28 +1634,30 @@ main(int argc, char **argv)
}
if (pcmk__str_eq(args->output_ty, "xml", pcmk__str_none)) {
- /* Kind of a hack to display XML lists using a real tag instead of <list>. This just
- * saves from having to write custom messages to build the lists around all these things
- */
switch (options.rsc_cmd) {
- case cmd_execute_agent:
- case cmd_list_resources:
- case cmd_query_xml:
- case cmd_query_raw_xml:
- case cmd_list_active_ops:
- case cmd_list_all_ops:
- case cmd_colocations:
- pcmk__force_args(context, &error, "%s --xml-simple-list --xml-substitute", g_get_prgname());
+ /* These are the only commands that have historically used the <list>
+ * elements in their XML schema. For all others, use the simple list
+ * argument.
+ */
+ case cmd_get_param:
+ case cmd_get_property:
+ case cmd_list_instances:
+ case cmd_list_standards:
+ pcmk__output_enable_list_element(out);
break;
default:
- pcmk__force_args(context, &error, "%s --xml-substitute", g_get_prgname());
break;
}
+
} else if (pcmk__str_eq(args->output_ty, "text", pcmk__str_null_matches)) {
- if ((options.rsc_cmd == cmd_colocations) ||
- options.rsc_cmd == cmd_list_resources) {
- pcmk__force_args(context, &error, "%s --text-fancy", g_get_prgname());
+ switch (options.rsc_cmd) {
+ case cmd_colocations:
+ case cmd_list_resources:
+ pcmk__output_text_set_fancy(out, true);
+ break;
+ default:
+ break;
}
}
@@ -1612,13 +1682,13 @@ main(int argc, char **argv)
options.cmdline_params = NULL;
}
- if (options.require_resource && (options.rsc_id == NULL)) {
+ if (is_resource_required() && (options.rsc_id == NULL)) {
exit_code = CRM_EX_USAGE;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
_("Must supply a resource id with -r"));
goto done;
}
- if (options.require_node && (options.host_uname == NULL)) {
+ if (is_node_required() && (options.host_uname == NULL)) {
exit_code = CRM_EX_USAGE;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
_("Must supply a node name with -N"));
@@ -1629,12 +1699,8 @@ main(int argc, char **argv)
* Set up necessary connections
*/
- if (options.find_flags && options.rsc_id) {
- options.require_scheduler = TRUE;
- }
-
// Establish a connection to the CIB if needed
- if (options.require_cib) {
+ if (is_cib_required()) {
cib_conn = cib_new();
if ((cib_conn == NULL) || (cib_conn->cmds == NULL)) {
exit_code = CRM_EX_DISCONNECT;
@@ -1653,7 +1719,7 @@ main(int argc, char **argv)
}
// Populate scheduler data from XML file if specified or CIB query otherwise
- if (options.require_scheduler) {
+ if (is_scheduler_required()) {
rc = initialize_scheduler_data(&cib_xml_copy);
if (rc != pcmk_rc_ok) {
exit_code = pcmk_rc2exitc(rc);
@@ -1661,10 +1727,12 @@ main(int argc, char **argv)
}
}
+ find_flags = get_find_flags();
+
// If command requires that resource exist if specified, find it
- if (options.find_flags && options.rsc_id) {
+ if ((find_flags != 0) && (options.rsc_id != NULL)) {
rsc = pe_find_resource_with_flags(scheduler->resources, options.rsc_id,
- options.find_flags);
+ find_flags);
if (rsc == NULL) {
exit_code = CRM_EX_NOSUCH;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
@@ -1675,9 +1743,9 @@ main(int argc, char **argv)
/* The --ban, --clear, --move, and --restart commands do not work with
* instances of clone resourcs.
*/
- if (strchr(options.rsc_id, ':') != NULL && pe_rsc_is_clone(rsc->parent) &&
- (options.rsc_cmd == cmd_ban || options.rsc_cmd == cmd_clear ||
- options.rsc_cmd == cmd_move || options.rsc_cmd == cmd_restart)) {
+ if (pcmk__is_clone(rsc->parent) && (strchr(options.rsc_id, ':') != NULL)
+ && !accept_clone_instance()) {
+
exit_code = CRM_EX_INVALID_PARAM;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
_("Cannot operate on clone resource instance '%s'"), options.rsc_id);
@@ -1687,7 +1755,7 @@ main(int argc, char **argv)
// If user supplied a node name, check whether it exists
if ((options.host_uname != NULL) && (scheduler != NULL)) {
- node = pe_find_node(scheduler->nodes, options.host_uname);
+ node = pcmk_find_node(scheduler, options.host_uname);
if (node == NULL) {
exit_code = CRM_EX_NOSUCH;
@@ -1698,7 +1766,7 @@ main(int argc, char **argv)
}
// Establish a connection to the controller if needed
- if (options.require_crmd) {
+ if (is_controller_required()) {
rc = pcmk_new_ipc_api(&controld_api, pcmk_ipc_controld);
if (rc != pcmk_rc_ok) {
exit_code = pcmk_rc2exitc(rc);
@@ -1725,10 +1793,11 @@ main(int argc, char **argv)
switch (options.rsc_cmd) {
case cmd_list_resources: {
GList *all = NULL;
+ uint32_t show_opts = pcmk_show_inactive_rscs | pcmk_show_rsc_only | pcmk_show_pending;
+
all = g_list_prepend(all, (gpointer) "*");
rc = out->message(out, "resource-list", scheduler,
- pcmk_show_inactive_rscs | pcmk_show_rsc_only | pcmk_show_pending,
- true, all, all, false);
+ show_opts, true, all, all, false);
g_list_free(all);
if (rc == pcmk_rc_no_output) {
@@ -1746,6 +1815,10 @@ main(int argc, char **argv)
break;
+ case cmd_list_options:
+ list_options();
+ break;
+
case cmd_list_alternatives:
rc = pcmk__list_alternatives(out, options.agent_spec);
break;
@@ -1774,7 +1847,7 @@ main(int argc, char **argv)
*/
rc = cli_resource_restart(out, rsc, node, options.move_lifetime,
options.timeout_ms, cib_conn,
- options.cib_options, options.promoted_role_only,
+ cib_sync_call, options.promoted_role_only,
options.force);
break;
@@ -1798,7 +1871,7 @@ main(int argc, char **argv)
goto done;
case cmd_digests:
- node = pe_find_node(scheduler->nodes, options.host_uname);
+ node = pcmk_find_node(scheduler, options.host_uname);
if (node == NULL) {
rc = pcmk_rc_node_unknown;
} else {
@@ -1850,7 +1923,7 @@ main(int argc, char **argv)
rc = cli_resource_print(rsc, scheduler, true);
break;
- case cmd_query_raw_xml:
+ case cmd_query_xml_raw:
rc = cli_resource_print(rsc, scheduler, false);
break;
@@ -1873,7 +1946,7 @@ main(int argc, char **argv)
} else {
rc = cli_resource_move(rsc, options.rsc_id, options.host_uname,
options.move_lifetime, cib_conn,
- options.cib_options, scheduler,
+ cib_sync_call, scheduler,
options.promoted_role_only,
options.force);
}
@@ -1893,9 +1966,8 @@ main(int argc, char **argv)
} else {
rc = cli_resource_ban(out, options.rsc_id, node->details->uname,
options.move_lifetime, cib_conn,
- options.cib_options,
- options.promoted_role_only,
- PCMK__ROLE_PROMOTED);
+ cib_sync_call, options.promoted_role_only,
+ PCMK_ROLE_PROMOTED);
}
if (rc == EINVAL) {
@@ -1933,15 +2005,17 @@ main(int argc, char **argv)
crm_debug("Looking up %s in %s", options.prop_name, rsc->id);
- if (pcmk__str_eq(options.attr_set_type, XML_TAG_ATTR_SETS, pcmk__str_none)) {
+ if (pcmk__str_eq(options.attr_set_type, PCMK_XE_INSTANCE_ATTRIBUTES,
+ pcmk__str_none)) {
params = pe_rsc_params(rsc, current, scheduler);
free_params = false;
value = g_hash_table_lookup(params, options.prop_name);
- } else if (pcmk__str_eq(options.attr_set_type, XML_TAG_META_SETS, pcmk__str_none)) {
+ } else if (pcmk__str_eq(options.attr_set_type,
+ PCMK_XE_META_ATTRIBUTES, pcmk__str_none)) {
params = pcmk__strkey_table(free, free);
- get_meta_attributes(params, rsc, current, scheduler);
+ get_meta_attributes(params, rsc, NULL, scheduler);
value = g_hash_table_lookup(params, options.prop_name);
@@ -1951,9 +2025,14 @@ main(int argc, char **argv)
free_params = false;
} else {
+ pe_rule_eval_data_t rule_data = {
+ .now = scheduler->now,
+ };
+
params = pcmk__strkey_table(free, free);
- pe__unpack_dataset_nvpairs(rsc->xml, XML_TAG_UTILIZATION, NULL, params,
- NULL, FALSE, scheduler);
+ pe__unpack_dataset_nvpairs(rsc->xml, PCMK_XE_UTILIZATION,
+ &rule_data, params, NULL, FALSE,
+ scheduler);
value = g_hash_table_lookup(params, options.prop_name);
}
@@ -1982,7 +2061,6 @@ main(int argc, char **argv)
options.prop_name,
options.prop_value,
options.recursive, cib_conn,
- options.cib_options,
options.force);
break;
@@ -1993,8 +2071,7 @@ main(int argc, char **argv)
options.attr_set_type,
options.prop_id,
options.prop_name, cib_conn,
- options.cib_options,
- options.force);
+ cib_sync_call, options.force);
break;
case cmd_cleanup:
@@ -2019,7 +2096,25 @@ main(int argc, char **argv)
break;
case cmd_delete:
- rc = delete();
+ /* rsc_id was already checked for NULL much earlier when validating
+ * command line arguments.
+ */
+ if (options.rsc_type == NULL) {
+ // @COMPAT @TODO change this to exit_code = CRM_EX_USAGE
+ rc = ENXIO;
+ g_set_error(&error, PCMK__RC_ERROR, rc,
+ _("You need to specify a resource type with -t"));
+ } else {
+ rc = pcmk__resource_delete(cib_conn, cib_sync_call,
+ options.rsc_id, options.rsc_type);
+
+ if (rc != pcmk_rc_ok) {
+ g_set_error(&error, PCMK__RC_ERROR, rc,
+ _("Could not delete resource %s: %s"),
+ options.rsc_id, pcmk_rc_str(rc));
+ }
+ }
+
break;
default:
diff --git a/tools/crm_resource.h b/tools/crm_resource.h
index dc86572..de85a5b 100644
--- a/tools/crm_resource.h
+++ b/tools/crm_resource.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2023 the Pacemaker project contributors
+ * Copyright 2004-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -14,7 +14,6 @@
#include <crm/crm.h>
-#include <crm/msg_xml.h>
#include <crm/services.h>
#include <crm/common/xml.h>
#include <crm/common/mainloop.h>
@@ -22,7 +21,7 @@
#include <crm/common/scheduler_internal.h>
#include <crm/cib.h>
-#include <crm/common/attrd_internal.h>
+#include <crm/common/attrs_internal.h>
#include <crm/pengine/rules.h>
#include <crm/pengine/status.h>
#include <crm/pengine/internal.h>
@@ -35,6 +34,16 @@ typedef struct node_info_s {
bool promoted;
} node_info_t;
+typedef struct {
+ char *attr_set_type;
+ char *attr_set_id;
+ char *attr_name;
+ char *attr_value;
+ char *given_rsc_id;
+ char *found_attr_id;
+ pcmk_resource_t *rsc;
+} attr_update_data_t;
+
enum resource_check_flags {
rsc_remain_stopped = (1 << 0),
rsc_unpromotable = (1 << 1),
@@ -89,7 +98,7 @@ int cli_cleanup_all(pcmk_ipc_api_t *controld_api, const char *node_name,
pcmk_scheduler_t *scheduler);
int cli_resource_restart(pcmk__output_t *out, pcmk_resource_t *rsc,
const pcmk_node_t *node, const char *move_lifetime,
- int timeout_ms, cib_t *cib, int cib_options,
+ guint timeout_ms, cib_t *cib, int cib_options,
gboolean promoted_role_only, gboolean force);
int cli_resource_move(const pcmk_resource_t *rsc, const char *rsc_id,
const char *host_name, const char *move_lifetime,
@@ -99,12 +108,13 @@ crm_exit_t cli_resource_execute_from_params(pcmk__output_t *out, const char *rsc
const char *rsc_class, const char *rsc_prov,
const char *rsc_type, const char *rsc_action,
GHashTable *params, GHashTable *override_hash,
- int timeout_ms, int resource_verbose,
+ guint timeout_ms,
+ int resource_verbose,
gboolean force, int check_level);
crm_exit_t cli_resource_execute(pcmk_resource_t *rsc,
const char *requested_name,
const char *rsc_action, GHashTable *override_hash,
- int timeout_ms, cib_t *cib,
+ guint timeout_ms, cib_t *cib,
pcmk_scheduler_t *scheduler,
int resource_verbose, gboolean force, int check_level);
@@ -113,7 +123,7 @@ int cli_resource_update_attribute(pcmk_resource_t *rsc,
const char *attr_set, const char *attr_set_type,
const char *attr_id, const char *attr_name,
const char *attr_value, gboolean recursive,
- cib_t *cib, int cib_options, gboolean force);
+ cib_t *cib, gboolean force);
int cli_resource_delete_attribute(pcmk_resource_t *rsc,
const char *requested_name,
const char *attr_set, const char *attr_set_type,
@@ -121,7 +131,7 @@ int cli_resource_delete_attribute(pcmk_resource_t *rsc,
cib_t *cib, int cib_options, gboolean force);
int update_scheduler_input(pcmk_scheduler_t *scheduler, xmlNode **xml);
-int wait_till_stable(pcmk__output_t *out, int timeout_ms, cib_t * cib);
+int wait_till_stable(pcmk__output_t *out, guint timeout_ms, cib_t * cib);
bool resource_is_running_on(pcmk_resource_t *rsc, const char *host);
diff --git a/tools/crm_resource_ban.c b/tools/crm_resource_ban.c
index 3b0e4a1..689a178 100644
--- a/tools/crm_resource_ban.c
+++ b/tools/crm_resource_ban.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2023 the Pacemaker project contributors
+ * Copyright 2004-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -72,62 +72,66 @@ cli_resource_ban(pcmk__output_t *out, const char *rsc_id, const char *host,
return EINVAL;
}
- fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
+ fragment = pcmk__xe_create(NULL, PCMK_XE_CONSTRAINTS);
- location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
+ location = pcmk__xe_create(fragment, PCMK_XE_RSC_LOCATION);
crm_xml_set_id(location, "cli-ban-%s-on-%s", rsc_id, host);
- out->info(out, "WARNING: Creating rsc_location constraint '%s' with a "
- "score of -INFINITY for resource %s on %s.\n\tThis will "
- "prevent %s from %s on %s until the constraint is removed "
- "using the clear option or by editing the CIB with an "
- "appropriate tool\n\tThis will be the case even if %s "
- "is the last node in the cluster",
- ID(location), rsc_id, host, rsc_id,
- (promoted_role_only? "being promoted" : "running"),
- host, host);
-
- crm_xml_add(location, XML_LOC_ATTR_SOURCE, rsc_id);
+ out->info(out,
+ "WARNING: Creating " PCMK_XE_RSC_LOCATION " constraint '%s' with "
+ "a score of " PCMK_VALUE_MINUS_INFINITY " for resource %s on %s."
+ "\n\tThis will prevent %s from %s on %s until the constraint is "
+ "removed using the clear option or by editing the CIB with an "
+ "appropriate tool.\n"
+ "\tThis will be the case even if %s is the last node in the "
+ "cluster",
+ pcmk__xe_id(location), rsc_id, host, rsc_id,
+ (promoted_role_only? "being promoted" : "running"), host, host);
+
+ crm_xml_add(location, PCMK_XA_RSC, rsc_id);
if(promoted_role_only) {
- crm_xml_add(location, XML_RULE_ATTR_ROLE, promoted_role);
+ crm_xml_add(location, PCMK_XA_ROLE, promoted_role);
} else {
- crm_xml_add(location, XML_RULE_ATTR_ROLE, PCMK__ROLE_STARTED);
+ crm_xml_add(location, PCMK_XA_ROLE, PCMK_ROLE_STARTED);
}
if (later_s == NULL) {
/* Short form */
- crm_xml_add(location, XML_CIB_TAG_NODE, host);
- crm_xml_add(location, XML_RULE_ATTR_SCORE, CRM_MINUS_INFINITY_S);
+ crm_xml_add(location, PCMK_XE_NODE, host);
+ crm_xml_add(location, PCMK_XA_SCORE, PCMK_VALUE_MINUS_INFINITY);
} else {
- xmlNode *rule = create_xml_node(location, XML_TAG_RULE);
- xmlNode *expr = create_xml_node(rule, XML_TAG_EXPRESSION);
+ xmlNode *rule = pcmk__xe_create(location, PCMK_XE_RULE);
+ xmlNode *expr = pcmk__xe_create(rule, PCMK_XE_EXPRESSION);
crm_xml_set_id(rule, "cli-ban-%s-on-%s-rule", rsc_id, host);
- crm_xml_add(rule, XML_RULE_ATTR_SCORE, CRM_MINUS_INFINITY_S);
- crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and");
+ crm_xml_add(rule, PCMK_XA_SCORE, PCMK_VALUE_MINUS_INFINITY);
+ crm_xml_add(rule, PCMK_XA_BOOLEAN_OP, PCMK_VALUE_AND);
crm_xml_set_id(expr, "cli-ban-%s-on-%s-expr", rsc_id, host);
- crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, CRM_ATTR_UNAME);
- crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq");
- crm_xml_add(expr, XML_EXPR_ATTR_VALUE, host);
- crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string");
+ crm_xml_add(expr, PCMK_XA_ATTRIBUTE, CRM_ATTR_UNAME);
+ crm_xml_add(expr, PCMK_XA_OPERATION, PCMK_VALUE_EQ);
+ crm_xml_add(expr, PCMK_XA_VALUE, host);
+ crm_xml_add(expr, PCMK_XA_TYPE, PCMK_VALUE_STRING);
- expr = create_xml_node(rule, "date_expression");
+ expr = pcmk__xe_create(rule, PCMK_XE_DATE_EXPRESSION);
crm_xml_set_id(expr, "cli-ban-%s-on-%s-lifetime", rsc_id, host);
- crm_xml_add(expr, "operation", "lt");
- crm_xml_add(expr, "end", later_s);
+ crm_xml_add(expr, PCMK_XA_OPERATION, PCMK_VALUE_LT);
+ crm_xml_add(expr, PCMK_XA_END, later_s);
}
crm_log_xml_notice(fragment, "Modify");
- rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment,
+ rc = cib_conn->cmds->modify(cib_conn, PCMK_XE_CONSTRAINTS, fragment,
cib_options);
rc = pcmk_legacy2rc(rc);
free_xml(fragment);
free(later_s);
- if (rc != pcmk_rc_ok && promoted_role_only && strcmp(promoted_role, PCMK__ROLE_PROMOTED) == 0) {
+ if ((rc != pcmk_rc_ok)
+ && promoted_role_only
+ && (strcmp(promoted_role, PCMK_ROLE_PROMOTED) == 0)) {
+
int banrc = cli_resource_ban(out, rsc_id, host, move_lifetime,
cib_conn, cib_options, promoted_role_only,
PCMK__ROLE_PROMOTED_LEGACY);
@@ -159,52 +163,55 @@ cli_resource_prefer(pcmk__output_t *out,const char *rsc_id, const char *host,
return ENOTCONN;
}
- fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
+ fragment = pcmk__xe_create(NULL, PCMK_XE_CONSTRAINTS);
- location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
+ location = pcmk__xe_create(fragment, PCMK_XE_RSC_LOCATION);
crm_xml_set_id(location, "cli-prefer-%s", rsc_id);
- crm_xml_add(location, XML_LOC_ATTR_SOURCE, rsc_id);
+ crm_xml_add(location, PCMK_XA_RSC, rsc_id);
if(promoted_role_only) {
- crm_xml_add(location, XML_RULE_ATTR_ROLE, promoted_role);
+ crm_xml_add(location, PCMK_XA_ROLE, promoted_role);
} else {
- crm_xml_add(location, XML_RULE_ATTR_ROLE, PCMK__ROLE_STARTED);
+ crm_xml_add(location, PCMK_XA_ROLE, PCMK_ROLE_STARTED);
}
if (later_s == NULL) {
/* Short form */
- crm_xml_add(location, XML_CIB_TAG_NODE, host);
- crm_xml_add(location, XML_RULE_ATTR_SCORE, CRM_INFINITY_S);
+ crm_xml_add(location, PCMK_XE_NODE, host);
+ crm_xml_add(location, PCMK_XA_SCORE, PCMK_VALUE_INFINITY);
} else {
- xmlNode *rule = create_xml_node(location, XML_TAG_RULE);
- xmlNode *expr = create_xml_node(rule, XML_TAG_EXPRESSION);
+ xmlNode *rule = pcmk__xe_create(location, PCMK_XE_RULE);
+ xmlNode *expr = pcmk__xe_create(rule, PCMK_XE_EXPRESSION);
crm_xml_set_id(rule, "cli-prefer-rule-%s", rsc_id);
- crm_xml_add(rule, XML_RULE_ATTR_SCORE, CRM_INFINITY_S);
- crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and");
+ crm_xml_add(rule, PCMK_XA_SCORE, PCMK_VALUE_INFINITY);
+ crm_xml_add(rule, PCMK_XA_BOOLEAN_OP, PCMK_VALUE_AND);
crm_xml_set_id(expr, "cli-prefer-expr-%s", rsc_id);
- crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, CRM_ATTR_UNAME);
- crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq");
- crm_xml_add(expr, XML_EXPR_ATTR_VALUE, host);
- crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string");
+ crm_xml_add(expr, PCMK_XA_ATTRIBUTE, CRM_ATTR_UNAME);
+ crm_xml_add(expr, PCMK_XA_OPERATION, PCMK_VALUE_EQ);
+ crm_xml_add(expr, PCMK_XA_VALUE, host);
+ crm_xml_add(expr, PCMK_XA_TYPE, PCMK_VALUE_STRING);
- expr = create_xml_node(rule, "date_expression");
+ expr = pcmk__xe_create(rule, PCMK_XE_DATE_EXPRESSION);
crm_xml_set_id(expr, "cli-prefer-lifetime-end-%s", rsc_id);
- crm_xml_add(expr, "operation", "lt");
- crm_xml_add(expr, "end", later_s);
+ crm_xml_add(expr, PCMK_XA_OPERATION, PCMK_VALUE_LT);
+ crm_xml_add(expr, PCMK_XA_END, later_s);
}
crm_log_xml_info(fragment, "Modify");
- rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment,
+ rc = cib_conn->cmds->modify(cib_conn, PCMK_XE_CONSTRAINTS, fragment,
cib_options);
rc = pcmk_legacy2rc(rc);
free_xml(fragment);
free(later_s);
- if (rc != pcmk_rc_ok && promoted_role_only && strcmp(promoted_role, PCMK__ROLE_PROMOTED) == 0) {
+ if ((rc != pcmk_rc_ok)
+ && promoted_role_only
+ && (strcmp(promoted_role, PCMK_ROLE_PROMOTED) == 0)) {
+
int preferrc = cli_resource_prefer(out, rsc_id, host, move_lifetime,
cib_conn, cib_options, promoted_role_only,
PCMK__ROLE_PROMOTED_LEGACY);
@@ -229,8 +236,9 @@ cli_resource_prefer(pcmk__output_t *out,const char *rsc_id, const char *host,
* </rule>
* </rsc_location>
*
- * (2) The mode could be given by node= in an rsc_location XML node. That's
- * what resource_clear_node_in_location handles. That XML looks like this:
+ * (2) The node could be given by node= in a PCMK_XE_RSC_LOCATION XML node.
+ * That's what resource_clear_node_in_location handles. That XML looks like
+ * this:
*
* <rsc_location id="cli-prefer-dummy" rsc="dummy" role="Started" node="node1" score="INFINITY"/>
*
@@ -243,13 +251,13 @@ resource_clear_node_in_expr(const char *rsc_id, const char *host, cib_t * cib_co
int rc = pcmk_rc_ok;
char *xpath_string = NULL;
-#define XPATH_FMT \
- "//" XML_CONS_TAG_RSC_LOCATION "[@" XML_ATTR_ID "='cli-prefer-%s']" \
- "[" XML_TAG_RULE \
- "[@" XML_ATTR_ID "='cli-prefer-rule-%s']" \
- "/" XML_TAG_EXPRESSION \
- "[@" XML_EXPR_ATTR_ATTRIBUTE "='#uname' " \
- "and @" XML_EXPR_ATTR_VALUE "='%s']" \
+#define XPATH_FMT \
+ "//" PCMK_XE_RSC_LOCATION "[@" PCMK_XA_ID "='cli-prefer-%s']" \
+ "[" PCMK_XE_RULE \
+ "[@" PCMK_XA_ID "='cli-prefer-rule-%s']" \
+ "/" PCMK_XE_EXPRESSION \
+ "[@" PCMK_XA_ATTRIBUTE "='" CRM_ATTR_UNAME "' " \
+ "and @" PCMK_XA_VALUE "='%s']" \
"]"
xpath_string = crm_strdup_printf(XPATH_FMT, rsc_id, rsc_id, host);
@@ -274,21 +282,22 @@ resource_clear_node_in_location(const char *rsc_id, const char *host, cib_t * ci
xmlNode *fragment = NULL;
xmlNode *location = NULL;
- fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
+ fragment = pcmk__xe_create(NULL, PCMK_XE_CONSTRAINTS);
if (clear_ban_constraints == TRUE) {
- location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
+ location = pcmk__xe_create(fragment, PCMK_XE_RSC_LOCATION);
crm_xml_set_id(location, "cli-ban-%s-on-%s", rsc_id, host);
}
- location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
+ location = pcmk__xe_create(fragment, PCMK_XE_RSC_LOCATION);
crm_xml_set_id(location, "cli-prefer-%s", rsc_id);
if (force == FALSE) {
- crm_xml_add(location, XML_CIB_TAG_NODE, host);
+ crm_xml_add(location, PCMK_XE_NODE, host);
}
crm_log_xml_info(fragment, "Delete");
- rc = cib_conn->cmds->remove(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, cib_options);
+ rc = cib_conn->cmds->remove(cib_conn, PCMK_XE_CONSTRAINTS, fragment,
+ cib_options);
if (rc == -ENXIO) {
rc = pcmk_rc_ok;
} else {
@@ -349,12 +358,11 @@ build_clear_xpath_string(GString *buf, const xmlNode *constraint_node,
const char *rsc, const char *node,
bool promoted_role_only)
{
- const char *cons_id = ID(constraint_node);
- const char *cons_rsc = crm_element_value(constraint_node,
- XML_LOC_ATTR_SOURCE);
+ const char *cons_id = pcmk__xe_id(constraint_node);
+ const char *cons_rsc = crm_element_value(constraint_node, PCMK_XA_RSC);
GString *rsc_role_substr = NULL;
- const char *promoted_role_rule = "@" XML_RULE_ATTR_ROLE "='" PCMK__ROLE_PROMOTED
- "' or @" XML_RULE_ATTR_ROLE "='"
+ const char *promoted_role_rule = "@" PCMK_XA_ROLE "='" PCMK_ROLE_PROMOTED
+ "' or @" PCMK_XA_ROLE "='"
PCMK__ROLE_PROMOTED_LEGACY "'";
CRM_ASSERT(buf != NULL);
@@ -365,13 +373,13 @@ build_clear_xpath_string(GString *buf, const xmlNode *constraint_node,
return;
}
- g_string_append(buf, "//" XML_CONS_TAG_RSC_LOCATION);
+ g_string_append(buf, "//" PCMK_XE_RSC_LOCATION);
if ((node != NULL) || (rsc != NULL) || promoted_role_only) {
g_string_append_c(buf, '[');
if (node != NULL) {
- pcmk__g_strcat(buf, "@" XML_CIB_TAG_NODE "='", node, "'", NULL);
+ pcmk__g_strcat(buf, "@" PCMK_XE_NODE "='", node, "'", NULL);
if (promoted_role_only || (rsc != NULL)) {
g_string_append(buf, " and ");
@@ -381,13 +389,13 @@ build_clear_xpath_string(GString *buf, const xmlNode *constraint_node,
if ((rsc != NULL) && promoted_role_only) {
rsc_role_substr = g_string_sized_new(64);
pcmk__g_strcat(rsc_role_substr,
- "@" XML_LOC_ATTR_SOURCE "='", rsc, "' "
+ "@" PCMK_XA_RSC "='", rsc, "' "
"and (" , promoted_role_rule, ")", NULL);
} else if (rsc != NULL) {
rsc_role_substr = g_string_sized_new(64);
pcmk__g_strcat(rsc_role_substr,
- "@" XML_LOC_ATTR_SOURCE "='", rsc, "'", NULL);
+ "@" PCMK_XA_RSC "='", rsc, "'", NULL);
} else if (promoted_role_only) {
rsc_role_substr = g_string_sized_new(64);
@@ -401,18 +409,18 @@ build_clear_xpath_string(GString *buf, const xmlNode *constraint_node,
}
if (node != NULL) {
- g_string_append(buf, "|//" XML_CONS_TAG_RSC_LOCATION);
+ g_string_append(buf, "|//" PCMK_XE_RSC_LOCATION);
if (rsc_role_substr != NULL) {
pcmk__g_strcat(buf, "[", rsc_role_substr, "]", NULL);
}
pcmk__g_strcat(buf,
- "/" XML_TAG_RULE "[" XML_TAG_EXPRESSION
- "[@" XML_EXPR_ATTR_ATTRIBUTE "='" CRM_ATTR_UNAME "' "
- "and @" XML_EXPR_ATTR_VALUE "='", node, "']]", NULL);
+ "/" PCMK_XE_RULE "[" PCMK_XE_EXPRESSION
+ "[@" PCMK_XA_ATTRIBUTE "='" CRM_ATTR_UNAME "' "
+ "and @" PCMK_XA_VALUE "='", node, "']]", NULL);
}
- g_string_append(buf, "//" PCMK_XE_DATE_EXPRESSION "[@" XML_ATTR_ID "='");
+ g_string_append(buf, "//" PCMK_XE_DATE_EXPRESSION "[@" PCMK_XA_ID "='");
if (pcmk__starts_with(cons_id, "cli-ban-")) {
pcmk__g_strcat(buf, cons_id, "-lifetime']", NULL);
@@ -438,13 +446,14 @@ cli_resource_clear_all_expired(xmlNode *root, cib_t *cib_conn, int cib_options,
int i;
int rc = pcmk_rc_ok;
- cib_constraints = pcmk_find_cib_element(root, XML_CIB_TAG_CONSTRAINTS);
- xpathObj = xpath_search(cib_constraints, "//" XML_CONS_TAG_RSC_LOCATION);
+ cib_constraints = pcmk_find_cib_element(root, PCMK_XE_CONSTRAINTS);
+ xpathObj = xpath_search(cib_constraints, "//" PCMK_XE_RSC_LOCATION);
for (i = 0; i < numXpathResults(xpathObj); i++) {
xmlNode *constraint_node = getXpathResult(xpathObj, i);
xmlNode *date_expr_node = NULL;
crm_time_t *end = NULL;
+ int rc = pcmk_rc_ok;
if (buf == NULL) {
buf = g_string_sized_new(1024);
@@ -464,20 +473,25 @@ cli_resource_clear_all_expired(xmlNode *root, cib_t *cib_conn, int cib_options,
/* And then finally, see if the date expression is expired. If so,
* clear the constraint.
+ *
+ * @COMPAT Check for error once we are rejecting rules with invalid end
*/
- end = crm_time_new(crm_element_value(date_expr_node, "end"));
+ rc = pcmk__xe_get_datetime(date_expr_node, PCMK_XA_END, &end);
+ if (rc != pcmk_rc_ok) {
+ crm_trace("Invalid " PCMK_XA_END ": %s", pcmk_rc_str(rc));
+ }
if (crm_time_compare(now, end) == 1) {
xmlNode *fragment = NULL;
xmlNode *location = NULL;
- fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
- location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
- crm_xml_set_id(location, "%s", ID(constraint_node));
+ fragment = pcmk__xe_create(NULL, PCMK_XE_CONSTRAINTS);
+ location = pcmk__xe_create(fragment, PCMK_XE_RSC_LOCATION);
+ crm_xml_set_id(location, "%s", pcmk__xe_id(constraint_node));
crm_log_xml_info(fragment, "Delete");
- rc = cib_conn->cmds->remove(cib_conn, XML_CIB_TAG_CONSTRAINTS,
- fragment, cib_options);
+ rc = cib_conn->cmds->remove(cib_conn, PCMK_XE_CONSTRAINTS, fragment,
+ cib_options);
rc = pcmk_legacy2rc(rc);
if (rc != pcmk_rc_ok) {
diff --git a/tools/crm_resource_print.c b/tools/crm_resource_print.c
index bdf3ad9..811bab0 100644
--- a/tools/crm_resource_print.c
+++ b/tools/crm_resource_print.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2023 the Pacemaker project contributors
+ * Copyright 2004-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -23,30 +23,33 @@ print_constraint(xmlNode *xml_obj, void *userdata)
pcmk_scheduler_t *scheduler = (pcmk_scheduler_t *) userdata;
pcmk__output_t *out = scheduler->priv;
xmlNode *lifetime = NULL;
- const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
+ const char *id = crm_element_value(xml_obj, PCMK_XA_ID);
+ pcmk_rule_input_t rule_input = {
+ .now = scheduler->now,
+ };
if (id == NULL) {
return pcmk_rc_ok;
}
- // @COMPAT lifetime is deprecated
- lifetime = first_named_child(xml_obj, "lifetime");
- if (pe_evaluate_rules(lifetime, NULL, scheduler->now, NULL) == FALSE) {
+ // @COMPAT PCMK__XE_LIFETIME is deprecated
+ lifetime = pcmk__xe_first_child(xml_obj, PCMK__XE_LIFETIME, NULL, NULL);
+ if (pcmk__evaluate_rules(lifetime, &rule_input, NULL) != pcmk_rc_ok) {
return pcmk_rc_ok;
}
- if (!pcmk__xe_is(xml_obj, XML_CONS_TAG_RSC_DEPEND)) {
+ if (!pcmk__xe_is(xml_obj, PCMK_XE_RSC_COLOCATION)) {
return pcmk_rc_ok;
}
out->info(out, "Constraint %s %s %s %s %s %s %s",
xml_obj->name,
- cons_string(crm_element_value(xml_obj, XML_ATTR_ID)),
- cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE)),
- cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET)),
- cons_string(crm_element_value(xml_obj, XML_RULE_ATTR_SCORE)),
- cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_ROLE)),
- cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET_ROLE)));
+ cons_string(crm_element_value(xml_obj, PCMK_XA_ID)),
+ cons_string(crm_element_value(xml_obj, PCMK_XA_RSC)),
+ cons_string(crm_element_value(xml_obj, PCMK_XA_WITH_RSC)),
+ cons_string(crm_element_value(xml_obj, PCMK_XA_SCORE)),
+ cons_string(crm_element_value(xml_obj, PCMK_XA_RSC_ROLE)),
+ cons_string(crm_element_value(xml_obj, PCMK_XA_WITH_RSC_ROLE)));
return pcmk_rc_ok;
}
@@ -55,7 +58,7 @@ void
cli_resource_print_cts_constraints(pcmk_scheduler_t *scheduler)
{
pcmk__xe_foreach_child(pcmk_find_cib_element(scheduler->input,
- XML_CIB_TAG_CONSTRAINTS),
+ PCMK_XE_CONSTRAINTS),
NULL, print_constraint, scheduler);
}
@@ -64,10 +67,10 @@ cli_resource_print_cts(pcmk_resource_t *rsc, pcmk__output_t *out)
{
const char *host = NULL;
bool needs_quorum = TRUE;
- const char *rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE);
- const char *rprov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
- const char *rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
- pcmk_node_t *node = pe__current_node(rsc);
+ const char *rtype = crm_element_value(rsc->xml, PCMK_XA_TYPE);
+ const char *rprov = crm_element_value(rsc->xml, PCMK_XA_PROVIDER);
+ const char *rclass = crm_element_value(rsc->xml, PCMK_XA_CLASS);
+ pcmk_node_t *node = pcmk__current_node(rsc);
if (pcmk__str_eq(rclass, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
needs_quorum = FALSE;
@@ -125,7 +128,8 @@ cli_resource_print(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler,
all = g_list_prepend(all, (gpointer) "*");
out->begin_list(out, NULL, NULL, "Resource Config");
- out->message(out, crm_map_element_name(rsc->xml), show_opts, rsc, all, all);
+ out->message(out, pcmk__map_element_name(rsc->xml), show_opts, rsc, all,
+ all);
out->message(out, "resource-config", rsc, !expanded);
out->end_list(out);
@@ -133,6 +137,88 @@ cli_resource_print(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler,
return pcmk_rc_ok;
}
+PCMK__OUTPUT_ARGS("attribute-changed", "attr_update_data_t *")
+static int
+attribute_changed_default(pcmk__output_t *out, va_list args)
+{
+ attr_update_data_t *ud = va_arg(args, attr_update_data_t *);
+
+ out->info(out, "Set '%s' option: "
+ PCMK_XA_ID "=%s%s%s%s%s value=%s",
+ ud->given_rsc_id, ud->found_attr_id,
+ ((ud->attr_set_id == NULL)? "" : " " PCMK__XA_SET "="),
+ pcmk__s(ud->attr_set_id, ""),
+ ((ud->attr_name == NULL)? "" : " " PCMK_XA_NAME "="),
+ pcmk__s(ud->attr_name, ""), ud->attr_value);
+
+ return pcmk_rc_ok;
+}
+
+PCMK__OUTPUT_ARGS("attribute-changed", "attr_update_data_t *")
+static int
+attribute_changed_xml(pcmk__output_t *out, va_list args)
+{
+ attr_update_data_t *ud = va_arg(args, attr_update_data_t *);
+
+ pcmk__output_xml_create_parent(out, (const char *) ud->rsc->xml->name,
+ PCMK_XA_ID, ud->rsc->id,
+ NULL);
+
+ pcmk__output_xml_create_parent(out, ud->attr_set_type,
+ PCMK_XA_ID, ud->attr_set_id,
+ NULL);
+
+ pcmk__output_create_xml_node(out, PCMK_XE_NVPAIR,
+ PCMK_XA_ID, ud->found_attr_id,
+ PCMK_XA_VALUE, ud->attr_value,
+ PCMK_XA_NAME, ud->attr_name,
+ NULL);
+
+ pcmk__output_xml_pop_parent(out);
+ pcmk__output_xml_pop_parent(out);
+
+ return pcmk_rc_ok;
+}
+
+PCMK__OUTPUT_ARGS("attribute-changed-list", "GList *")
+static int
+attribute_changed_list_default(pcmk__output_t *out, va_list args)
+{
+ GList *results = va_arg(args, GList *);
+
+ if (results == NULL) {
+ return pcmk_rc_no_output;
+ }
+
+ for (GList *iter = results; iter != NULL; iter = iter->next) {
+ attr_update_data_t *ud = iter->data;
+ out->message(out, "attribute-changed", ud);
+ }
+
+ return pcmk_rc_ok;
+}
+
+PCMK__OUTPUT_ARGS("attribute-changed-list", "GList *")
+static int
+attribute_changed_list_xml(pcmk__output_t *out, va_list args)
+{
+ GList *results = va_arg(args, GList *);
+
+ if (results == NULL) {
+ return pcmk_rc_no_output;
+ }
+
+ pcmk__output_xml_create_parent(out, PCMK__XE_RESOURCE_SETTINGS, NULL);
+
+ for (GList *iter = results; iter != NULL; iter = iter->next) {
+ attr_update_data_t *ud = iter->data;
+ out->message(out, "attribute-changed", ud);
+ }
+
+ pcmk__output_xml_pop_parent(out);
+ return pcmk_rc_ok;
+}
+
PCMK__OUTPUT_ARGS("attribute-list", "pcmk_resource_t *", "const char *",
"const char *")
static int
@@ -210,19 +296,21 @@ agent_status_xml(pcmk__output_t *out, va_list args) {
crm_exit_t rc = va_arg(args, crm_exit_t);
const char *exit_reason = va_arg(args, const char *);
- char *exit_str = pcmk__itoa(rc);
- char *status_str = pcmk__itoa(status);
-
- pcmk__output_create_xml_node(out, "agent-status",
- "code", exit_str,
- "message", services_ocf_exitcode_str((int) rc),
- "execution_code", status_str,
- "execution_message", pcmk_exec_status_str(status),
- "reason", exit_reason,
+ char *exit_s = pcmk__itoa(rc);
+ const char *message = services_ocf_exitcode_str((int) rc);
+ char *status_s = pcmk__itoa(status);
+ const char *execution_message = pcmk_exec_status_str(status);
+
+ pcmk__output_create_xml_node(out, PCMK_XE_AGENT_STATUS,
+ PCMK_XA_CODE, exit_s,
+ PCMK_XA_MESSAGE, message,
+ PCMK_XA_EXECUTION_CODE, status_s,
+ PCMK_XA_EXECUTION_MESSAGE, execution_message,
+ PCMK_XA_REASON, exit_reason,
NULL);
- free(exit_str);
- free(status_str);
+ free(exit_s);
+ free(status_s);
return pcmk_rc_ok;
}
@@ -268,13 +356,13 @@ override_xml(pcmk__output_t *out, va_list args) {
const char *name = va_arg(args, const char *);
const char *value = va_arg(args, const char *);
- xmlNodePtr node = pcmk__output_create_xml_node(out, "override",
- "name", name,
- "value", value,
+ xmlNodePtr node = pcmk__output_create_xml_node(out, PCMK_XE_OVERRIDE,
+ PCMK_XA_NAME, name,
+ PCMK_XA_VALUE, value,
NULL);
if (rsc_name != NULL) {
- crm_xml_add(node, "rsc", rsc_name);
+ crm_xml_add(node, PCMK_XA_RSC, rsc_name);
}
return pcmk_rc_ok;
@@ -336,7 +424,7 @@ resource_agent_action_default(pcmk__output_t *out, va_list args) {
const char *name = NULL;
const char *value = NULL;
- out->begin_list(out, NULL, NULL, "overrides");
+ out->begin_list(out, NULL, NULL, PCMK_XE_OVERRIDES);
g_hash_table_iter_init(&iter, overrides);
while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &value)) {
@@ -359,10 +447,10 @@ resource_agent_action_default(pcmk__output_t *out, va_list args) {
xmlNodePtr doc = NULL;
if (stdout_data != NULL) {
- doc = string2xml(stdout_data);
+ doc = pcmk__xml_parse(stdout_data);
}
if (doc != NULL) {
- out->output_xml(out, "command", stdout_data);
+ out->output_xml(out, PCMK_XE_COMMAND, stdout_data);
xmlFreeNode(doc);
} else {
out->subprocess_output(out, rc, stdout_data, stderr_data);
@@ -391,26 +479,26 @@ resource_agent_action_xml(pcmk__output_t *out, va_list args) {
const char *stdout_data = va_arg(args, const char *);
const char *stderr_data = va_arg(args, const char *);
- xmlNodePtr node = pcmk__output_xml_create_parent(out, "resource-agent-action",
- "action", action,
- "class", class,
- "type", type,
- NULL);
+ xmlNodePtr node = NULL;
+
+ node = pcmk__output_xml_create_parent(out, PCMK_XE_RESOURCE_AGENT_ACTION,
+ PCMK_XA_ACTION, action,
+ PCMK_XA_CLASS, class,
+ PCMK_XA_TYPE, type,
+ NULL);
if (rsc_name) {
- crm_xml_add(node, "rsc", rsc_name);
+ crm_xml_add(node, PCMK_XA_RSC, rsc_name);
}
- if (provider) {
- crm_xml_add(node, "provider", provider);
- }
+ crm_xml_add(node, PCMK_XA_PROVIDER, provider);
if (overrides) {
GHashTableIter iter;
const char *name = NULL;
const char *value = NULL;
- out->begin_list(out, NULL, NULL, "overrides");
+ out->begin_list(out, NULL, NULL, PCMK_XE_OVERRIDES);
g_hash_table_iter_init(&iter, overrides);
while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &value)) {
@@ -427,10 +515,10 @@ resource_agent_action_xml(pcmk__output_t *out, va_list args) {
xmlNodePtr doc = NULL;
if (stdout_data != NULL) {
- doc = string2xml(stdout_data);
+ doc = pcmk__xml_parse(stdout_data);
}
if (doc != NULL) {
- out->output_xml(out, "command", stdout_data);
+ out->output_xml(out, PCMK_XE_COMMAND, stdout_data);
xmlFreeNode(doc);
} else {
out->subprocess_output(out, rc, stdout_data, stderr_data);
@@ -477,10 +565,10 @@ resource_check_list_default(pcmk__output_t *out, va_list args) {
if (pcmk_is_set(checks->flags, rsc_node_health)) {
out->list_item(out, "check",
"'%s' cannot run on unhealthy nodes due to "
- PCMK__OPT_NODE_HEALTH_STRATEGY "='%s'",
+ PCMK_OPT_NODE_HEALTH_STRATEGY "='%s'",
parent->id,
- pe_pref(checks->rsc->cluster->config_hash,
- PCMK__OPT_NODE_HEALTH_STRATEGY));
+ pcmk__cluster_option(checks->rsc->cluster->config_hash,
+ PCMK_OPT_NODE_HEALTH_STRATEGY));
}
out->end_list(out);
@@ -494,39 +582,39 @@ resource_check_list_xml(pcmk__output_t *out, va_list args) {
const pcmk_resource_t *parent = pe__const_top_resource(checks->rsc, false);
- xmlNodePtr node = pcmk__output_create_xml_node(out, "check",
- "id", parent->id,
+ xmlNodePtr node = pcmk__output_create_xml_node(out, PCMK_XE_CHECK,
+ PCMK_XA_ID, parent->id,
NULL);
if (pcmk_is_set(checks->flags, rsc_remain_stopped)) {
- pcmk__xe_set_bool_attr(node, "remain_stopped", true);
+ pcmk__xe_set_bool_attr(node, PCMK_XA_REMAIN_STOPPED, true);
}
if (pcmk_is_set(checks->flags, rsc_unpromotable)) {
- pcmk__xe_set_bool_attr(node, "promotable", false);
+ pcmk__xe_set_bool_attr(node, PCMK_XA_PROMOTABLE, false);
}
if (pcmk_is_set(checks->flags, rsc_unmanaged)) {
- pcmk__xe_set_bool_attr(node, "unmanaged", true);
+ pcmk__xe_set_bool_attr(node, PCMK_XA_UNMANAGED, true);
}
if (pcmk_is_set(checks->flags, rsc_locked)) {
- crm_xml_add(node, "locked-to", checks->lock_node);
+ crm_xml_add(node, PCMK_XA_LOCKED_TO_HYPHEN, checks->lock_node);
}
if (pcmk_is_set(checks->flags, rsc_node_health)) {
- pcmk__xe_set_bool_attr(node, "unhealthy", true);
+ pcmk__xe_set_bool_attr(node, PCMK_XA_UNHEALTHY, true);
}
return pcmk_rc_ok;
}
-PCMK__OUTPUT_ARGS("resource-search-list", "GList *", "const char *")
+PCMK__OUTPUT_ARGS("resource-search-list", "GList *", "const gchar *")
static int
resource_search_list_default(pcmk__output_t *out, va_list args)
{
GList *nodes = va_arg(args, GList *);
- const char *requested_name = va_arg(args, const char *);
+ const gchar *requested_name = va_arg(args, const gchar *);
bool printed = false;
int rc = pcmk_rc_no_output;
@@ -554,7 +642,7 @@ resource_search_list_default(pcmk__output_t *out, va_list args)
#ifdef PCMK__COMPAT_2_0
role_text = " " PCMK__ROLE_PROMOTED_LEGACY;
#else
- role_text = " " PCMK__ROLE_PROMOTED;
+ role_text = " " PCMK_ROLE_PROMOTED;
#endif
}
out->list_item(out, "node", "resource %s is running on: %s%s",
@@ -569,26 +657,29 @@ resource_search_list_default(pcmk__output_t *out, va_list args)
return rc;
}
-PCMK__OUTPUT_ARGS("resource-search-list", "GList *", "const char *")
+PCMK__OUTPUT_ARGS("resource-search-list", "GList *", "const gchar *")
static int
resource_search_list_xml(pcmk__output_t *out, va_list args)
{
GList *nodes = va_arg(args, GList *);
- const char *requested_name = va_arg(args, const char *);
+ const gchar *requested_name = va_arg(args, const gchar *);
- pcmk__output_xml_create_parent(out, "nodes",
- "resource", requested_name,
+ pcmk__output_xml_create_parent(out, PCMK_XE_NODES,
+ PCMK_XA_RESOURCE, requested_name,
NULL);
for (GList *lpc = nodes; lpc != NULL; lpc = lpc->next) {
node_info_t *ni = (node_info_t *) lpc->data;
- xmlNodePtr sub_node = pcmk__output_create_xml_text_node(out, "node", ni->node_name);
+ xmlNodePtr sub_node = pcmk__output_create_xml_text_node(out,
+ PCMK_XE_NODE,
+ ni->node_name);
if (ni->promoted) {
- crm_xml_add(sub_node, "state", "promoted");
+ crm_xml_add(sub_node, PCMK_XA_STATE, "promoted");
}
}
+ pcmk__output_xml_pop_parent(out);
return pcmk_rc_ok;
}
@@ -685,22 +776,25 @@ resource_reasons_list_xml(pcmk__output_t *out, va_list args)
const char *host_uname = (node == NULL)? NULL : node->details->uname;
- xmlNodePtr xml_node = pcmk__output_xml_create_parent(out, "reason", NULL);
+ xmlNodePtr xml_node = pcmk__output_xml_create_parent(out, PCMK_XE_REASON,
+ NULL);
if ((rsc == NULL) && (host_uname == NULL)) {
GList *lpc = NULL;
GList *hosts = NULL;
- pcmk__output_xml_create_parent(out, "resources", NULL);
+ pcmk__output_xml_create_parent(out, PCMK_XE_RESOURCES, NULL);
for (lpc = resources; lpc != NULL; lpc = lpc->next) {
pcmk_resource_t *rsc = (pcmk_resource_t *) lpc->data;
+ const char *running = NULL;
rsc->fns->location(rsc, &hosts, TRUE);
+ running = pcmk__btoa(hosts != NULL);
- pcmk__output_xml_create_parent(out, "resource",
- "id", rsc->id,
- "running", pcmk__btoa(hosts != NULL),
+ pcmk__output_xml_create_parent(out, PCMK_XE_RESOURCE,
+ PCMK_XA_ID, rsc->id,
+ PCMK_XA_RUNNING, running,
NULL);
cli_resource_check(out, rsc, NULL);
@@ -713,7 +807,7 @@ resource_reasons_list_xml(pcmk__output_t *out, va_list args)
} else if ((rsc != NULL) && (host_uname != NULL)) {
if (resource_is_running_on(rsc, host_uname)) {
- crm_xml_add(xml_node, "running_on", host_uname);
+ crm_xml_add(xml_node, PCMK_XA_RUNNING_ON, host_uname);
}
cli_resource_check(out, rsc, node);
@@ -725,15 +819,15 @@ resource_reasons_list_xml(pcmk__output_t *out, va_list args)
GList *unactiveResources = pcmk__subtract_lists(allResources, activeResources, (GCompareFunc) strcmp);
GList *lpc = NULL;
- pcmk__output_xml_create_parent(out, "resources", NULL);
+ pcmk__output_xml_create_parent(out, PCMK_XE_RESOURCES, NULL);
for (lpc = activeResources; lpc != NULL; lpc = lpc->next) {
pcmk_resource_t *rsc = (pcmk_resource_t *) lpc->data;
- pcmk__output_xml_create_parent(out, "resource",
- "id", rsc->id,
- "running", "true",
- "host", host_uname,
+ pcmk__output_xml_create_parent(out, PCMK_XE_RESOURCE,
+ PCMK_XA_ID, rsc->id,
+ PCMK_XA_RUNNING, PCMK_VALUE_TRUE,
+ PCMK_XA_HOST, host_uname,
NULL);
cli_resource_check(out, rsc, node);
@@ -743,10 +837,10 @@ resource_reasons_list_xml(pcmk__output_t *out, va_list args)
for(lpc = unactiveResources; lpc != NULL; lpc = lpc->next) {
pcmk_resource_t *rsc = (pcmk_resource_t *) lpc->data;
- pcmk__output_xml_create_parent(out, "resource",
- "id", rsc->id,
- "running", "false",
- "host", host_uname,
+ pcmk__output_xml_create_parent(out, PCMK_XE_RESOURCE,
+ PCMK_XA_ID, rsc->id,
+ PCMK_XA_RUNNING, PCMK_VALUE_FALSE,
+ PCMK_XA_HOST, host_uname,
NULL);
cli_resource_check(out, rsc, node);
@@ -762,11 +856,12 @@ resource_reasons_list_xml(pcmk__output_t *out, va_list args)
GList *hosts = NULL;
rsc->fns->location(rsc, &hosts, TRUE);
- crm_xml_add(xml_node, "running", pcmk__btoa(hosts != NULL));
+ crm_xml_add(xml_node, PCMK_XA_RUNNING, pcmk__btoa(hosts != NULL));
cli_resource_check(out, rsc, NULL);
g_list_free(hosts);
}
+ pcmk__output_xml_pop_parent(out);
return pcmk_rc_ok;
}
@@ -774,7 +869,11 @@ static void
add_resource_name(pcmk_resource_t *rsc, pcmk__output_t *out)
{
if (rsc->children == NULL) {
- out->list_item(out, "resource", "%s", rsc->id);
+ /* Sometimes PCMK_XE_RESOURCE might act as a PCMK_XA_NAME instead of an
+ * XML element name, depending on whether pcmk__output_enable_list_element
+ * was called.
+ */
+ out->list_item(out, PCMK_XE_RESOURCE, "%s", rsc->id);
} else {
g_list_foreach(rsc->children, (GFunc) add_resource_name, out);
}
@@ -799,6 +898,10 @@ resource_names(pcmk__output_t *out, va_list args) {
static pcmk__message_entry_t fmt_functions[] = {
{ "agent-status", "default", agent_status_default },
{ "agent-status", "xml", agent_status_xml },
+ { "attribute-changed", "default", attribute_changed_default },
+ { "attribute-changed", "xml", attribute_changed_xml },
+ { "attribute-changed-list", "default", attribute_changed_list_default },
+ { "attribute-changed-list", "xml", attribute_changed_list_xml },
{ "attribute-list", "default", attribute_list_default },
{ "attribute-list", "text", attribute_list_text },
{ "override", "default", override_default },
diff --git a/tools/crm_resource_runtime.c b/tools/crm_resource_runtime.c
index da360fd..5b4fd2b 100644
--- a/tools/crm_resource_runtime.c
+++ b/tools/crm_resource_runtime.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2023 the Pacemaker project contributors
+ * Copyright 2004-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -9,12 +9,18 @@
#include <crm_internal.h>
-#include <crm_resource.h>
+#include <stdio.h>
+#include <limits.h>
+#include <glib.h>
+#include <libxml/tree.h>
+
#include <crm/common/ipc_attrd_internal.h>
#include <crm/common/ipc_controld.h>
#include <crm/common/lists_internal.h>
#include <crm/services_internal.h>
+#include <crm_resource.h>
+
static GList *
build_node_info_list(const pcmk_resource_t *rsc)
{
@@ -27,7 +33,7 @@ build_node_info_list(const pcmk_resource_t *rsc)
iter2 != NULL; iter2 = iter2->next) {
const pcmk_node_t *node = (const pcmk_node_t *) iter2->data;
- node_info_t *ni = calloc(1, sizeof(node_info_t));
+ node_info_t *ni = pcmk__assert_alloc(1, sizeof(node_info_t));
ni->node_name = node->details->uname;
ni->promoted = pcmk_is_set(rsc->flags, pcmk_rsc_promotable) &&
@@ -47,22 +53,23 @@ cli_resource_search(pcmk_resource_t *rsc, const char *requested_name,
GList *retval = NULL;
const pcmk_resource_t *parent = pe__const_top_resource(rsc, false);
- if (pe_rsc_is_clone(rsc)) {
+ if (pcmk__is_clone(rsc)) {
retval = build_node_info_list(rsc);
/* The anonymous clone children's common ID is supplied */
- } else if (pe_rsc_is_clone(parent)
+ } else if (pcmk__is_clone(parent)
&& !pcmk_is_set(rsc->flags, pcmk_rsc_unique)
&& rsc->clone_name
- && pcmk__str_eq(requested_name, rsc->clone_name, pcmk__str_casei)
- && !pcmk__str_eq(requested_name, rsc->id, pcmk__str_casei)) {
+ && pcmk__str_eq(requested_name, rsc->clone_name, pcmk__str_none)
+ && !pcmk__str_eq(requested_name, rsc->id, pcmk__str_none)) {
retval = build_node_info_list(parent);
} else if (rsc->running_on != NULL) {
for (GList *iter = rsc->running_on; iter != NULL; iter = iter->next) {
pcmk_node_t *node = (pcmk_node_t *) iter->data;
- node_info_t *ni = calloc(1, sizeof(node_info_t));
+ node_info_t *ni = pcmk__assert_alloc(1, sizeof(node_info_t));
+
ni->node_name = node->details->uname;
ni->promoted = (rsc->fns->state(rsc, TRUE) == pcmk_role_promoted);
@@ -77,83 +84,73 @@ cli_resource_search(pcmk_resource_t *rsc, const char *requested_name,
static int
find_resource_attr(pcmk__output_t *out, cib_t * the_cib, const char *attr,
const char *rsc, const char *attr_set_type, const char *set_name,
- const char *attr_id, const char *attr_name, char **value)
+ const char *attr_id, const char *attr_name, xmlNode **result)
{
+ xmlNode *xml_search;
int rc = pcmk_rc_ok;
- xmlNode *xml_search = NULL;
GString *xpath = NULL;
const char *xpath_base = NULL;
- if(value) {
- *value = NULL;
+ if (result) {
+ *result = NULL;
}
if(the_cib == NULL) {
return ENOTCONN;
}
- xpath_base = pcmk_cib_xpath_for(XML_CIB_TAG_RESOURCES);
+ xpath_base = pcmk_cib_xpath_for(PCMK_XE_RESOURCES);
if (xpath_base == NULL) {
- crm_err(XML_CIB_TAG_RESOURCES " CIB element not known (bug?)");
+ crm_err(PCMK_XE_RESOURCES " CIB element not known (bug?)");
return ENOMSG;
}
xpath = g_string_sized_new(1024);
pcmk__g_strcat(xpath,
- xpath_base, "//*[@" XML_ATTR_ID "=\"", rsc, "\"]", NULL);
+ xpath_base, "//*[@" PCMK_XA_ID "=\"", rsc, "\"]", NULL);
if (attr_set_type != NULL) {
pcmk__g_strcat(xpath, "/", attr_set_type, NULL);
if (set_name != NULL) {
- pcmk__g_strcat(xpath, "[@" XML_ATTR_ID "=\"", set_name, "\"]",
+ pcmk__g_strcat(xpath, "[@" PCMK_XA_ID "=\"", set_name, "\"]",
NULL);
}
}
- g_string_append(xpath, "//" XML_CIB_TAG_NVPAIR "[");
- if (attr_id != NULL) {
- pcmk__g_strcat(xpath, "@" XML_ATTR_ID "=\"", attr_id, "\"", NULL);
- }
+ g_string_append(xpath, "//" PCMK_XE_NVPAIR);
- if (attr_name != NULL) {
- if (attr_id != NULL) {
- g_string_append(xpath, " and ");
- }
- pcmk__g_strcat(xpath, "@" XML_NVPAIR_ATTR_NAME "=\"", attr_name, "\"",
- NULL);
+ if (attr_id != NULL && attr_name!= NULL) {
+ pcmk__g_strcat(xpath,
+ "[@" PCMK_XA_ID "='", attr_id, "' "
+ "and @" PCMK_XA_NAME "='", attr_name, "']", NULL);
+
+ } else if (attr_id != NULL) {
+ pcmk__g_strcat(xpath, "[@" PCMK_XA_ID "='", attr_id, "']", NULL);
+
+ } else if (attr_name != NULL) {
+ pcmk__g_strcat(xpath, "[@" PCMK_XA_NAME "='", attr_name, "']", NULL);
}
- g_string_append_c(xpath, ']');
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);
- if (rc != pcmk_rc_ok) {
- goto done;
- }
-
- crm_log_xml_debug(xml_search, "Match");
- if (xml_search->children != NULL) {
- xmlNode *child = NULL;
-
- rc = ENOTUNIQ;
- out->info(out, "Multiple attributes match name=%s", attr_name);
-
- for (child = pcmk__xml_first_child(xml_search); child != NULL;
- child = pcmk__xml_next(child)) {
- out->info(out, " Value: %s \t(id=%s)",
- crm_element_value(child, XML_NVPAIR_ATTR_VALUE), ID(child));
+ if (rc == pcmk_rc_ok) {
+ crm_log_xml_debug(xml_search, "Match");
+ if (xml_search->children != NULL) {
+ rc = ENOTUNIQ;
+ pcmk__warn_multiple_name_matches(out, xml_search, attr_name);
+ out->spacer(out);
}
+ }
- out->spacer(out);
-
- } else if(value) {
- pcmk__str_update(value, crm_element_value(xml_search, attr));
+ if (result) {
+ *result = xml_search;
+ } else {
+ free_xml(xml_search);
}
- done:
g_string_free(xpath, TRUE);
- free_xml(xml_search);
return rc;
}
@@ -161,29 +158,27 @@ find_resource_attr(pcmk__output_t *out, cib_t * the_cib, const char *attr,
static void
find_matching_attr_resources_recursive(pcmk__output_t *out,
GList /* <pcmk_resource_t*> */ **result,
- pcmk_resource_t *rsc, const char *rsc_id,
- const char * attr_set, const char * attr_set_type,
- const char * attr_id, const char * attr_name,
- cib_t * cib, const char * cmd, int depth)
+ pcmk_resource_t *rsc, const char * attr_set,
+ const char * attr_set_type, const char * attr_id,
+ const char * attr_name, cib_t * cib, int depth)
{
int rc = pcmk_rc_ok;
char *lookup_id = clone_strip(rsc->id);
- char *local_attr_id = NULL;
/* visit the children */
for(GList *gIter = rsc->children; gIter; gIter = gIter->next) {
find_matching_attr_resources_recursive(out, result,
(pcmk_resource_t *) gIter->data,
- rsc_id, attr_set, attr_set_type,
- attr_id, attr_name, cib, cmd, depth+1);
+ attr_set, attr_set_type, attr_id,
+ attr_name, cib, depth+1);
/* do it only once for clones */
- if (rsc->variant == pcmk_rsc_variant_clone) {
+ if (pcmk__is_clone(rsc)) {
break;
}
}
- rc = find_resource_attr(out, cib, XML_ATTR_ID, lookup_id, attr_set_type,
- attr_set, attr_id, attr_name, &local_attr_id);
+ rc = find_resource_attr(out, cib, PCMK_XA_ID, lookup_id, attr_set_type,
+ attr_set, attr_id, attr_name, NULL);
/* Post-order traversal.
* The root is always on the list and it is the last item. */
if((0 == depth) || (pcmk_rc_ok == rc)) {
@@ -191,7 +186,6 @@ find_matching_attr_resources_recursive(pcmk__output_t *out,
*result = g_list_append(*result, rsc);
}
- free(local_attr_id);
free(lookup_id);
}
@@ -206,7 +200,6 @@ find_matching_attr_resources(pcmk__output_t *out, pcmk_resource_t *rsc,
{
int rc = pcmk_rc_ok;
char *lookup_id = NULL;
- char *local_attr_id = NULL;
GList * result = NULL;
/* If --force is used, update only the requested resource (clone or primitive).
* Otherwise, if the primitive has the attribute, use that.
@@ -214,13 +207,9 @@ find_matching_attr_resources(pcmk__output_t *out, pcmk_resource_t *rsc,
if(force == TRUE) {
return g_list_append(result, rsc);
}
- if ((rsc->parent != NULL)
- && (rsc->parent->variant == pcmk_rsc_variant_clone)) {
- int rc = pcmk_rc_ok;
- char *local_attr_id = NULL;
- rc = find_resource_attr(out, cib, XML_ATTR_ID, rsc_id, attr_set_type,
- attr_set, attr_id, attr_name, &local_attr_id);
- free(local_attr_id);
+ if (pcmk__is_clone(rsc->parent)) {
+ int rc = find_resource_attr(out, cib, PCMK_XA_ID, rsc_id, attr_set_type,
+ attr_set, attr_id, attr_name, NULL);
if(rc != pcmk_rc_ok) {
rsc = rsc->parent;
@@ -230,13 +219,13 @@ find_matching_attr_resources(pcmk__output_t *out, pcmk_resource_t *rsc,
return g_list_append(result, rsc);
} else if ((rsc->parent == NULL) && (rsc->children != NULL)
- && (rsc->variant == pcmk_rsc_variant_clone)) {
+ && pcmk__is_clone(rsc)) {
pcmk_resource_t *child = rsc->children->data;
- if (child->variant == pcmk_rsc_variant_primitive) {
+ if (pcmk__is_primitive(child)) {
lookup_id = clone_strip(child->id); /* Could be a cloned group! */
- rc = find_resource_attr(out, cib, XML_ATTR_ID, lookup_id, attr_set_type,
- attr_set, attr_id, attr_name, &local_attr_id);
+ rc = find_resource_attr(out, cib, PCMK_XA_ID, lookup_id,
+ attr_set_type, attr_set, attr_id, attr_name, NULL);
if(rc == pcmk_rc_ok) {
rsc = child;
@@ -244,110 +233,167 @@ find_matching_attr_resources(pcmk__output_t *out, pcmk_resource_t *rsc,
attr_name, lookup_id, cmd, rsc_id);
}
- free(local_attr_id);
free(lookup_id);
}
return g_list_append(result, rsc);
}
/* If the resource is a group ==> children inherit the attribute if defined. */
- find_matching_attr_resources_recursive(out, &result, rsc, rsc_id, attr_set,
+ find_matching_attr_resources_recursive(out, &result, rsc, attr_set,
attr_set_type, attr_id, attr_name,
- cib, cmd, 0);
+ cib, 0);
return result;
}
-// \return Standard Pacemaker return code
-int
-cli_resource_update_attribute(pcmk_resource_t *rsc, const char *requested_name,
- const char *attr_set, const char *attr_set_type,
- const char *attr_id, const char *attr_name,
- const char *attr_value, gboolean recursive,
- cib_t *cib, int cib_options, gboolean force)
+static int
+update_element_attribute(pcmk__output_t *out, pcmk_resource_t *rsc,
+ cib_t *cib, const char *attr_name, const char *attr_value)
{
- pcmk__output_t *out = rsc->cluster->priv;
int rc = pcmk_rc_ok;
- char *found_attr_id = NULL;
+ if (cib == NULL) {
+ return ENOTCONN;
+ }
- GList/*<pcmk_resource_t*>*/ *resources = NULL;
- const char *top_id = pe__const_top_resource(rsc, false)->id;
+ crm_xml_add(rsc->xml, attr_name, attr_value);
- if ((attr_id == NULL) && !force) {
- find_resource_attr(out, cib, XML_ATTR_ID, top_id, NULL, NULL, NULL,
- attr_name, NULL);
+ rc = cib->cmds->replace(cib, PCMK_XE_RESOURCES, rsc->xml, cib_sync_call);
+ rc = pcmk_legacy2rc(rc);
+ if (rc == pcmk_rc_ok) {
+ out->info(out, "Set attribute: " PCMK_XA_NAME "=%s value=%s",
+ attr_name, attr_value);
}
- if (pcmk__str_eq(attr_set_type, XML_TAG_ATTR_SETS, pcmk__str_casei)) {
+ return rc;
+}
+
+static int
+resources_with_attr(pcmk__output_t *out, cib_t *cib, pcmk_resource_t *rsc,
+ const char *requested_name, const char *attr_set,
+ const char *attr_set_type, const char *attr_id,
+ const char *attr_name, const char *top_id, gboolean force,
+ GList **resources)
+{
+ if (pcmk__str_eq(attr_set_type, PCMK_XE_INSTANCE_ATTRIBUTES,
+ pcmk__str_casei)) {
if (!force) {
- rc = find_resource_attr(out, cib, XML_ATTR_ID, top_id,
- XML_TAG_META_SETS, attr_set, attr_id,
- attr_name, &found_attr_id);
- if ((rc == pcmk_rc_ok) && !out->is_quiet(out)) {
- out->err(out,
- "WARNING: There is already a meta attribute "
- "for '%s' called '%s' (id=%s)",
- top_id, attr_name, found_attr_id);
- out->err(out,
- " Delete '%s' first or use the force option "
- "to override", found_attr_id);
- }
- free(found_attr_id);
- if (rc == pcmk_rc_ok) {
+ xmlNode *xml_search = NULL;
+ int rc = pcmk_rc_ok;
+
+ rc = find_resource_attr(out, cib, PCMK_XA_ID, top_id,
+ PCMK_XE_META_ATTRIBUTES, attr_set, attr_id,
+ attr_name, &xml_search);
+
+ if (rc == pcmk_rc_ok || rc == ENOTUNIQ) {
+ char *found_attr_id = NULL;
+
+ found_attr_id = crm_element_value_copy(xml_search, PCMK_XA_ID);
+
+ if (!out->is_quiet(out)) {
+ out->err(out,
+ "WARNING: There is already a meta attribute "
+ "for '%s' called '%s' (id=%s)",
+ top_id, attr_name, found_attr_id);
+ out->err(out,
+ " Delete '%s' first or use the force option "
+ "to override", found_attr_id);
+ }
+
+ free(found_attr_id);
+ free_xml(xml_search);
return ENOTUNIQ;
}
- }
- resources = g_list_append(resources, rsc);
- } else if (pcmk__str_eq(attr_set_type, ATTR_SET_ELEMENT, pcmk__str_none)) {
- crm_xml_add(rsc->xml, attr_name, attr_value);
- CRM_ASSERT(cib != NULL);
- rc = cib->cmds->replace(cib, XML_CIB_TAG_RESOURCES, rsc->xml,
- cib_options);
- rc = pcmk_legacy2rc(rc);
- if (rc == pcmk_rc_ok) {
- out->info(out, "Set attribute: name=%s value=%s",
- attr_name, attr_value);
+ free_xml(xml_search);
}
- return rc;
+
+ *resources = g_list_append(*resources, rsc);
} else {
- resources = find_matching_attr_resources(out, rsc, requested_name,
- attr_set, attr_set_type,
- attr_id, attr_name, cib,
- "update", force);
+ *resources = find_matching_attr_resources(out, rsc, requested_name,
+ attr_set, attr_set_type,
+ attr_id, attr_name, cib,
+ "update", force);
}
/* If the user specified attr_set or attr_id, the intent is to modify a
* single resource, which will be the last item in the list.
*/
if ((attr_set != NULL) || (attr_id != NULL)) {
- GList *last = g_list_last(resources);
+ GList *last = g_list_last(*resources);
+
+ *resources = g_list_remove_link(*resources, last);
+ g_list_free(*resources);
+ *resources = last;
+ }
+
+ return pcmk_rc_ok;
+}
+
+static void
+free_attr_update_data(gpointer data)
+{
+ attr_update_data_t *ud = data;
+
+ if (ud == NULL) {
+ return;
+ }
+
+ free(ud->attr_set_type);
+ free(ud->attr_set_id);
+ free(ud->attr_name);
+ free(ud->attr_value);
+ free(ud->given_rsc_id);
+ free(ud->found_attr_id);
+ free(ud);
+}
+
+static int
+update_attribute(pcmk_resource_t *rsc, const char *requested_name,
+ const char *attr_set, const char *attr_set_type,
+ const char *attr_id, const char *attr_name,
+ const char *attr_value, gboolean recursive, cib_t *cib,
+ gboolean force, GList **results)
+{
+ pcmk__output_t *out = rsc->cluster->priv;
+ int rc = pcmk_rc_ok;
+
+ GList/*<pcmk_resource_t*>*/ *resources = NULL;
+ const char *top_id = pe__const_top_resource(rsc, false)->id;
+
+ if ((attr_id == NULL) && !force) {
+ find_resource_attr(out, cib, PCMK_XA_ID, top_id, NULL, NULL, NULL,
+ attr_name, NULL);
+ }
- resources = g_list_remove_link(resources, last);
- g_list_free(resources);
- resources = last;
+ rc = resources_with_attr(out, cib, rsc, requested_name, attr_set, attr_set_type,
+ attr_id, attr_name, top_id, force, &resources);
+
+ if (rc != pcmk_rc_ok) {
+ return rc;
}
for (GList *iter = resources; iter != NULL; iter = iter->next) {
char *lookup_id = NULL;
char *local_attr_set = NULL;
+ char *found_attr_id = NULL;
const char *rsc_attr_id = attr_id;
const char *rsc_attr_set = attr_set;
xmlNode *xml_top = NULL;
xmlNode *xml_obj = NULL;
- found_attr_id = NULL;
+ xmlNode *xml_search = NULL;
rsc = (pcmk_resource_t *) iter->data;
lookup_id = clone_strip(rsc->id); /* Could be a cloned group! */
- rc = find_resource_attr(out, cib, XML_ATTR_ID, lookup_id, attr_set_type,
- attr_set, attr_id, attr_name, &found_attr_id);
+ rc = find_resource_attr(out, cib, PCMK_XA_ID, lookup_id, attr_set_type,
+ attr_set, attr_id, attr_name, &xml_search);
switch (rc) {
case pcmk_rc_ok:
- crm_debug("Found a match for name=%s: id=%s",
- attr_name, found_attr_id);
+ found_attr_id = crm_element_value_copy(xml_search, PCMK_XA_ID);
+ crm_debug("Found a match for " PCMK_XA_NAME "='%s': "
+ PCMK_XA_ID "='%s'", attr_name, found_attr_id);
rsc_attr_id = found_attr_id;
break;
@@ -363,16 +409,17 @@ cli_resource_update_attribute(pcmk_resource_t *rsc, const char *requested_name,
rsc_attr_id = found_attr_id;
}
- xml_top = create_xml_node(NULL, (const char *) rsc->xml->name);
- crm_xml_add(xml_top, XML_ATTR_ID, lookup_id);
+ xml_top = pcmk__xe_create(NULL, (const char *) rsc->xml->name);
+ crm_xml_add(xml_top, PCMK_XA_ID, lookup_id);
- xml_obj = create_xml_node(xml_top, attr_set_type);
- crm_xml_add(xml_obj, XML_ATTR_ID, rsc_attr_set);
+ xml_obj = pcmk__xe_create(xml_top, attr_set_type);
+ crm_xml_add(xml_obj, PCMK_XA_ID, rsc_attr_set);
break;
default:
free(lookup_id);
free(found_attr_id);
+ free_xml(xml_search);
g_list_free(resources);
return rc;
}
@@ -385,66 +432,114 @@ cli_resource_update_attribute(pcmk_resource_t *rsc, const char *requested_name,
crm_log_xml_debug(xml_top, "Update");
- rc = cib->cmds->modify(cib, XML_CIB_TAG_RESOURCES, xml_top,
- cib_options);
+ rc = cib->cmds->modify(cib, PCMK_XE_RESOURCES, xml_top, cib_sync_call);
rc = pcmk_legacy2rc(rc);
if (rc == pcmk_rc_ok) {
- out->info(out, "Set '%s' option: id=%s%s%s%s%s value=%s",
- lookup_id, found_attr_id,
- ((rsc_attr_set == NULL)? "" : " set="),
- pcmk__s(rsc_attr_set, ""),
- ((attr_name == NULL)? "" : " name="),
- pcmk__s(attr_name, ""), attr_value);
+ attr_update_data_t *ud = pcmk__assert_alloc(1, sizeof(attr_update_data_t));
+
+ if (attr_set_type == NULL) {
+ attr_set_type = (const char *) xml_search->parent->name;
+ }
+
+ if (rsc_attr_set == NULL) {
+ rsc_attr_set = crm_element_value(xml_search->parent, PCMK_XA_ID);
+ }
+
+ ud->attr_set_type = pcmk__str_copy(attr_set_type);
+ ud->attr_set_id = pcmk__str_copy(rsc_attr_set);
+ ud->attr_name = pcmk__str_copy(attr_name);
+ ud->attr_value = pcmk__str_copy(attr_value);
+ ud->given_rsc_id = pcmk__str_copy(lookup_id);
+ ud->found_attr_id = pcmk__str_copy(found_attr_id);
+ ud->rsc = rsc;
+
+ *results = g_list_append(*results, ud);
}
free_xml(xml_top);
+ free_xml(xml_search);
free(lookup_id);
free(found_attr_id);
free(local_attr_set);
if (recursive
- && pcmk__str_eq(attr_set_type, XML_TAG_META_SETS,
+ && pcmk__str_eq(attr_set_type, PCMK_XE_META_ATTRIBUTES,
pcmk__str_casei)) {
- GList *lpc = NULL;
- static bool need_init = true;
-
- if (need_init) {
- need_init = false;
- pcmk__unpack_constraints(rsc->cluster);
- pe__clear_resource_flags_on_all(rsc->cluster,
- pcmk_rsc_detect_loop);
- }
-
/* We want to set the attribute only on resources explicitly
* colocated with this one, so we use rsc->rsc_cons_lhs directly
* rather than the with_this_colocations() method.
*/
- pe__set_resource_flags(rsc, pcmk_rsc_detect_loop);
- for (lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
+ pcmk__set_rsc_flags(rsc, pcmk_rsc_detect_loop);
+ for (GList *lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
crm_debug("Checking %s %d", cons->id, cons->score);
- if (!pcmk_is_set(cons->dependent->flags, pcmk_rsc_detect_loop)
- && (cons->score > 0)) {
- crm_debug("Setting %s=%s for dependent resource %s",
- attr_name, attr_value, cons->dependent->id);
- cli_resource_update_attribute(cons->dependent,
- cons->dependent->id, NULL,
- attr_set_type, NULL,
- attr_name, attr_value,
- recursive, cib, cib_options,
- force);
+
+ if (pcmk_is_set(cons->dependent->flags, pcmk_rsc_detect_loop)
+ || (cons->score <= 0)) {
+ continue;
}
+
+ crm_debug("Setting %s=%s for dependent resource %s",
+ attr_name, attr_value, cons->dependent->id);
+ update_attribute(cons->dependent, cons->dependent->id, NULL,
+ attr_set_type, NULL, attr_name, attr_value,
+ recursive, cib, force, results);
}
}
}
+
g_list_free(resources);
return rc;
}
// \return Standard Pacemaker return code
int
+cli_resource_update_attribute(pcmk_resource_t *rsc, const char *requested_name,
+ const char *attr_set, const char *attr_set_type,
+ const char *attr_id, const char *attr_name,
+ const char *attr_value, gboolean recursive,
+ cib_t *cib, gboolean force)
+{
+ static bool need_init = true;
+ int rc = pcmk_rc_ok;
+
+ GList *results = NULL;
+ pcmk__output_t *out = rsc->cluster->priv;
+
+ /* If we were asked to update the attribute in a resource element (for
+ * instance, <primitive class="ocf">) there's really not much we need to do.
+ */
+ if (pcmk__str_eq(attr_set_type, ATTR_SET_ELEMENT, pcmk__str_none)) {
+ return update_element_attribute(out, rsc, cib, attr_name, attr_value);
+ }
+
+ /* One time initialization - clear flags so we can detect loops */
+ if (need_init) {
+ need_init = false;
+ pcmk__unpack_constraints(rsc->cluster);
+ pe__clear_resource_flags_on_all(rsc->cluster, pcmk_rsc_detect_loop);
+ }
+
+ rc = update_attribute(rsc, requested_name, attr_set, attr_set_type,
+ attr_id, attr_name, attr_value, recursive, cib,
+ force, &results);
+
+ if (rc == pcmk_rc_ok) {
+ if (results == NULL) {
+ return rc;
+ }
+
+ out->message(out, "attribute-changed-list", results);
+ g_list_free_full(results, free_attr_update_data);
+ }
+
+ return rc;
+}
+
+// \return Standard Pacemaker return code
+int
cli_resource_delete_attribute(pcmk_resource_t *rsc, const char *requested_name,
const char *attr_set, const char *attr_set_type,
const char *attr_id, const char *attr_name,
@@ -455,22 +550,21 @@ cli_resource_delete_attribute(pcmk_resource_t *rsc, const char *requested_name,
GList/*<pcmk_resource_t*>*/ *resources = NULL;
if ((attr_id == NULL) && !force) {
- find_resource_attr(out, cib, XML_ATTR_ID,
+ find_resource_attr(out, cib, PCMK_XA_ID,
pe__const_top_resource(rsc, false)->id, NULL,
NULL, NULL, attr_name, NULL);
}
- if (pcmk__str_eq(attr_set_type, XML_TAG_META_SETS, pcmk__str_casei)) {
+ if (pcmk__str_eq(attr_set_type, PCMK_XE_META_ATTRIBUTES, pcmk__str_casei)) {
resources = find_matching_attr_resources(out, rsc, requested_name,
attr_set, attr_set_type,
attr_id, attr_name, cib,
"delete", force);
} else if (pcmk__str_eq(attr_set_type, ATTR_SET_ELEMENT, pcmk__str_none)) {
- xml_remove_prop(rsc->xml, attr_name);
+ pcmk__xe_remove_attr(rsc->xml, attr_name);
CRM_ASSERT(cib != NULL);
- rc = cib->cmds->replace(cib, XML_CIB_TAG_RESOURCES, rsc->xml,
- cib_options);
+ rc = cib->cmds->replace(cib, PCMK_XE_RESOURCES, rsc->xml, cib_options);
rc = pcmk_legacy2rc(rc);
if (rc == pcmk_rc_ok) {
out->info(out, "Deleted attribute: %s", attr_name);
@@ -484,25 +578,29 @@ cli_resource_delete_attribute(pcmk_resource_t *rsc, const char *requested_name,
for (GList *iter = resources; iter != NULL; iter = iter->next) {
char *lookup_id = NULL;
xmlNode *xml_obj = NULL;
+ xmlNode *xml_search = NULL;
char *found_attr_id = NULL;
const char *rsc_attr_id = attr_id;
rsc = (pcmk_resource_t *) iter->data;
lookup_id = clone_strip(rsc->id);
- rc = find_resource_attr(out, cib, XML_ATTR_ID, lookup_id, attr_set_type,
- attr_set, attr_id, attr_name, &found_attr_id);
+ rc = find_resource_attr(out, cib, PCMK_XA_ID, lookup_id, attr_set_type,
+ attr_set, attr_id, attr_name, &xml_search);
switch (rc) {
case pcmk_rc_ok:
+ found_attr_id = crm_element_value_copy(xml_search, PCMK_XA_ID);
+ free_xml(xml_search);
break;
case ENXIO:
free(lookup_id);
- rc = pcmk_rc_ok;
+ free_xml(xml_search);
continue;
default:
free(lookup_id);
+ free_xml(xml_search);
g_list_free(resources);
return rc;
}
@@ -515,16 +613,15 @@ cli_resource_delete_attribute(pcmk_resource_t *rsc, const char *requested_name,
crm_log_xml_debug(xml_obj, "Delete");
CRM_ASSERT(cib);
- rc = cib->cmds->remove(cib, XML_CIB_TAG_RESOURCES, xml_obj,
- cib_options);
+ rc = cib->cmds->remove(cib, PCMK_XE_RESOURCES, xml_obj, cib_options);
rc = pcmk_legacy2rc(rc);
if (rc == pcmk_rc_ok) {
- out->info(out, "Deleted '%s' option: id=%s%s%s%s%s",
+ out->info(out, "Deleted '%s' option: " PCMK_XA_ID "=%s%s%s%s%s",
lookup_id, found_attr_id,
((attr_set == NULL)? "" : " set="),
pcmk__s(attr_set, ""),
- ((attr_name == NULL)? "" : " name="),
+ ((attr_name == NULL)? "" : " " PCMK_XA_NAME "="),
pcmk__s(attr_name, ""));
}
@@ -556,21 +653,21 @@ send_lrm_rsc_op(pcmk_ipc_api_t *controld_api, bool do_fail_resource,
out->err(out, "Resource %s not found", rsc_id);
return ENXIO;
- } else if (rsc->variant != pcmk_rsc_variant_primitive) {
+ } else if (!pcmk__is_primitive(rsc)) {
out->err(out, "We can only process primitive resources, not %s", rsc_id);
return EINVAL;
}
- rsc_class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
- rsc_provider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER),
- rsc_type = crm_element_value(rsc->xml, XML_ATTR_TYPE);
+ rsc_class = crm_element_value(rsc->xml, PCMK_XA_CLASS);
+ rsc_provider = crm_element_value(rsc->xml, PCMK_XA_PROVIDER),
+ rsc_type = crm_element_value(rsc->xml, PCMK_XA_TYPE);
if ((rsc_class == NULL) || (rsc_type == NULL)) {
out->err(out, "Resource %s does not have a class and type", rsc_id);
return EINVAL;
}
{
- pcmk_node_t *node = pe_find_node(scheduler->nodes, host_uname);
+ pcmk_node_t *node = pcmk_find_node(scheduler, host_uname);
if (node == NULL) {
out->err(out, "Node %s not found", host_uname);
@@ -585,8 +682,8 @@ send_lrm_rsc_op(pcmk_ipc_api_t *controld_api, bool do_fail_resource,
cib_only = true;
}
}
- if (!cib_only && pe__is_guest_or_remote_node(node)) {
- node = pe__current_node(node->details->remote_rsc);
+ if (!cib_only && pcmk__is_pacemaker_remote_node(node)) {
+ node = pcmk__current_node(node->details->remote_rsc);
if (node == NULL) {
out->err(out, "No cluster connection to Pacemaker Remote node %s detected",
host_uname);
@@ -668,7 +765,7 @@ clear_rsc_failures(pcmk__output_t *out, pcmk_ipc_api_t *controld_api,
int rc = pcmk_rc_ok;
const char *failed_value = NULL;
const char *failed_id = NULL;
- const char *interval_ms_s = NULL;
+ char *interval_ms_s = NULL;
GHashTable *rscs = NULL;
GHashTableIter iter;
@@ -680,15 +777,17 @@ clear_rsc_failures(pcmk__output_t *out, pcmk_ipc_api_t *controld_api,
// Normalize interval to milliseconds for comparison to history entry
if (operation) {
- interval_ms_s = crm_strdup_printf("%u",
- crm_parse_interval_spec(interval_spec));
+ guint interval_ms = 0U;
+
+ pcmk_parse_interval_spec(interval_spec, &interval_ms);
+ interval_ms_s = crm_strdup_printf("%u", interval_ms);
}
- for (xmlNode *xml_op = pcmk__xml_first_child(scheduler->failed);
- xml_op != NULL;
- xml_op = pcmk__xml_next(xml_op)) {
+ for (xmlNode *xml_op = pcmk__xe_first_child(scheduler->failed, NULL, NULL,
+ NULL);
+ xml_op != NULL; xml_op = pcmk__xe_next(xml_op)) {
- failed_id = crm_element_value(xml_op, XML_LRM_ATTR_RSCID);
+ failed_id = crm_element_value(xml_op, PCMK__XA_RSC_ID);
if (failed_id == NULL) {
// Malformed history entry, should never happen
continue;
@@ -708,20 +807,20 @@ clear_rsc_failures(pcmk__output_t *out, pcmk_ipc_api_t *controld_api,
}
// Host name should always have been provided by this point
- failed_value = crm_element_value(xml_op, XML_ATTR_UNAME);
+ failed_value = crm_element_value(xml_op, PCMK_XA_UNAME);
if (!pcmk__str_eq(node_name, failed_value, pcmk__str_casei)) {
continue;
}
// No operation specified means all operations match
if (operation) {
- failed_value = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
+ failed_value = crm_element_value(xml_op, PCMK_XA_OPERATION);
if (!pcmk__str_eq(operation, failed_value, pcmk__str_casei)) {
continue;
}
// Interval (if operation was specified) defaults to 0 (not all)
- failed_value = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL_MS);
+ failed_value = crm_element_value(xml_op, PCMK_META_INTERVAL);
if (!pcmk__str_eq(interval_ms_s, failed_value, pcmk__str_casei)) {
continue;
}
@@ -730,6 +829,8 @@ clear_rsc_failures(pcmk__output_t *out, pcmk_ipc_api_t *controld_api,
g_hash_table_add(rscs, (gpointer) failed_id);
}
+ free(interval_ms_s);
+
g_hash_table_iter_init(&iter, rscs);
while (g_hash_table_iter_next(&iter, (gpointer *) &failed_id, NULL)) {
crm_debug("Erasing failures of %s on %s", failed_id, node_name);
@@ -751,7 +852,7 @@ clear_rsc_fail_attrs(const pcmk_resource_t *rsc, const char *operation,
int attr_options = pcmk__node_attr_none;
char *rsc_name = rsc_fail_name(rsc);
- if (pe__is_guest_or_remote_node(node)) {
+ if (pcmk__is_pacemaker_remote_node(node)) {
attr_options |= pcmk__node_attr_remote;
}
@@ -830,7 +931,7 @@ cli_resource_delete(pcmk_ipc_api_t *controld_api, const char *host_uname,
return pcmk_rc_ok;
}
- node = pe_find_node(scheduler->nodes, host_uname);
+ node = pcmk_find_node(scheduler, host_uname);
if (node == NULL) {
out->err(out, "Unable to clean up %s because node %s not found",
@@ -890,13 +991,13 @@ cli_cleanup_all(pcmk_ipc_api_t *controld_api, const char *node_name,
}
if (node_name) {
- pcmk_node_t *node = pe_find_node(scheduler->nodes, node_name);
+ pcmk_node_t *node = pcmk_find_node(scheduler, node_name);
if (node == NULL) {
out->err(out, "Unknown node: %s", node_name);
return ENXIO;
}
- if (pe__is_guest_or_remote_node(node)) {
+ if (pcmk__is_pacemaker_remote_node(node)) {
attr_options |= pcmk__node_attr_remote;
}
}
@@ -939,12 +1040,12 @@ static void
check_role(resource_checks_t *checks)
{
const char *role_s = g_hash_table_lookup(checks->rsc->meta,
- XML_RSC_ATTR_TARGET_ROLE);
+ PCMK_META_TARGET_ROLE);
if (role_s == NULL) {
return;
}
- switch (text2role(role_s)) {
+ switch (pcmk_parse_role(role_s)) {
case pcmk_role_stopped:
checks->flags |= rsc_remain_stopped;
break;
@@ -965,7 +1066,7 @@ static void
check_managed(resource_checks_t *checks)
{
const char *managed_s = g_hash_table_lookup(checks->rsc->meta,
- XML_RSC_ATTR_MANAGED);
+ PCMK_META_IS_MANAGED);
if ((managed_s != NULL) && !crm_is_true(managed_s)) {
checks->flags |= rsc_unmanaged;
@@ -1075,12 +1176,12 @@ generate_resource_params(pcmk_resource_t *rsc, pcmk_node_t *node,
if (params != NULL) {
g_hash_table_iter_init(&iter, params);
while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
- g_hash_table_insert(combined, strdup(key), strdup(value));
+ pcmk__insert_dup(combined, key, value);
}
}
meta = pcmk__strkey_table(free, free);
- get_meta_attributes(meta, rsc, node, scheduler);
+ get_meta_attributes(meta, rsc, NULL, scheduler);
if (meta != NULL) {
g_hash_table_iter_init(&iter, meta);
while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
@@ -1150,7 +1251,7 @@ get_active_resources(const char *host, GList *rsc_list)
* other than the first, we can't otherwise tell which resources are
* stopping and starting.
*/
- if (rsc->variant == pcmk_rsc_variant_group) {
+ if (pcmk__is_group(rsc)) {
active = g_list_concat(active,
get_active_resources(host, rsc->children));
} else if (resource_is_running_on(rsc, host)) {
@@ -1192,18 +1293,16 @@ static void display_list(pcmk__output_t *out, GList *items, const char *tag)
* \return Standard Pacemaker return code
* \note On success, caller is responsible for freeing memory allocated for
* scheduler->now.
- * \todo This follows the example of other callers of cli_config_update()
- * and returns ENOKEY ("Required key not available") if that fails,
- * but perhaps pcmk_rc_schema_validation would be better in that case.
*/
int
update_scheduler_input(pcmk_scheduler_t *scheduler, xmlNode **xml)
{
- if (cli_config_update(xml, NULL, FALSE) == FALSE) {
- return ENOKEY;
+ int rc = pcmk_update_configured_schema(xml, false);
+
+ if (rc == pcmk_rc_ok) {
+ scheduler->input = *xml;
+ scheduler->now = crm_time_new(NULL);
}
- scheduler->input = *xml;
- scheduler->now = crm_time_new(NULL);
return pcmk_rc_ok;
}
@@ -1254,7 +1353,7 @@ update_dataset(cib_t *cib, pcmk_scheduler_t *scheduler, bool simulate)
pcmk__output_t *out = scheduler->priv;
pe_reset_working_set(scheduler);
- pe__set_working_set_flags(scheduler,
+ pcmk__set_scheduler_flags(scheduler,
pcmk_sched_no_counts|pcmk_sched_no_compat);
rc = update_scheduler_input_to_cib(out, scheduler, cib);
if (rc != pcmk_rc_ok) {
@@ -1274,10 +1373,9 @@ update_dataset(cib_t *cib, pcmk_scheduler_t *scheduler, bool simulate)
goto done;
}
- rc = write_xml_file(scheduler->input, shadow_file, FALSE);
-
- if (rc < 0) {
- out->err(out, "Could not populate shadow cib: %s (%d)", pcmk_strerror(rc), rc);
+ rc = pcmk__xml_write_file(scheduler->input, shadow_file, false, NULL);
+ if (rc != pcmk_rc_ok) {
+ out->err(out, "Could not populate shadow cib: %s", pcmk_rc_str(rc));
goto done;
}
@@ -1285,7 +1383,8 @@ update_dataset(cib_t *cib, pcmk_scheduler_t *scheduler, bool simulate)
rc = pcmk_legacy2rc(rc);
if (rc != pcmk_rc_ok) {
- out->err(out, "Could not connect to shadow cib: %s (%d)", pcmk_rc_str(rc), rc);
+ out->err(out, "Could not connect to shadow cib: %s",
+ pcmk_rc_str(rc));
goto done;
}
@@ -1325,11 +1424,11 @@ update_dataset(cib_t *cib, pcmk_scheduler_t *scheduler, bool simulate)
*
* \return Maximum stop timeout for \p rsc (in milliseconds)
*/
-static int
+static guint
max_rsc_stop_timeout(pcmk_resource_t *rsc)
{
long long result_ll;
- int max_delay = 0;
+ guint max_delay = 0;
xmlNode *config = NULL;
GHashTable *meta = NULL;
@@ -1341,12 +1440,13 @@ max_rsc_stop_timeout(pcmk_resource_t *rsc)
if (rsc->children != NULL) {
for (GList *iter = rsc->children; iter; iter = iter->next) {
pcmk_resource_t *child = iter->data;
- int delay = max_rsc_stop_timeout(child);
+ guint delay = max_rsc_stop_timeout(child);
if (delay > max_delay) {
- pe_rsc_trace(rsc,
- "Maximum stop timeout for %s is now %s due to %s",
- rsc->id, pcmk__readable_interval(delay), child->id);
+ pcmk__rsc_trace(rsc,
+ "Maximum stop timeout for %s is now %s "
+ "due to %s", rsc->id,
+ pcmk__readable_interval(delay), child->id);
max_delay = delay;
}
}
@@ -1362,10 +1462,9 @@ max_rsc_stop_timeout(pcmk_resource_t *rsc)
* @TODO This currently ignores node (which might matter for rules)
*/
meta = pcmk__unpack_action_meta(rsc, NULL, PCMK_ACTION_STOP, 0, config);
- if ((pcmk__scan_ll(g_hash_table_lookup(meta, XML_ATTR_TIMEOUT),
- &result_ll, -1LL) == pcmk_rc_ok)
- && (result_ll >= 0) && (result_ll <= INT_MAX)) {
- max_delay = (int) result_ll;
+ if ((pcmk__scan_ll(g_hash_table_lookup(meta, PCMK_META_TIMEOUT),
+ &result_ll, -1LL) == pcmk_rc_ok) && (result_ll >= 0)) {
+ max_delay = (guint) QB_MIN(result_ll, UINT_MAX);
}
g_hash_table_destroy(meta);
@@ -1387,26 +1486,26 @@ max_rsc_stop_timeout(pcmk_resource_t *rsc)
* throttling, or any demotions needed. It checks the stop timeout, even
* if the resources in question are actually being started.
*/
-static int
+static guint
wait_time_estimate(pcmk_scheduler_t *scheduler, const GList *resources)
{
- int max_delay = 0;
+ guint max_delay = 0U;
// Find maximum stop timeout in milliseconds
for (const GList *item = resources; item != NULL; item = item->next) {
pcmk_resource_t *rsc = pe_find_resource(scheduler->resources,
(const char *) item->data);
- int delay = max_rsc_stop_timeout(rsc);
+ guint delay = max_rsc_stop_timeout(rsc);
if (delay > max_delay) {
- pe_rsc_trace(rsc,
- "Wait time is now %s due to %s",
- pcmk__readable_interval(delay), rsc->id);
+ pcmk__rsc_trace(rsc,
+ "Wait time is now %s due to %s",
+ pcmk__readable_interval(delay), rsc->id);
max_delay = delay;
}
}
- return (max_delay / 1000) + 5;
+ return (max_delay / 1000U) + 5U;
}
#define waiting_for_starts(d, r, h) ((d != NULL) || \
@@ -1438,15 +1537,15 @@ wait_time_estimate(pcmk_scheduler_t *scheduler, const GList *resources)
int
cli_resource_restart(pcmk__output_t *out, pcmk_resource_t *rsc,
const pcmk_node_t *node, const char *move_lifetime,
- int timeout_ms, cib_t *cib, int cib_options,
+ guint timeout_ms, cib_t *cib, int cib_options,
gboolean promoted_role_only, gboolean force)
{
int rc = pcmk_rc_ok;
int lpc = 0;
int before = 0;
- int step_timeout_s = 0;
- int sleep_interval = 2;
- int timeout = timeout_ms / 1000;
+ guint step_timeout_s = 0;
+ guint sleep_interval = 2U;
+ guint timeout = timeout_ms / 1000U;
bool stop_via_ban = false;
char *rsc_id = NULL;
@@ -1468,14 +1567,14 @@ cli_resource_restart(pcmk__output_t *out, pcmk_resource_t *rsc,
/* If the implicit resource or primitive resource of a bundle is given, operate on the
* bundle itself instead.
*/
- if (pe_rsc_is_bundled(rsc)) {
+ if (pcmk__is_bundled(rsc)) {
rsc = parent->parent;
}
running = resource_is_running_on(rsc, host);
- if (pe_rsc_is_clone(parent) && !running) {
- if (pe_rsc_is_unique_clone(parent)) {
+ if (pcmk__is_clone(parent) && !running) {
+ if (pcmk__is_unique_clone(parent)) {
lookup_id = strdup(rsc->id);
} else {
lookup_id = clone_strip(rsc->id);
@@ -1504,16 +1603,16 @@ cli_resource_restart(pcmk__output_t *out, pcmk_resource_t *rsc,
rsc_id = strdup(rsc->id);
- if (pe_rsc_is_unique_clone(parent)) {
+ if (pcmk__is_unique_clone(parent)) {
lookup_id = strdup(rsc->id);
} else {
lookup_id = clone_strip(rsc->id);
}
if (host) {
- if (pe_rsc_is_clone(rsc) || pe_bundle_replicas(rsc)) {
+ if (pcmk__is_clone(rsc) || pe_bundle_replicas(rsc)) {
stop_via_ban = true;
- } else if (pe_rsc_is_clone(parent)) {
+ } else if (pcmk__is_clone(parent)) {
stop_via_ban = true;
free(lookup_id);
lookup_id = strdup(parent->id);
@@ -1563,22 +1662,33 @@ cli_resource_restart(pcmk__output_t *out, pcmk_resource_t *rsc,
out->quiet = true;
rc = cli_resource_ban(out, lookup_id, host, move_lifetime, cib,
cib_options, promoted_role_only,
- PCMK__ROLE_PROMOTED);
+ PCMK_ROLE_PROMOTED);
} else {
- /* Stop the resource by setting target-role to Stopped.
- * Remember any existing target-role so we can restore it later
- * (though it only makes any difference if it's Unpromoted).
+ xmlNode *xml_search = NULL;
+
+ /* Stop the resource by setting PCMK_META_TARGET_ROLE to Stopped.
+ * Remember any existing PCMK_META_TARGET_ROLE so we can restore it
+ * later (though it only makes any difference if it's Unpromoted).
*/
- find_resource_attr(out, cib, XML_NVPAIR_ATTR_VALUE, lookup_id, NULL, NULL,
- NULL, XML_RSC_ATTR_TARGET_ROLE, &orig_target_role);
- rc = cli_resource_update_attribute(rsc, rsc_id, NULL, XML_TAG_META_SETS,
- NULL, XML_RSC_ATTR_TARGET_ROLE,
+ rc = find_resource_attr(out, cib, PCMK_XA_VALUE, lookup_id, NULL, NULL, NULL,
+ PCMK_META_TARGET_ROLE, &xml_search);
+
+ if (rc == pcmk_rc_ok) {
+ orig_target_role = crm_element_value_copy(xml_search, PCMK_XA_VALUE);
+ }
+
+ free_xml(xml_search);
+
+ rc = cli_resource_update_attribute(rsc, rsc_id, NULL,
+ PCMK_XE_META_ATTRIBUTES, NULL,
+ PCMK_META_TARGET_ROLE,
PCMK_ACTION_STOPPED, FALSE, cib,
- cib_options, force);
+ force);
}
if(rc != pcmk_rc_ok) {
- out->err(out, "Could not set target-role for %s: %s (%d)", rsc_id, pcmk_rc_str(rc), rc);
+ out->err(out, "Could not set " PCMK_META_TARGET_ROLE " for %s: %s (%d)",
+ rsc_id, pcmk_rc_str(rc), rc);
if (current_active != NULL) {
g_list_free_full(current_active, free);
current_active = NULL;
@@ -1616,7 +1726,7 @@ cli_resource_restart(pcmk__output_t *out, pcmk_resource_t *rsc,
sleep(sleep_interval);
if(timeout) {
timeout -= sleep_interval;
- crm_trace("%ds remaining", timeout);
+ crm_trace("%us remaining", timeout);
}
rc = update_dataset(cib, scheduler, FALSE);
if(rc != pcmk_rc_ok) {
@@ -1651,20 +1761,23 @@ cli_resource_restart(pcmk__output_t *out, pcmk_resource_t *rsc,
rc = cli_resource_clear(lookup_id, host, NULL, cib, cib_options, true, force);
} else if (orig_target_role) {
- rc = cli_resource_update_attribute(rsc, rsc_id, NULL, XML_TAG_META_SETS,
- NULL, XML_RSC_ATTR_TARGET_ROLE,
- orig_target_role, FALSE, cib,
- cib_options, force);
+ rc = cli_resource_update_attribute(rsc, rsc_id, NULL,
+ PCMK_XE_META_ATTRIBUTES, NULL,
+ PCMK_META_TARGET_ROLE,
+ orig_target_role, FALSE, cib, force);
free(orig_target_role);
orig_target_role = NULL;
} else {
- rc = cli_resource_delete_attribute(rsc, rsc_id, NULL, XML_TAG_META_SETS,
- NULL, XML_RSC_ATTR_TARGET_ROLE, cib,
+ rc = cli_resource_delete_attribute(rsc, rsc_id, NULL,
+ PCMK_XE_META_ATTRIBUTES, NULL,
+ PCMK_META_TARGET_ROLE, cib,
cib_options, force);
}
if(rc != pcmk_rc_ok) {
- out->err(out, "Could not unset target-role for %s: %s (%d)", rsc_id, pcmk_rc_str(rc), rc);
+ out->err(out,
+ "Could not unset " PCMK_META_TARGET_ROLE " for %s: %s (%d)",
+ rsc_id, pcmk_rc_str(rc), rc);
goto done;
}
@@ -1731,14 +1844,16 @@ cli_resource_restart(pcmk__output_t *out, pcmk_resource_t *rsc,
if (stop_via_ban) {
cli_resource_clear(lookup_id, host, NULL, cib, cib_options, true, force);
} else if (orig_target_role) {
- cli_resource_update_attribute(rsc, rsc_id, NULL, XML_TAG_META_SETS, NULL,
- XML_RSC_ATTR_TARGET_ROLE, orig_target_role,
- FALSE, cib, cib_options, force);
+ cli_resource_update_attribute(rsc, rsc_id, NULL,
+ PCMK_XE_META_ATTRIBUTES, NULL,
+ PCMK_META_TARGET_ROLE, orig_target_role,
+ FALSE, cib, force);
free(orig_target_role);
} else {
- cli_resource_delete_attribute(rsc, rsc_id, NULL, XML_TAG_META_SETS,
- NULL, XML_RSC_ATTR_TARGET_ROLE, cib,
- cib_options, force);
+ cli_resource_delete_attribute(rsc, rsc_id, NULL,
+ PCMK_XE_META_ATTRIBUTES, NULL,
+ PCMK_META_TARGET_ROLE, cib, cib_options,
+ force);
}
done:
@@ -1809,7 +1924,7 @@ print_pending_actions(pcmk__output_t *out, GList *actions)
if (a->node) {
out->info(out, "\tAction %d: %s\ton %s",
- a->id, a->uuid, pe__node_name(a->node));
+ a->id, a->uuid, pcmk__node_name(a->node));
} else {
out->info(out, "\tAction %d: %s", a->id, a->uuid);
}
@@ -1839,32 +1954,47 @@ print_pending_actions(pcmk__output_t *out, GList *actions)
* \return Standard Pacemaker return code
*/
int
-wait_till_stable(pcmk__output_t *out, int timeout_ms, cib_t * cib)
+wait_till_stable(pcmk__output_t *out, guint timeout_ms, cib_t * cib)
{
pcmk_scheduler_t *scheduler = NULL;
xmlXPathObjectPtr search;
int rc = pcmk_rc_ok;
bool pending_unknown_state_resources;
- int timeout_s = timeout_ms? ((timeout_ms + 999) / 1000) : WAIT_DEFAULT_TIMEOUT_S;
- time_t expire_time = time(NULL) + timeout_s;
+ time_t expire_time = time(NULL);
time_t time_diff;
bool printed_version_warning = out->is_quiet(out); // i.e. don't print if quiet
+ char *xpath = NULL;
+
+ if (timeout_ms == 0) {
+ expire_time += WAIT_DEFAULT_TIMEOUT_S;
+ } else {
+ expire_time += (timeout_ms + 999) / 1000;
+ }
scheduler = pe_new_working_set();
if (scheduler == NULL) {
return ENOMEM;
}
+ xpath = crm_strdup_printf("/" PCMK_XE_CIB "/" PCMK_XE_STATUS
+ "/" PCMK__XE_NODE_STATE "/" PCMK__XE_LRM
+ "/" PCMK__XE_LRM_RESOURCES
+ "/" PCMK__XE_LRM_RESOURCE
+ "/" PCMK__XE_LRM_RSC_OP
+ "[@" PCMK__XA_RC_CODE "='%d']",
+ PCMK_OCF_UNKNOWN);
do {
/* Abort if timeout is reached */
time_diff = expire_time - time(NULL);
- if (time_diff > 0) {
- crm_info("Waiting up to %lld seconds for cluster actions to complete", (long long) time_diff);
- } else {
+ if (time_diff <= 0) {
print_pending_actions(out, scheduler->actions);
- pe_free_working_set(scheduler);
- return ETIME;
+ rc = ETIME;
+ break;
}
+
+ crm_info("Waiting up to %lld seconds for cluster actions to complete",
+ (long long) time_diff);
+
if (rc == pcmk_rc_ok) { /* this avoids sleep on first loop iteration */
sleep(WAIT_SLEEP_S);
}
@@ -1873,8 +2003,7 @@ wait_till_stable(pcmk__output_t *out, int timeout_ms, cib_t * cib)
pe_reset_working_set(scheduler);
rc = update_scheduler_input_to_cib(out, scheduler, cib);
if (rc != pcmk_rc_ok) {
- pe_free_working_set(scheduler);
- return rc;
+ break;
}
pcmk__schedule_actions(scheduler->input,
pcmk_sched_no_counts|pcmk_sched_no_compat,
@@ -1890,7 +2019,7 @@ wait_till_stable(pcmk__output_t *out, int timeout_ms, cib_t * cib)
* DC. However, that would have potential problems of its own.
*/
const char *dc_version = g_hash_table_lookup(scheduler->config_hash,
- "dc-version");
+ PCMK_OPT_DC_VERSION);
if (!pcmk__str_eq(dc_version, PACEMAKER_VERSION "-" BUILD_VERSION, pcmk__str_casei)) {
out->info(out, "warning: wait option may not work properly in "
@@ -1899,13 +2028,13 @@ wait_till_stable(pcmk__output_t *out, int timeout_ms, cib_t * cib)
}
}
- search = xpath_search(scheduler->input, "/cib/status/node_state/lrm/lrm_resources/lrm_resource/"
- XML_LRM_TAG_RSC_OP "[@" XML_LRM_ATTR_RC "='193']");
+ search = xpath_search(scheduler->input, xpath);
pending_unknown_state_resources = (numXpathResults(search) > 0);
freeXpathObject(search);
} while (actions_are_pending(scheduler->actions) || pending_unknown_state_resources);
pe_free_working_set(scheduler);
+ free(xpath);
return rc;
}
@@ -1943,14 +2072,13 @@ get_action(const char *rsc_action) {
* \param[in] verbosity Verbosity level
*/
static void
-set_agent_environment(GHashTable *params, int timeout_ms, int check_level,
+set_agent_environment(GHashTable *params, guint timeout_ms, int check_level,
int verbosity)
{
- g_hash_table_insert(params, strdup("CRM_meta_timeout"),
- crm_strdup_printf("%d", timeout_ms));
+ g_hash_table_insert(params, crm_meta_name(PCMK_META_TIMEOUT),
+ crm_strdup_printf("%u", timeout_ms));
- g_hash_table_insert(params, strdup(XML_ATTR_CRM_VERSION),
- strdup(CRM_FEATURE_SET));
+ pcmk__insert_dup(params, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET);
if (check_level >= 0) {
char *level = crm_strdup_printf("%d", check_level);
@@ -1989,7 +2117,7 @@ apply_overrides(GHashTable *params, GHashTable *overrides)
g_hash_table_iter_init(&iter, overrides);
while (g_hash_table_iter_next(&iter, (gpointer *) &name,
(gpointer *) &value)) {
- g_hash_table_replace(params, strdup(name), strdup(value));
+ pcmk__insert_dup(params, name, value);
}
}
}
@@ -1999,8 +2127,8 @@ cli_resource_execute_from_params(pcmk__output_t *out, const char *rsc_name,
const char *rsc_class, const char *rsc_prov,
const char *rsc_type, const char *rsc_action,
GHashTable *params, GHashTable *override_hash,
- int timeout_ms, int resource_verbose, gboolean force,
- int check_level)
+ guint timeout_ms, int resource_verbose,
+ gboolean force, int check_level)
{
const char *class = rsc_class;
const char *action = get_action(rsc_action);
@@ -2008,7 +2136,7 @@ cli_resource_execute_from_params(pcmk__output_t *out, const char *rsc_name,
svc_action_t *op = NULL;
// If no timeout was provided, use the same default as the cluster
- if (timeout_ms == 0) {
+ if (timeout_ms == 0U) {
timeout_ms = PCMK_DEFAULT_ACTION_TIMEOUT_MS;
}
@@ -2017,7 +2145,8 @@ cli_resource_execute_from_params(pcmk__output_t *out, const char *rsc_name,
op = services__create_resource_action(rsc_name? rsc_name : "test",
rsc_class, rsc_prov, rsc_type, action,
- 0, timeout_ms, params, 0);
+ 0, QB_MIN(timeout_ms, INT_MAX),
+ params, 0);
if (op == NULL) {
out->err(out, "Could not execute %s using %s%s%s:%s: %s",
action, rsc_class, (rsc_prov? ":" : ""),
@@ -2060,10 +2189,33 @@ done:
return exit_code;
}
+/*!
+ * \internal
+ * \brief Get the timeout the cluster would use for an action
+ *
+ * \param[in] rsc Resource that action is for
+ * \param[in] action Name of action
+ */
+static guint
+get_action_timeout(pcmk_resource_t *rsc, const char *action)
+{
+ long long timeout_ms = -1LL;
+ xmlNode *op = pcmk__find_action_config(rsc, action, 0, true);
+ GHashTable *meta = pcmk__unpack_action_meta(rsc, NULL, action, 0, op);
+
+ if ((pcmk__scan_ll(g_hash_table_lookup(meta, PCMK_META_TIMEOUT),
+ &timeout_ms, -1LL) != pcmk_rc_ok)
+ || (timeout_ms <= 0LL)) {
+ timeout_ms = PCMK_DEFAULT_ACTION_TIMEOUT_MS;
+ }
+ g_hash_table_destroy(meta);
+ return (guint) QB_MIN(timeout_ms, UINT_MAX);
+}
+
crm_exit_t
cli_resource_execute(pcmk_resource_t *rsc, const char *requested_name,
const char *rsc_action, GHashTable *override_hash,
- int timeout_ms, cib_t *cib, pcmk_scheduler_t *scheduler,
+ guint timeout_ms, cib_t *cib, pcmk_scheduler_t *scheduler,
int resource_verbose, gboolean force, int check_level)
{
pcmk__output_t *out = scheduler->priv;
@@ -2076,13 +2228,15 @@ cli_resource_execute(pcmk_resource_t *rsc, const char *requested_name,
if (pcmk__strcase_any_of(rsc_action, "force-start", "force-demote",
"force-promote", NULL)) {
- if(pe_rsc_is_clone(rsc)) {
+ if (pcmk__is_clone(rsc)) {
GList *nodes = cli_resource_search(rsc, requested_name, scheduler);
if(nodes != NULL && force == FALSE) {
out->err(out, "It is not safe to %s %s here: the cluster claims it is already active",
rsc_action, rsc->id);
- out->err(out, "Try setting target-role=Stopped first or specifying "
- "the force option");
+ out->err(out,
+ "Try setting "
+ PCMK_META_TARGET_ROLE "=" PCMK_ROLE_STOPPED
+ " first or specifying the force option");
return CRM_EX_UNSAFE;
}
@@ -2090,32 +2244,31 @@ cli_resource_execute(pcmk_resource_t *rsc, const char *requested_name,
}
}
- if(pe_rsc_is_clone(rsc)) {
+ if (pcmk__is_clone(rsc)) {
/* Grab the first child resource in the hope it's not a group */
rsc = rsc->children->data;
}
- if (rsc->variant == pcmk_rsc_variant_group) {
+ if (pcmk__is_group(rsc)) {
out->err(out, "Sorry, the %s option doesn't support group resources", rsc_action);
return CRM_EX_UNIMPLEMENT_FEATURE;
- } else if (pe_rsc_is_bundled(rsc)) {
+ } else if (pcmk__is_bundled(rsc)) {
out->err(out, "Sorry, the %s option doesn't support bundled resources", rsc_action);
return CRM_EX_UNIMPLEMENT_FEATURE;
}
- rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
- rprov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
- rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE);
+ rclass = crm_element_value(rsc->xml, PCMK_XA_CLASS);
+ rprov = crm_element_value(rsc->xml, PCMK_XA_PROVIDER);
+ rtype = crm_element_value(rsc->xml, PCMK_XA_TYPE);
params = generate_resource_params(rsc, NULL /* @TODO use local node */,
scheduler);
- if (timeout_ms == 0) {
- timeout_ms = pe_get_configured_timeout(rsc, get_action(rsc_action),
- scheduler);
+ if (timeout_ms == 0U) {
+ timeout_ms = get_action_timeout(rsc, get_action(rsc_action));
}
- rid = pe_rsc_is_anon_clone(rsc->parent)? requested_name : rsc->id;
+ rid = pcmk__is_anonymous_clone(rsc->parent)? requested_name : rsc->id;
exit_code = cli_resource_execute_from_params(out, rid, rclass, rprov, rtype, rsc_action,
params, override_hash, timeout_ms,
@@ -2134,7 +2287,7 @@ cli_resource_move(const pcmk_resource_t *rsc, const char *rsc_id,
int rc = pcmk_rc_ok;
unsigned int count = 0;
pcmk_node_t *current = NULL;
- pcmk_node_t *dest = pe_find_node(scheduler->nodes, host_name);
+ pcmk_node_t *dest = pcmk_find_node(scheduler, host_name);
bool cur_is_dest = false;
if (dest == NULL) {
@@ -2170,7 +2323,7 @@ cli_resource_move(const pcmk_resource_t *rsc, const char *rsc_id,
if (child_role == pcmk_role_promoted) {
rsc = child;
- promoted_node = pe__current_node(child);
+ promoted_node = pcmk__current_node(child);
promoted_count++;
}
}
@@ -2182,19 +2335,19 @@ cli_resource_move(const pcmk_resource_t *rsc, const char *rsc_id,
}
if (count > 1) {
- if (pe_rsc_is_clone(rsc)) {
+ if (pcmk__is_clone(rsc)) {
current = NULL;
} else {
return pcmk_rc_multiple;
}
}
- if (current && (current->details == dest->details)) {
+ if (pcmk__same_node(current, dest)) {
cur_is_dest = true;
if (force) {
crm_info("%s is already %s on %s, reinforcing placement with location constraint.",
rsc_id, promoted_role_only?"promoted":"active",
- pe__node_name(dest));
+ pcmk__node_name(dest));
} else {
return pcmk_rc_already;
}
@@ -2211,11 +2364,11 @@ cli_resource_move(const pcmk_resource_t *rsc, const char *rsc_id,
/* Record an explicit preference for 'dest' */
rc = cli_resource_prefer(out, rsc_id, dest->details->uname, move_lifetime,
cib, cib_options, promoted_role_only,
- PCMK__ROLE_PROMOTED);
+ PCMK_ROLE_PROMOTED);
crm_trace("%s%s now prefers %s%s",
rsc->id, (promoted_role_only? " (promoted)" : ""),
- pe__node_name(dest), force?"(forced)":"");
+ pcmk__node_name(dest), force?"(forced)":"");
/* only ban the previous location if current location != destination location.
* it is possible to use -M to enforce a location without regard of where the
@@ -2225,12 +2378,12 @@ cli_resource_move(const pcmk_resource_t *rsc, const char *rsc_id,
if(current) {
(void)cli_resource_ban(out, rsc_id, current->details->uname, move_lifetime,
cib, cib_options, promoted_role_only,
- PCMK__ROLE_PROMOTED);
+ PCMK_ROLE_PROMOTED);
} else if(count > 1) {
out->info(out, "Resource '%s' is currently %s in %d locations. "
"One may now move to %s",
rsc_id, (promoted_role_only? "promoted" : "active"),
- count, pe__node_name(dest));
+ count, pcmk__node_name(dest));
out->info(out, "To prevent '%s' from being %s at a specific location, "
"specify a node.",
rsc_id, (promoted_role_only? "promoted" : "active"));
diff --git a/tools/crm_rule.c b/tools/crm_rule.c
index 5cdc118..aa13de2 100644
--- a/tools/crm_rule.c
+++ b/tools/crm_rule.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2023 the Pacemaker project contributors
+ * Copyright 2019-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -12,7 +12,7 @@
#include <crm/common/cmdline_internal.h>
#include <crm/common/output_internal.h>
#include <crm/common/iso8601.h>
-#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
#include <crm/pengine/rules_internal.h>
#include <crm/pengine/status.h>
#include <pacemaker-internal.h>
@@ -174,21 +174,22 @@ main(int argc, char **argv)
}
// Parse the input XML specified by the command-line options, if any
- if (pcmk__str_eq(options.input_xml, "-", pcmk__str_casei)) {
- input = stdin2xml();
+ if (pcmk__str_eq(options.input_xml, "-", pcmk__str_none)) {
+ input = pcmk__xml_read(NULL);
if (input == NULL) {
exit_code = CRM_EX_DATAERR;
- g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Couldn't parse input from STDIN\n");
+ g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
+ "Couldn't parse input from STDIN");
goto done;
}
} else if (options.input_xml != NULL) {
- input = string2xml(options.input_xml);
+ input = pcmk__xml_parse(options.input_xml);
if (input == NULL) {
exit_code = CRM_EX_DATAERR;
g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
- "Couldn't parse input string: %s\n", options.input_xml);
+ "Couldn't parse input string: %s", options.input_xml);
goto done;
}
}
diff --git a/tools/crm_shadow.c b/tools/crm_shadow.c
index b86f462..aedf805 100644
--- a/tools/crm_shadow.c
+++ b/tools/crm_shadow.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2023 the Pacemaker project contributors
+ * Copyright 2004-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -20,7 +20,6 @@
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
-#include <crm/msg_xml.h>
#include <crm/common/cmdline_internal.h>
#include <crm/common/ipc.h>
@@ -86,12 +85,12 @@ static struct {
* \internal
* \brief Display an instruction to the user
*
- * \param[in,out] out Output object
- * \param[in] ... Message arguments
+ * \param[in,out] out Output object
+ * \param[in] args Message-specific arguments
*
* \return Standard Pacemaker return code
*
- * \note The variadic message arguments are of the following format:
+ * \note \p args should contain the following:
* -# Instructional message
*/
PCMK__OUTPUT_ARGS("instruction", "const char *")
@@ -110,12 +109,12 @@ instruction_default(pcmk__output_t *out, va_list args)
* \internal
* \brief Display an instruction to the user
*
- * \param[in,out] out Output object
- * \param[in] ... Message arguments
+ * \param[in,out] out Output object
+ * \param[in] args Message-specific arguments
*
* \return Standard Pacemaker return code
*
- * \note The variadic message arguments are of the following format:
+ * \note \p args should contain the following:
* -# Instructional message
*/
PCMK__OUTPUT_ARGS("instruction", "const char *")
@@ -135,12 +134,12 @@ instruction_xml(pcmk__output_t *out, va_list args)
* \internal
* \brief Display information about a shadow CIB instance
*
- * \param[in,out] out Output object
- * \param[in] ... Message arguments
+ * \param[in,out] out Output object
+ * \param[in] args Message-specific arguments
*
* \return Standard Pacemaker return code
*
- * \note The variadic message arguments are of the following format:
+ * \note \p args should contain the following:
* -# Instance name (can be \p NULL)
* -# Shadow file name (can be \p NULL)
* -# Shadow file content (can be \p NULL)
@@ -170,12 +169,18 @@ shadow_default(pcmk__output_t *out, va_list args)
rc = out->info(out, "Content:");
if (content != NULL) {
- char *buf = pcmk__trim(dump_xml_formatted_with_text(content));
+ GString *buf = g_string_sized_new(1024);
+ gchar *str = NULL;
- if (!pcmk__str_empty(buf)) {
- out->info(out, "%s", buf);
+ pcmk__xml_string(content, pcmk__xml_fmt_pretty|pcmk__xml_fmt_text,
+ buf, 0);
+
+ str = g_string_free(buf, FALSE);
+ str = pcmk__trim(str);
+ if (!pcmk__str_empty(str)) {
+ out->info(out, "%s", str);
}
- free(buf);
+ g_free(str);
} else {
out->info(out, "<unknown>");
@@ -198,12 +203,12 @@ shadow_default(pcmk__output_t *out, va_list args)
* \internal
* \brief Display information about a shadow CIB instance
*
- * \param[in,out] out Output object
- * \param[in] ... Message arguments
+ * \param[in,out] out Output object
+ * \param[in] args Message-specific arguments
*
* \return Standard Pacemaker return code
*
- * \note The variadic message arguments are of the following format:
+ * \note \p args should contain the following:
* -# Instance name (can be \p NULL)
* -# Shadow file name (can be \p NULL)
* -# Shadow file content (can be \p NULL)
@@ -240,10 +245,16 @@ shadow_text(pcmk__output_t *out, va_list args)
rc = out->info(out, "%s", filename);
}
if (pcmk_is_set(flags, shadow_disp_content) && (content != NULL)) {
- char *buf = pcmk__trim(dump_xml_formatted_with_text(content));
+ GString *buf = g_string_sized_new(1024);
+ gchar *str = NULL;
+
+ pcmk__xml_string(content, pcmk__xml_fmt_pretty|pcmk__xml_fmt_text,
+ buf, 0);
- rc = out->info(out, "%s", pcmk__trim(buf));
- free(buf);
+ str = g_string_free(buf, FALSE);
+ str = pcmk__trim(str);
+ rc = out->info(out, "%s", str);
+ g_free(str);
}
if (pcmk_is_set(flags, shadow_disp_diff) && (diff != NULL)) {
rc = out->message(out, "xml-patchset", diff);
@@ -258,12 +269,12 @@ shadow_text(pcmk__output_t *out, va_list args)
* \internal
* \brief Display information about a shadow CIB instance
*
- * \param[in,out] out Output object
- * \param[in] ... Message arguments
+ * \param[in,out] out Output object
+ * \param[in] args Message-specific arguments
*
* \return Standard Pacemaker return code
*
- * \note The variadic message arguments are of the following format:
+ * \note \p args should contain the following:
* -# Instance name (can be \p NULL)
* -# Shadow file name (can be \p NULL)
* -# Shadow file content (can be \p NULL)
@@ -283,16 +294,19 @@ shadow_xml(pcmk__output_t *out, va_list args)
enum shadow_disp_flags flags G_GNUC_UNUSED =
(enum shadow_disp_flags) va_arg(args, int);
- pcmk__output_xml_create_parent(out, "shadow",
- "instance", instance,
- "file", filename,
+ pcmk__output_xml_create_parent(out, PCMK_XE_SHADOW,
+ PCMK_XA_INSTANCE, instance,
+ PCMK_XA_FILE, filename,
NULL);
if (content != NULL) {
- char *buf = dump_xml_formatted_with_text(content);
+ GString *buf = g_string_sized_new(1024);
+
+ pcmk__xml_string(content, pcmk__xml_fmt_pretty|pcmk__xml_fmt_text, buf,
+ 0);
- out->output_xml(out, "content", buf);
- free(buf);
+ out->output_xml(out, PCMK_XE_CONTENT, buf->str);
+ g_string_free(buf, TRUE);
}
if (diff != NULL) {
@@ -498,7 +512,7 @@ read_xml(const char *filename, xmlNode **output, GError **error)
{
int rc = pcmk_rc_ok;
- *output = filename2xml(filename);
+ *output = pcmk__xml_read(filename);
if (*output == NULL) {
rc = pcmk_rc_no_input;
exit_code = pcmk_rc2exitc(rc);
@@ -521,18 +535,16 @@ static int
write_shadow_file(const xmlNode *xml, const char *filename, bool reset,
GError **error)
{
- int rc = write_xml_file(xml, filename, FALSE);
+ int rc = pcmk__xml_write_file(xml, filename, false, NULL);
- if (rc < 0) {
- 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 %s the shadow instance '%s': %s",
reset? "reset" : "create", options.instance,
pcmk_rc_str(rc));
- return rc;
}
- return pcmk_rc_ok;
+ return rc;
}
/*!
@@ -577,7 +589,7 @@ shadow_setup(pcmk__output_t *out, bool do_switch, GError **error)
setenv("PS1", new_prompt, 1);
setenv("CIB_shadow", options.instance, 1);
- out->message(out, "instruction",
+ out->message(out, PCMK_XE_INSTRUCTION,
"Press Ctrl+D to exit the crm_shadow shell");
if (pcmk__str_eq(shell, "(^|/)bash$", pcmk__str_regex)) {
@@ -683,8 +695,8 @@ commit_shadow_file(GError **error)
section_xml = input;
if (!options.full_upload) {
- section = XML_CIB_TAG_CONFIGURATION;
- section_xml = first_named_child(input, section);
+ section = PCMK_XE_CONFIGURATION;
+ section_xml = pcmk__xe_first_child(input, section, NULL, NULL);
}
rc = real_cib->cmds->replace(real_cib, section, section_xml,
@@ -726,9 +738,9 @@ create_shadow_empty(pcmk__output_t *out, GError **error)
}
output = createEmptyCib(0);
- crm_xml_add(output, XML_ATTR_VALIDATION, options.validate_with);
+ crm_xml_add(output, PCMK_XA_VALIDATE_WITH, options.validate_with);
out->info(out, "Created new %s configuration",
- crm_element_value(output, XML_ATTR_VALIDATION));
+ crm_element_value(output, PCMK_XA_VALIDATE_WITH));
if (write_shadow_file(output, filename, false, error) != pcmk_rc_ok) {
goto done;
diff --git a/tools/crm_simulate.c b/tools/crm_simulate.c
index aab4110..81ff8b3 100644
--- a/tools/crm_simulate.c
+++ b/tools/crm_simulate.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2009-2023 the Pacemaker project contributors
+ * Copyright 2009-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -257,7 +257,7 @@ static GOptionEntry operation_entries[] = {
"N" },
/* Deprecated */
{ "pending", 'j', G_OPTION_FLAG_NO_ARG|G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, pending_cb,
- "Display pending state if 'record-pending' is enabled",
+ "Display pending state if '" PCMK_META_RECORD_PENDING "' is enabled",
NULL },
{ NULL }
@@ -359,22 +359,30 @@ setup_input(pcmk__output_t *out, const char *input, const char *output,
}
} else if (pcmk__str_eq(input, "-", pcmk__str_casei)) {
- cib_object = filename2xml(NULL);
+ cib_object = pcmk__xml_read(NULL);
} else {
- cib_object = filename2xml(input);
+ cib_object = pcmk__xml_read(input);
}
- if (pcmk_find_cib_element(cib_object, XML_CIB_TAG_STATUS) == NULL) {
- create_xml_node(cib_object, XML_CIB_TAG_STATUS);
+ if (cib_object == NULL) {
+ rc = pcmk_rc_bad_input;
+ g_set_error(error, PCMK__EXITC_ERROR, pcmk_rc2exitc(rc),
+ "Could not read input XML: %s", pcmk_rc_str(rc));
+ return rc;
+ }
+
+ if (pcmk_find_cib_element(cib_object, PCMK_XE_STATUS) == NULL) {
+ pcmk__xe_create(cib_object, PCMK_XE_STATUS);
}
- if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
+ rc = pcmk_update_configured_schema(&cib_object, false);
+ if (rc != pcmk_rc_ok) {
free_xml(cib_object);
- return pcmk_rc_transform_failed;
+ return rc;
}
- if (validate_xml(cib_object, NULL, FALSE) != TRUE) {
+ if (!pcmk__validate_xml(cib_object, NULL, NULL, NULL)) {
free_xml(cib_object);
return pcmk_rc_schema_validation;
}
@@ -388,20 +396,17 @@ setup_input(pcmk__output_t *out, const char *input, const char *output,
free(pid);
}
- rc = write_xml_file(cib_object, output, FALSE);
- free_xml(cib_object);
- cib_object = NULL;
-
- if (rc < 0) {
- rc = pcmk_legacy2rc(rc);
+ rc = pcmk__xml_write_file(cib_object, output, false, NULL);
+ if (rc != pcmk_rc_ok) {
g_set_error(error, PCMK__EXITC_ERROR, CRM_EX_CANTCREAT,
"Could not create '%s': %s", output, pcmk_rc_str(rc));
- return rc;
} else {
setenv("CIB_file", output, 1);
- free(local_output);
- return pcmk_rc_ok;
}
+
+ free_xml(cib_object);
+ free(local_output);
+ return rc;
}
static GOptionContext *
@@ -489,9 +494,8 @@ main(int argc, char **argv)
if (pcmk__str_eq(args->output_ty, "text", pcmk__str_null_matches) &&
!pcmk_is_set(options.flags, pcmk_sim_show_scores) &&
!pcmk_is_set(options.flags, pcmk_sim_show_utilization)) {
- pcmk__force_args(context, &error, "%s --text-fancy", g_get_prgname());
- } else if (pcmk__str_eq(args->output_ty, "xml", pcmk__str_none)) {
- pcmk__force_args(context, &error, "%s --xml-simple-list --xml-substitute", g_get_prgname());
+
+ pcmk__output_text_set_fancy(out, true);
}
pe__register_messages(out);
@@ -523,12 +527,12 @@ main(int argc, char **argv)
}
if (pcmk_is_set(options.flags, pcmk_sim_show_scores)) {
- pe__set_working_set_flags(scheduler, pcmk_sched_output_scores);
+ pcmk__set_scheduler_flags(scheduler, pcmk_sched_output_scores);
}
if (pcmk_is_set(options.flags, pcmk_sim_show_utilization)) {
- pe__set_working_set_flags(scheduler, pcmk_sched_show_utilization);
+ pcmk__set_scheduler_flags(scheduler, pcmk_sched_show_utilization);
}
- pe__set_working_set_flags(scheduler, pcmk_sched_no_compat);
+ pcmk__set_scheduler_flags(scheduler, pcmk_sched_no_compat);
if (options.test_dir != NULL) {
scheduler->priv = out;
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);
}
diff --git a/tools/crm_verify.c b/tools/crm_verify.c
index 199814e..81e375a 100644
--- a/tools/crm_verify.c
+++ b/tools/crm_verify.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2023 the Pacemaker project contributors
+ * Copyright 2004-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -24,7 +24,6 @@
#include <crm/common/xml.h>
#include <crm/common/util.h>
-#include <crm/msg_xml.h>
#include <crm/cib.h>
#include <crm/cib/internal.h>
#include <crm/pengine/status.h>
@@ -43,6 +42,7 @@ struct {
char *xml_file;
gboolean xml_stdin;
char *xml_string;
+ unsigned int verbosity;
} options;
static GOptionEntry data_entries[] = {
@@ -112,11 +112,33 @@ build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
return context;
}
+/*!
+ * \internal
+ * \brief Output a configuration issue
+ *
+ * \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_issue(void *ctx, const char *msg, ...)
+{
+ va_list ap;
+ char *buf = NULL;
+ pcmk__output_t *out = ctx;
+
+ va_start(ap, msg);
+ CRM_ASSERT(vasprintf(&buf, msg, ap) > 0);
+ if (options.verbosity > 0) {
+ out->err(out, "%s", buf);
+ }
+ va_end(ap);
+}
+
int
main(int argc, char **argv)
{
- xmlNode *cib_object = NULL;
- xmlNode *status = NULL;
pcmk_scheduler_t *scheduler = NULL;
@@ -127,7 +149,13 @@ main(int argc, char **argv)
pcmk__output_t *out = NULL;
+ const char *cib_source = NULL;
+ xmlNode *cib_object = NULL;
+
GOptionGroup *output_group = NULL;
+
+ const char *failure_type = NULL;
+
pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
gchar **processed_args = pcmk__cmdline_preproc(argv, "xSX");
GOptionContext *context = build_arg_context(args, &output_group);
@@ -159,127 +187,73 @@ main(int argc, char **argv)
pcmk__register_lib_messages(out);
- pcmk__set_config_error_handler((pcmk__config_error_func) out->err, out);
- pcmk__set_config_warning_handler((pcmk__config_warning_func) out->err, out);
+ pcmk__set_config_error_handler(output_config_issue, out);
+ pcmk__set_config_warning_handler(output_config_issue, out);
- crm_info("=#=#=#=#= Getting XML =#=#=#=#=");
-
- if (options.use_live_cib) {
- crm_info("Reading XML from: live cluster");
- rc = cib__signon_query(out, NULL, &cib_object);
-
- if (rc != pcmk_rc_ok) {
- // cib__signon_query() outputs any relevant error
- goto done;
- }
-
- } else if (options.xml_file != NULL) {
- cib_object = filename2xml(options.xml_file);
- if (cib_object == NULL) {
- rc = ENODATA;
- g_set_error(&error, PCMK__RC_ERROR, rc, "Couldn't parse input file: %s", options.xml_file);
- goto done;
- }
+ if (pcmk__str_eq(args->output_ty, "xml", pcmk__str_none)) {
+ args->verbosity = 1;
+ }
+ options.verbosity = args->verbosity;
+ if (options.xml_file != NULL) {
+ cib_source = options.xml_file;
} else if (options.xml_string != NULL) {
- cib_object = string2xml(options.xml_string);
- if (cib_object == NULL) {
- rc = ENODATA;
- g_set_error(&error, PCMK__RC_ERROR, rc, "Couldn't parse input string: %s", options.xml_string);
- goto done;
- }
+ cib_source = options.xml_string;
} else if (options.xml_stdin) {
- cib_object = stdin2xml();
- if (cib_object == NULL) {
- rc = ENODATA;
- g_set_error(&error, PCMK__RC_ERROR, rc, "Couldn't parse input from STDIN.");
- goto done;
- }
-
+ cib_source = "-";
+ } else if (options.use_live_cib) {
+ cib_source = NULL;
} else {
rc = ENODATA;
- g_set_error(&error, PCMK__RC_ERROR, rc,
- "No configuration source specified. Use --help for usage information.");
+ g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "No input specified");
goto done;
}
- if (!pcmk__xe_is(cib_object, XML_TAG_CIB)) {
- rc = EBADMSG;
- g_set_error(&error, PCMK__RC_ERROR, rc,
- "This tool can only check complete configurations (i.e. those starting with <cib>).");
+ rc = pcmk__parse_cib(out, cib_source, &cib_object);
+
+ if (rc != pcmk_rc_ok) {
+ g_set_error(&error, PCMK__EXITC_ERROR, rc, "Couldn't parse input");
goto done;
}
if (options.cib_save != NULL) {
- write_xml_file(cib_object, options.cib_save, FALSE);
- }
-
- status = pcmk_find_cib_element(cib_object, XML_CIB_TAG_STATUS);
- if (status == NULL) {
- create_xml_node(cib_object, XML_CIB_TAG_STATUS);
- }
-
- if (pcmk__validate_xml(cib_object, NULL, (xmlRelaxNGValidityErrorFunc) out->err, out) == FALSE) {
- pcmk__config_err("CIB did not pass schema validation");
- free_xml(cib_object);
- cib_object = NULL;
-
- } else if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
- crm_config_error = TRUE;
- free_xml(cib_object);
- cib_object = NULL;
- out->err(out, "The cluster will NOT be able to use this configuration.\n"
- "Please manually update the configuration to conform to the %s syntax.",
- xml_latest_schema());
+ pcmk__xml_write_file(cib_object, options.cib_save, false, NULL);
}
scheduler = pe_new_working_set();
+
if (scheduler == NULL) {
rc = errno;
g_set_error(&error, PCMK__RC_ERROR, rc,
"Could not allocate scheduler data: %s", pcmk_rc_str(rc));
goto done;
}
+
scheduler->priv = out;
- /* Process the configuration to set crm_config_error/crm_config_warning.
- *
- * @TODO Some parts of the configuration are unpacked only when needed (for
- * example, action configuration), so we aren't necessarily checking those.
- */
- if (cib_object != NULL) {
- unsigned long long flags = pcmk_sched_no_counts|pcmk_sched_no_compat;
+ rc = pcmk__verify(scheduler, out, cib_object);
- if ((status == NULL) && !options.use_live_cib) {
- // No status available, so do minimal checks
- flags |= pcmk_sched_validate_only;
- }
- pcmk__schedule_actions(cib_object, flags, scheduler);
- }
- pe_free_working_set(scheduler);
+ if (rc == pcmk_rc_schema_validation) {
+ if (crm_config_error) {
+ failure_type = "Errors found during check: ";
+ } else if (crm_config_warning) {
+ failure_type = "Warnings found during check: ";
+ } else {
+ failure_type = "";
+ }
+
+ if (args->quiet) {
+ // User requested no output
- if (crm_config_error) {
- rc = pcmk_rc_schema_validation;
-
- if (args->verbosity > 0 || pcmk__str_eq(args->output_ty, "xml", pcmk__str_none)) {
- g_set_error(&error, PCMK__RC_ERROR, rc,
- "Errors found during check: config not valid");
- } else {
- g_set_error(&error, PCMK__RC_ERROR, rc,
- "Errors found during check: config not valid\n-V may provide more details");
- }
-
- } else if (crm_config_warning) {
- rc = pcmk_rc_schema_validation;
-
- if (args->verbosity > 0 || pcmk__str_eq(args->output_ty, "xml", pcmk__str_none)) {
- g_set_error(&error, PCMK__RC_ERROR, rc,
- "Warnings found during check: config may not be valid");
- } else {
- g_set_error(&error, PCMK__RC_ERROR, rc,
- "Warnings found during check: config may not be valid\n-V may provide more details");
+ } else if (options.verbosity > 0) {
+ out->err(out, "%sconfig not valid", failure_type);
+
+ } else {
+ out->err(out, "%sconfig not valid\n-V may provide more details", failure_type);
+ }
}
- }
+
+ pe_free_working_set(scheduler);
done:
g_strfreev(processed_args);
@@ -288,6 +262,10 @@ main(int argc, char **argv)
free(options.xml_file);
free(options.xml_string);
+ if (cib_object != NULL) {
+ free_xml(cib_object);
+ }
+
if (exit_code == CRM_EX_OK) {
exit_code = pcmk_rc2exitc(rc);
}
diff --git a/tools/crmadmin.c b/tools/crmadmin.c
index 0b400ae..082904f 100644
--- a/tools/crmadmin.c
+++ b/tools/crmadmin.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2023 the Pacemaker project contributors
+ * Copyright 2004-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -33,7 +33,7 @@ static enum {
struct {
gboolean health;
- gint timeout;
+ guint timeout;
char *optarg;
char *ipc_name;
gboolean bash_export;
@@ -117,11 +117,7 @@ command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError
}
if (!strcmp(option_name, "--timeout") || !strcmp(option_name, "-t")) {
- options.timeout = crm_parse_interval_spec(optarg);
- if (errno == EINVAL) {
- return FALSE;
- }
- return TRUE;
+ return pcmk_parse_interval_spec(optarg, &options.timeout) == pcmk_rc_ok;
}
pcmk__str_update(&options.optarg, optarg);
@@ -205,10 +201,6 @@ main(int argc, char **argv)
out->quiet = args->quiet;
- if (!pcmk__force_args(context, &error, "%s --xml-simple-list --xml-substitute", g_get_prgname())) {
- goto done;
- }
-
if (args->version) {
out->version(out, false);
goto done;
diff --git a/tools/stonith_admin.c b/tools/stonith_admin.c
index 01f72d5..2268e0d 100644
--- a/tools/stonith_admin.c
+++ b/tools/stonith_admin.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2009-2023 the Pacemaker project contributors
+ * Copyright 2009-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -23,14 +23,13 @@
#include <string.h>
#include <crm/crm.h>
-#include <crm/msg_xml.h>
#include <crm/common/ipc.h>
#include <crm/cluster/internal.h>
#include <crm/common/cmdline_internal.h>
#include <crm/common/output_internal.h>
#include <crm/stonith-ng.h>
-#include <crm/fencing/internal.h>
+#include <crm/fencing/internal.h> // stonith__register_messages()
#include <crm/cib.h>
#include <crm/pengine/status.h>
@@ -53,7 +52,7 @@ struct {
stonith_key_value_t *params;
int fence_level;
int timeout ;
- int tolerance;
+ long long tolerance_ms;
int delay;
char *agent;
char *confirm_host;
@@ -265,7 +264,15 @@ add_stonith_device(const gchar *option_name, const gchar *optarg, gpointer data,
gboolean
add_tolerance(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- options.tolerance = crm_get_msec(optarg) / 1000;
+ // pcmk__request_fencing() expects an unsigned int
+ options.tolerance_ms = crm_get_msec(optarg);
+
+ if (options.tolerance_ms < 0) {
+ crm_warn("Ignoring invalid tolerance '%s'", optarg);
+ options.tolerance_ms = 0;
+ } else {
+ options.tolerance_ms = QB_MIN(options.tolerance_ms, UINT_MAX);
+ }
return TRUE;
}
@@ -339,8 +346,8 @@ request_fencing(stonith_t *st, const char *target, const char *command,
char *reason = NULL;
int rc = pcmk__request_fencing(st, target, command, name,
options.timeout * 1000,
- options.tolerance * 1000,
- options.delay, &reason);
+ options.tolerance_ms, options.delay,
+ &reason);
if (rc != pcmk_rc_ok) {
const char *rc_str = pcmk_rc_str(rc);
@@ -408,6 +415,8 @@ main(int argc, char **argv)
goto done;
}
+ pcmk__output_enable_list_element(out);
+
stonith__register_messages(out);
if (args->version) {