Page MenuHomeClusterLabs Projects

No OneTemporary

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

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)

Event Timeline