Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F1842528
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
20 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 9f59c9debf..e5c44e8d55 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,165 +1,166 @@
#
# Copyright 2004-2019 the Pacemaker project contributors
#
# The version control history for this file may have further details.
#
# This source code is licensed under the GNU General Public License version 2
# or later (GPLv2+) WITHOUT ANY WARRANTY.
#
include $(top_srcdir)/mk/common.mk
if BUILD_SYSTEMD
systemdsystemunit_DATA = crm_mon.service
endif
noinst_HEADERS = crm_mon.h crm_resource.h crm_resource_controller.h
pcmkdir = $(datadir)/$(PACKAGE)
pcmk_DATA = report.common report.collector
sbin_SCRIPTS = crm_report crm_standby crm_master crm_failcount
if BUILD_CIBSECRETS
sbin_SCRIPTS += cibsecret
endif
noinst_SCRIPTS = pcmk_simtimes
EXTRA_DIST = crm_diff.8.inc \
crm_mon.sysconfig \
crm_mon.8.inc \
crm_node.8.inc \
+ crm_rule.8.inc \
fix-manpages \
stonith_admin.8.inc
sbin_PROGRAMS = attrd_updater \
cibadmin \
crmadmin \
crm_simulate \
crm_attribute \
crm_diff \
crm_error \
crm_mon \
crm_node \
crm_resource \
crm_rule \
crm_shadow \
crm_verify \
crm_ticket \
iso8601 \
stonith_admin
if BUILD_SERVICELOG
sbin_PROGRAMS += notifyServicelogEvent
endif
if BUILD_OPENIPMI_SERVICELOG
sbin_PROGRAMS += ipmiservicelogd
endif
## SOURCES
# A few tools are just thin wrappers around crm_attribute.
# This makes their help get updated when crm_attribute changes
# (see mk/common.mk).
MAN8DEPS = crm_attribute
crmadmin_SOURCES = crmadmin.c
crmadmin_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
crm_error_SOURCES = crm_error.c
crm_error_LDADD = $(top_builddir)/lib/common/libcrmcommon.la
cibadmin_SOURCES = cibadmin.c
cibadmin_LDADD = $(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
crm_shadow_SOURCES = crm_shadow.c
crm_shadow_LDADD = $(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
crm_node_SOURCES = crm_node.c
crm_node_LDADD = $(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
crm_simulate_SOURCES = crm_simulate.c
crm_simulate_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/pacemaker/libpacemaker.la \
$(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
crm_diff_SOURCES = crm_diff.c
crm_diff_LDADD = $(top_builddir)/lib/common/libcrmcommon.la
crm_mon_SOURCES = crm_mon.c crm_mon_curses.c crm_mon_print.c crm_mon_runtime.c crm_mon_xml.c
crm_mon_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/fencing/libstonithd.la \
$(top_builddir)/lib/pacemaker/libpacemaker.la \
$(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la \
$(CURSESLIBS)
crm_verify_SOURCES = crm_verify.c
crm_verify_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/pacemaker/libpacemaker.la \
$(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
crm_attribute_SOURCES = crm_attribute.c
crm_attribute_LDADD = $(top_builddir)/lib/cluster/libcrmcluster.la \
$(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
crm_resource_SOURCES = crm_resource.c \
crm_resource_ban.c \
crm_resource_controller.c \
crm_resource_print.c \
crm_resource_runtime.c
crm_resource_LDADD = $(top_builddir)/lib/pengine/libpe_rules.la \
$(top_builddir)/lib/fencing/libstonithd.la \
$(top_builddir)/lib/lrmd/liblrmd.la \
$(top_builddir)/lib/services/libcrmservice.la \
$(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/pacemaker/libpacemaker.la \
$(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
crm_rule_SOURCES = crm_rule.c
crm_rule_LDADD = $(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/pengine/libpe_rules.la \
$(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/common/libcrmcommon.la
iso8601_SOURCES = iso8601.c
iso8601_LDADD = $(top_builddir)/lib/common/libcrmcommon.la
attrd_updater_SOURCES = attrd_updater.c
attrd_updater_LDADD = $(top_builddir)/lib/common/libcrmcommon.la
crm_ticket_SOURCES = crm_ticket.c
crm_ticket_LDADD = $(top_builddir)/lib/pengine/libpe_rules.la \
$(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/pacemaker/libpacemaker.la \
$(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
stonith_admin_SOURCES = stonith_admin.c
stonith_admin_LDADD = $(top_builddir)/lib/pacemaker/libpacemaker.la \
$(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/fencing/libstonithd.la \
$(top_builddir)/lib/common/libcrmcommon.la
if BUILD_SERVICELOG
notifyServicelogEvent_SOURCES = notifyServicelogEvent.c
notifyServicelogEvent_CFLAGS = $(SERVICELOG_CFLAGS)
notifyServicelogEvent_LDADD = $(top_builddir)/lib/common/libcrmcommon.la $(SERVICELOG_LIBS)
endif
if BUILD_OPENIPMI_SERVICELOG
ipmiservicelogd_SOURCES = ipmiservicelogd.c
ipmiservicelogd_CFLAGS = $(OPENIPMI_SERVICELOG_CFLAGS) $(SERVICELOG_CFLAGS)
ipmiservicelogd_LDFLAGS = $(top_builddir)/lib/common/libcrmcommon.la $(OPENIPMI_SERVICELOG_LIBS) $(SERVICELOG_LIBS)
endif
CLEANFILES = $(man8_MANS)
diff --git a/tools/crm_rule.8.inc b/tools/crm_rule.8.inc
new file mode 100644
index 0000000000..2b6ac89617
--- /dev/null
+++ b/tools/crm_rule.8.inc
@@ -0,0 +1,8 @@
+[synopsis]
+crm_rule mode [options]
+
+/state of rules/
+.SH OPTIONS
+
+/multiple times/
+.SH NOTICE
diff --git a/tools/crm_rule.c b/tools/crm_rule.c
index 59aec6e532..f80fd95f0e 100644
--- a/tools/crm_rule.c
+++ b/tools/crm_rule.c
@@ -1,349 +1,359 @@
/*
* Copyright 2019-2020 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/cib.h>
+#include <crm/common/cmdline_internal.h>
#include <crm/common/iso8601.h>
#include <crm/msg_xml.h>
#include <crm/pengine/rules_internal.h>
#include <crm/pengine/status.h>
#include <pacemaker-internal.h>
#include <sys/stat.h>
+#define SUMMARY "evaluate rules from the Pacemaker configuration"
+
enum crm_rule_mode {
crm_rule_mode_none,
crm_rule_mode_check
-} rule_mode = crm_rule_mode_none;
+};
+
+struct {
+ char *date;
+ char *input_xml;
+ enum crm_rule_mode mode;
+ char *rule;
+} options = {
+ .mode = crm_rule_mode_none
+};
static int crm_rule_check(pe_working_set_t *data_set, const char *rule_id, crm_time_t *effective_date);
-static pcmk__cli_option_t long_options[] = {
- // long option, argument type, storage, short option, description, flags
- {
- "help", no_argument, NULL, '?',
- "\tThis text", pcmk__option_default
- },
- {
- "version", no_argument, NULL, '$',
- "\tVersion information", pcmk__option_default
- },
- {
- "verbose", no_argument, NULL, 'V',
- "\tIncrease debug output", pcmk__option_default
- },
- {
- "-spacer-", no_argument, NULL, '-',
- "\nModes (mutually exclusive):", pcmk__option_default
- },
- {
- "check", no_argument, NULL, 'c',
- "\tCheck whether a rule is in effect", pcmk__option_default
- },
- {
- "-spacer-", no_argument, NULL, '-',
- "\nAdditional options:", pcmk__option_default
- },
- {
- "date", required_argument, NULL, 'd',
- "Whether the rule is in effect on a given date", pcmk__option_default
- },
- {
- "rule", required_argument, NULL, 'r',
- "The ID of the rule to check", pcmk__option_default
- },
- {
- "-spacer-", no_argument, NULL, '-',
- "\nData:", pcmk__option_default
- },
- {
- "xml-text", required_argument, NULL, 'X',
- "Use argument for XML (or stdin if '-')", pcmk__option_default
- },
- {
- "-spacer-", no_argument, NULL, '-',
- "\n\nThis tool is currently experimental.",
- pcmk__option_paragraph
- },
- {
- "-spacer-", no_argument, NULL, '-',
- "The interface, behavior, and output may change with any version of "
- "pacemaker.",
- pcmk__option_paragraph
- },
- { 0, 0, 0, 0 }
+static gboolean mode_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
+
+static GOptionEntry mode_entries[] = {
+ { "check", 'c', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, mode_cb,
+ "Check whether a rule is in effect",
+ NULL },
+
+ { NULL }
};
+static GOptionEntry data_entries[] = {
+ { "xml-text", 'X', 0, G_OPTION_ARG_STRING, &options.input_xml,
+ "Use argument for XML (or stdin if '-')",
+ NULL },
+
+ { NULL }
+};
+
+static GOptionEntry addl_entries[] = {
+ { "date", 'd', 0, G_OPTION_ARG_STRING, &options.date,
+ "Whether the rule is in effect on a given date",
+ NULL },
+ { "rule", 'r', 0, G_OPTION_ARG_STRING, &options.rule,
+ "The ID of the rule to check",
+ NULL },
+
+ { NULL }
+};
+
+static gboolean
+mode_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
+ if (strcmp(option_name, "c")) {
+ options.mode = crm_rule_mode_check;
+ }
+
+ return TRUE;
+}
+
static int
crm_rule_check(pe_working_set_t *data_set, const char *rule_id, crm_time_t *effective_date)
{
xmlNode *cib_constraints = NULL;
xmlNode *match = NULL;
xmlXPathObjectPtr xpathObj = NULL;
char *xpath = NULL;
int rc = pcmk_rc_ok;
int max = 0;
/* Rules are under the constraints node in the XML, so first find that. */
cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, data_set->input);
/* Get all rules matching the given ID which are also simple enough for us to check.
* For the moment, these rules must only have a single date_expression child and:
* - Do not have a date_spec operation, or
* - Have a date_spec operation that contains years= but does not contain moon=.
*
* We do this in steps to provide better error messages. First, check that there's
* any rule with the given ID.
*/
xpath = crm_strdup_printf("//rule[@id='%s']", rule_id);
xpathObj = xpath_search(cib_constraints, xpath);
max = numXpathResults(xpathObj);
if (max == 0) {
CMD_ERR("No rule found with ID=%s", rule_id);
rc = ENXIO;
goto bail;
} else if (max > 1) {
CMD_ERR("More than one rule with ID=%s found", rule_id);
rc = ENXIO;
goto bail;
}
free(xpath);
freeXpathObject(xpathObj);
/* Next, make sure it has exactly one date_expression. */
xpath = crm_strdup_printf("//rule[@id='%s']//date_expression", rule_id);
xpathObj = xpath_search(cib_constraints, xpath);
max = numXpathResults(xpathObj);
if (max != 1) {
CMD_ERR("Can't check rule %s because it does not have exactly one date_expression", rule_id);
rc = EOPNOTSUPP;
goto bail;
}
free(xpath);
freeXpathObject(xpathObj);
/* Then, check that it's something we actually support. */
xpath = crm_strdup_printf("//rule[@id='%s']//date_expression[@operation!='date_spec']", rule_id);
xpathObj = xpath_search(cib_constraints, xpath);
max = numXpathResults(xpathObj);
if (max == 0) {
free(xpath);
freeXpathObject(xpathObj);
xpath = crm_strdup_printf("//rule[@id='%s']//date_expression[@operation='date_spec' and date_spec/@years and not(date_spec/@moon)]",
rule_id);
xpathObj = xpath_search(cib_constraints, xpath);
max = numXpathResults(xpathObj);
if (max == 0) {
CMD_ERR("Rule either must not use date_spec, or use date_spec with years= but not moon=");
rc = ENXIO;
goto bail;
}
}
match = getXpathResult(xpathObj, 0);
/* We should have ensured both of these pass with the xpath query above, but
* double checking can't hurt.
*/
CRM_ASSERT(match != NULL);
CRM_ASSERT(find_expression_type(match) == time_expr);
rc = pe_eval_date_expression(match, effective_date, NULL);
if (rc == pcmk_rc_within_range) {
printf("Rule %s is still in effect\n", rule_id);
rc = pcmk_rc_ok;
} else if (rc == pcmk_rc_ok) {
printf("Rule %s satisfies conditions\n", rule_id);
} else if (rc == pcmk_rc_after_range) {
printf("Rule %s is expired\n", rule_id);
} else if (rc == pcmk_rc_before_range) {
printf("Rule %s has not yet taken effect\n", rule_id);
} else if (rc == pcmk_rc_op_unsatisfied) {
printf("Rule %s does not satisfy conditions\n", rule_id);
} else {
printf("Could not determine whether rule %s is expired\n", rule_id);
}
bail:
free(xpath);
freeXpathObject(xpathObj);
return rc;
}
+static GOptionContext *
+build_arg_context(pcmk__common_args_t *args) {
+ GOptionContext *context = NULL;
+
+ const char *description = "This tool is currently experimental.\n"
+ "The interface, behavior, and output may change with any version of pacemaker.";
+
+ context = pcmk__build_arg_context(args, NULL, NULL);
+ g_option_context_set_description(context, description);
+
+ pcmk__add_arg_group(context, "modes", "Modes (mutually exclusive):",
+ "Show modes of operation", mode_entries);
+ pcmk__add_arg_group(context, "data", "Data:",
+ "Show data options", data_entries);
+ pcmk__add_arg_group(context, "additional", "Additional Options:",
+ "Show additional options", addl_entries);
+ return context;
+}
+
int
main(int argc, char **argv)
{
cib_t *cib_conn = NULL;
pe_working_set_t *data_set = NULL;
- int flag = 0;
- int option_index = 0;
-
- char *rule_id = NULL;
crm_time_t *rule_date = NULL;
-
xmlNode *input = NULL;
- char *input_xml = NULL;
int rc = pcmk_ok;
crm_exit_t exit_code = CRM_EX_OK;
+ pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
+
+ GError *error = NULL;
+ GOptionContext *context = NULL;
+ gchar **processed_args = NULL;
+
+ context = build_arg_context(args);
+
crm_log_cli_init("crm_rule");
- pcmk__set_cli_options(NULL, "[options]", long_options,
- "evaluate rules from the Pacemaker configuration");
-
- while (flag >= 0) {
- flag = pcmk__next_cli_option(argc, argv, &option_index, NULL);
- switch (flag) {
- case -1:
- break;
-
- case 'V':
- crm_bump_log_level(argc, argv);
- break;
-
- case '$':
- case '?':
- pcmk__cli_help(flag, CRM_EX_OK);
- break;
-
- case 'c':
- rule_mode = crm_rule_mode_check;
- break;
-
- case 'd':
- rule_date = crm_time_new(optarg);
- if (rule_date == NULL) {
- exit_code = CRM_EX_DATAERR;
- goto bail;
- }
-
- break;
-
- case 'X':
- input_xml = optarg;
- break;
-
- case 'r':
- rule_id = strdup(optarg);
- break;
-
- default:
- pcmk__cli_help(flag, CRM_EX_OK);
- break;
- }
+
+ processed_args = pcmk__cmdline_preproc(argv, "nopNO");
+
+ if (!g_option_context_parse_strv(context, &processed_args, &error)) {
+ CMD_ERR("%s: %s\n", g_get_prgname(), error->message);
+ exit_code = CRM_EX_USAGE;
+ goto bail;
+ }
+
+ for (int i = 0; i < args->verbosity; i++) {
+ crm_bump_log_level(argc, argv);
+ }
+
+ if (args->version) {
+ /* FIXME: When crm_rule is converted to use formatted output, this can go. */
+ pcmk__cli_help('v', CRM_EX_USAGE);
+ }
+
+ if (optind > argc) {
+ CMD_ERR("%s", g_option_context_get_help(context, TRUE, NULL));
+ exit_code = CRM_EX_USAGE;
+ goto bail;
}
/* Check command line arguments before opening a connection to
* the CIB manager or doing anything else important.
*/
- if (rule_mode == crm_rule_mode_check) {
- if (rule_id == NULL) {
- CMD_ERR("--check requires use of --rule=\n");
- pcmk__cli_help(flag, CRM_EX_USAGE);
- }
+ switch(options.mode) {
+ case crm_rule_mode_check:
+ if (options.rule == NULL) {
+ CMD_ERR("--check requires use of --rule=");
+ exit_code = CRM_EX_USAGE;
+ goto bail;
+ }
+
+ break;
+
+ default:
+ CMD_ERR("No mode operation given");
+ exit_code = CRM_EX_USAGE;
+ goto bail;
+ break;
}
/* Set up some defaults. */
+ rule_date = crm_time_new(options.date);
if (rule_date == NULL) {
- rule_date = crm_time_new(NULL);
+ CMD_ERR("No --date given and can't determine current date");
+ exit_code = CRM_EX_DATAERR;
+ goto bail;
}
/* Where does the XML come from? If one of various command line options were
* given, use those. Otherwise, connect to the CIB and use that.
*/
- if (safe_str_eq(input_xml, "-")) {
+ if (safe_str_eq(options.input_xml, "-")) {
input = stdin2xml();
if (input == NULL) {
- fprintf(stderr, "Couldn't parse input from STDIN\n");
+ CMD_ERR("Couldn't parse input from STDIN\n");
exit_code = CRM_EX_DATAERR;
goto bail;
}
- } else if (input_xml != NULL) {
- input = string2xml(input_xml);
+ } else if (options.input_xml != NULL) {
+ input = string2xml(options.input_xml);
if (input == NULL) {
- fprintf(stderr, "Couldn't parse input string: %s\n", input_xml);
+ CMD_ERR("Couldn't parse input string: %s\n", options.input_xml);
+
exit_code = CRM_EX_DATAERR;
goto bail;
}
} else {
/* Establish a connection to the CIB manager */
cib_conn = cib_new();
rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
if (rc != pcmk_ok) {
CMD_ERR("Error connecting to the CIB manager: %s", pcmk_strerror(rc));
exit_code = crm_errno2exit(rc);
goto bail;
}
}
/* Populate working set from CIB query */
if (input == NULL) {
rc = cib_conn->cmds->query(cib_conn, NULL, &input, cib_scope_local | cib_sync_call);
if (rc != pcmk_ok) {
exit_code = crm_errno2exit(rc);
goto bail;
}
}
/* Populate the working set instance */
data_set = pe_new_working_set();
if (data_set == NULL) {
exit_code = crm_errno2exit(ENOMEM);
goto bail;
}
set_bit(data_set->flags, pe_flag_no_counts);
set_bit(data_set->flags, pe_flag_no_compat);
data_set->input = input;
data_set->now = rule_date;
/* Unpack everything. */
cluster_status(data_set);
/* Now do whichever operation mode was asked for. There's only one at the
* moment so this looks a little silly, but I expect there will be more
* modes in the future.
*/
- switch(rule_mode) {
+ switch(options.mode) {
case crm_rule_mode_check:
- rc = crm_rule_check(data_set, rule_id, rule_date);
+ rc = crm_rule_check(data_set, options.rule, rule_date);
if (rc > 0) {
CMD_ERR("Error checking rule: %s", pcmk_rc_str(rc));
}
exit_code = pcmk_rc2exitc(rc);
-
break;
default:
break;
}
bail:
if (cib_conn != NULL) {
cib_conn->cmds->signoff(cib_conn);
cib_delete(cib_conn);
}
+ g_strfreev(processed_args);
+ g_clear_error(&error);
+ pcmk__free_arg_context(context);
pe_free_working_set(data_set);
crm_exit(exit_code);
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 23, 5:01 PM (10 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1013348
Default Alt Text
(20 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment