summaryrefslogtreecommitdiffstats
path: root/tools/crm_rule.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/crm_rule.c')
-rw-r--r--tools/crm_rule.c227
1 files changed, 227 insertions, 0 deletions
diff --git a/tools/crm_rule.c b/tools/crm_rule.c
new file mode 100644
index 0000000..5cdc118
--- /dev/null
+++ b/tools/crm_rule.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2019-2023 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/common/cmdline_internal.h>
+#include <crm/common/output_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"
+
+static pcmk__supported_format_t formats[] = {
+ PCMK__SUPPORTED_FORMAT_NONE,
+ PCMK__SUPPORTED_FORMAT_TEXT,
+ PCMK__SUPPORTED_FORMAT_XML,
+ { NULL, NULL, NULL }
+};
+
+enum crm_rule_mode {
+ crm_rule_mode_none,
+ crm_rule_mode_check
+};
+
+struct {
+ char *date;
+ char *input_xml;
+ enum crm_rule_mode mode;
+ gchar **rules;
+} options = {
+ .mode = crm_rule_mode_none
+};
+
+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_ARRAY, &options.rules,
+ "The ID of the rule to check (may be specified multiple times)",
+ 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 GOptionContext *
+build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
+ GOptionContext *context = NULL;
+
+ context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
+
+ 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)
+{
+ crm_time_t *rule_date = NULL;
+ xmlNode *input = NULL;
+
+ int rc = pcmk_rc_ok;
+ crm_exit_t exit_code = CRM_EX_OK;
+
+ GError *error = NULL;
+
+ pcmk__output_t *out = NULL;
+
+ GOptionGroup *output_group = NULL;
+ pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
+ GOptionContext *context = build_arg_context(args, &output_group);
+ gchar **processed_args = pcmk__cmdline_preproc(argv, "drX");
+
+ pcmk__register_formats(output_group, formats);
+ if (!g_option_context_parse_strv(context, &processed_args, &error)) {
+ exit_code = CRM_EX_USAGE;
+ goto done;
+ }
+
+ pcmk__cli_init_logging("crm_rule", args->verbosity);
+
+ rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
+ if (rc != pcmk_rc_ok) {
+ exit_code = CRM_EX_ERROR;
+ g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s",
+ args->output_ty, pcmk_rc_str(rc));
+ goto done;
+ }
+
+ pcmk__register_lib_messages(out);
+
+ if (args->version) {
+ out->version(out, false);
+ goto done;
+ }
+
+ /* Check command line arguments before opening a connection to
+ * the CIB manager or doing anything else important.
+ */
+ switch(options.mode) {
+ case crm_rule_mode_check:
+ if (options.rules == NULL) {
+ exit_code = CRM_EX_USAGE;
+ g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "--check requires use of --rule=");
+ goto done;
+ }
+
+ break;
+
+ default:
+ exit_code = CRM_EX_USAGE;
+ g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "No mode operation given");
+ goto done;
+ break;
+ }
+
+ /* Set up some defaults. */
+ rule_date = crm_time_new(options.date);
+ if (rule_date == NULL) {
+ if (options.date != NULL) {
+ exit_code = CRM_EX_DATAERR;
+ g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
+ "Invalid date specified: '%s'", options.date);
+
+ } else {
+ // Should never happen
+ exit_code = CRM_EX_OSERR;
+ g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
+ "No --date given and can't determine current date");
+ }
+ goto done;
+ }
+
+ // 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 (input == NULL) {
+ exit_code = CRM_EX_DATAERR;
+ g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Couldn't parse input from STDIN\n");
+ goto done;
+ }
+ } else if (options.input_xml != NULL) {
+ input = string2xml(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);
+ goto done;
+ }
+ }
+
+ /* 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(options.mode) {
+ case crm_rule_mode_check:
+ rc = pcmk__check_rules(out, input, rule_date,
+ (const char **) options.rules);
+ exit_code = pcmk_rc2exitc(rc);
+ break;
+
+ default:
+ break;
+ }
+
+done:
+ g_strfreev(processed_args);
+ pcmk__free_arg_context(context);
+
+ crm_time_free(rule_date);
+ free_xml(input);
+
+ pcmk__output_and_clear_error(&error, out);
+
+ if (out != NULL) {
+ out->finish(out, exit_code, true, NULL);
+ pcmk__output_free(out);
+ }
+
+ pcmk__unregister_formats();
+ return crm_exit(exit_code);
+}