root/tools/crm_verify.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. build_arg_context
  2. G_GNUC_PRINTF
  3. G_GNUC_PRINTF
  4. main

   1 /*
   2  * Copyright 2004-2024 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 #include <crm/crm.h>
  12 #include <crm/common/cmdline_internal.h>
  13 #include <crm/common/output_internal.h>
  14 
  15 #include <stdio.h>
  16 #include <sys/types.h>
  17 #include <unistd.h>
  18 
  19 #include <stdlib.h>
  20 #include <errno.h>
  21 #include <fcntl.h>
  22 #include <libgen.h>
  23 #include <glib.h>
  24 
  25 #include <crm/common/xml.h>
  26 #include <crm/common/util.h>
  27 #include <crm/cib.h>
  28 #include <crm/cib/internal.h>
  29 #include <crm/pengine/status.h>
  30 #include <pacemaker-internal.h>
  31 
  32 const char *SUMMARY = "Check a Pacemaker configuration for errors\n\n"
  33                       "Check the well-formedness of a complete Pacemaker XML configuration,\n"
  34                       "its conformance to the configured schema, and the presence of common\n"
  35                       "misconfigurations. Problems reported as errors must be fixed before the\n"
  36                       "cluster will work properly. It is left to the administrator to decide\n"
  37                       "whether to fix problems reported as warnings.";
  38 
  39 struct {
  40     char *cib_save;
  41     gboolean use_live_cib;
  42     char *xml_file;
  43     gboolean xml_stdin;
  44     char *xml_string;
  45     unsigned int verbosity;
  46 } options;
  47 
  48 static GOptionEntry data_entries[] = {
  49     { "live-check", 'L', 0, G_OPTION_ARG_NONE,
  50       &options.use_live_cib, "Check the configuration used by the running cluster",
  51       NULL },
  52     { "xml-file", 'x', 0, G_OPTION_ARG_FILENAME,
  53       &options.xml_file, "Check the configuration in the named file",
  54       "FILE" },
  55     { "xml-pipe", 'p', 0, G_OPTION_ARG_NONE,
  56       &options.xml_stdin, "Check the configuration piped in via stdin",
  57       NULL },
  58     { "xml-text", 'X', 0, G_OPTION_ARG_STRING,
  59       &options.xml_string, "Check the configuration in the supplied string",
  60       "XML" },
  61 
  62     { NULL }
  63 };
  64 
  65 static GOptionEntry addl_entries[] = {
  66     { "save-xml", 'S', G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME,
  67       &options.cib_save, "Save verified XML to named file (most useful with -L)",
  68       "FILE" },
  69 
  70     { NULL }
  71 };
  72 
  73 static pcmk__supported_format_t formats[] = {
  74     PCMK__SUPPORTED_FORMAT_NONE,
  75     PCMK__SUPPORTED_FORMAT_TEXT,
  76     PCMK__SUPPORTED_FORMAT_XML,
  77     { NULL, NULL, NULL }
  78 };
  79 
  80 static GOptionContext *
  81 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
     /* [previous][next][first][last][top][bottom][index][help] */
  82     GOptionContext *context = NULL;
  83 
  84     const char *description = "Examples:\n\n"
  85                               "Check the consistency of the configuration in the running cluster:\n\n"
  86                               "\tcrm_verify --live-check\n\n"
  87                               "Check the consistency of the configuration in a given file and "
  88                               "produce quiet output:\n\n"
  89                               "\tcrm_verify --xml-file file.xml --quiet\n\n"
  90                               "Check the consistency of the configuration in a given file and "
  91                               "produce verbose output:\n\n"
  92                               "\tcrm_verify --xml-file file.xml --verbose\n\n";
  93 
  94     GOptionEntry extra_prog_entries[] = {
  95         { "quiet", 'q', 0, G_OPTION_ARG_NONE, &(args->quiet),
  96           "Don't print verify information",
  97           NULL },
  98         { NULL }
  99     };
 100 
 101     context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
 102 
 103     pcmk__add_main_args(context, extra_prog_entries);
 104 
 105     g_option_context_set_description(context, description);
 106 
 107     pcmk__add_arg_group(context, "data", "Data sources:",
 108                         "Show data options", data_entries);
 109     pcmk__add_arg_group(context, "additional", "Additional options:",
 110                         "Show additional options", addl_entries);
 111 
 112     return context;
 113 }
 114 
 115 /*!
 116  * \internal
 117  * \brief Output a configuration error
 118  *
 119  * \param[in] ctx  Output object
 120  * \param[in] msg  printf(3)-style format string
 121  * \param[in] ...  Format string arguments
 122  */
 123 G_GNUC_PRINTF(2, 3)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 static void
 125 output_config_error(void *ctx, const char *msg, ...)
 126 {
 127     va_list ap;
 128     char *buf = NULL;
 129     pcmk__output_t *out = ctx;
 130 
 131     va_start(ap, msg);
 132     pcmk__assert(vasprintf(&buf, msg, ap) > 0);
 133     if (options.verbosity > 0) {
 134         out->err(out, "error: %s", buf);
 135     }
 136     va_end(ap);
 137 }
 138 
 139 /*!
 140  * \internal
 141  * \brief Output a configuration warning
 142  *
 143  * \param[in] ctx  Output object
 144  * \param[in] msg  printf(3)-style format string
 145  * \param[in] ...  Format string arguments
 146  */
 147 G_GNUC_PRINTF(2, 3)
     /* [previous][next][first][last][top][bottom][index][help] */
 148 static void
 149 output_config_warning(void *ctx, const char *msg, ...)
 150 {
 151     va_list ap;
 152     char *buf = NULL;
 153     pcmk__output_t *out = ctx;
 154 
 155     va_start(ap, msg);
 156     pcmk__assert(vasprintf(&buf, msg, ap) > 0);
 157     if (options.verbosity > 0) {
 158         out->err(out, "warning: %s", buf);
 159     }
 160     va_end(ap);
 161 }
 162 
 163 int
 164 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 165 {
 166 
 167     pcmk_scheduler_t *scheduler = NULL;
 168 
 169     int rc = pcmk_rc_ok;
 170     crm_exit_t exit_code = CRM_EX_OK;
 171 
 172     GError *error = NULL;
 173 
 174     pcmk__output_t *out = NULL;
 175 
 176     const char *cib_source = NULL;
 177     xmlNode *cib_object = NULL;
 178 
 179     GOptionGroup *output_group = NULL;
 180 
 181     pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
 182     gchar **processed_args = pcmk__cmdline_preproc(argv, "xSX");
 183     GOptionContext *context = build_arg_context(args, &output_group);
 184 
 185     pcmk__register_formats(output_group, formats);
 186     if (!g_option_context_parse_strv(context, &processed_args, &error)) {
 187         exit_code = CRM_EX_USAGE;
 188         goto done;
 189     }
 190 
 191     if (args->verbosity > 0) {
 192         args->verbosity -= args->quiet;
 193     }
 194 
 195     pcmk__cli_init_logging("crm_verify", args->verbosity);
 196 
 197     rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
 198     if (rc != pcmk_rc_ok) {
 199         exit_code = CRM_EX_ERROR;
 200         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 201                     "Error creating output format %s: %s",
 202                     args->output_ty, pcmk_rc_str(rc));
 203         goto done;
 204     }
 205 
 206     if (args->version) {
 207         out->version(out, false);
 208         goto done;
 209     }
 210 
 211     pcmk__register_lib_messages(out);
 212 
 213     pcmk__set_config_error_handler(output_config_error, out);
 214     pcmk__set_config_warning_handler(output_config_warning, out);
 215 
 216     if (pcmk__str_eq(args->output_ty, "xml", pcmk__str_none)) {
 217         args->verbosity = 1;
 218     }
 219     options.verbosity = args->verbosity;
 220 
 221     if (options.xml_file != NULL) {
 222         cib_source = options.xml_file;
 223     } else if (options.xml_string != NULL) {
 224         cib_source = options.xml_string;
 225     } else if (options.xml_stdin) {
 226         cib_source = "-";
 227     } else if (options.use_live_cib) {
 228         cib_source = NULL;
 229     } else {
 230         rc = ENODATA;
 231         g_set_error(&error, PCMK__RC_ERROR, rc, "No input specified");
 232         goto done;
 233     }
 234 
 235     rc = pcmk__parse_cib(out, cib_source, &cib_object);
 236     if (rc != pcmk_rc_ok) {
 237         g_set_error(&error, PCMK__RC_ERROR, rc, "Verification failed: %s",
 238                     pcmk_rc_str(rc));
 239         goto done;
 240     }
 241 
 242     if (options.cib_save != NULL) {
 243         pcmk__xml_write_file(cib_object, options.cib_save, false);
 244     }
 245 
 246     scheduler = pe_new_working_set();
 247 
 248     if (scheduler == NULL) {
 249         rc = errno;
 250         g_set_error(&error, PCMK__RC_ERROR, rc,
 251                     "Could not allocate scheduler data: %s", pcmk_rc_str(rc));
 252         goto done;
 253     }
 254 
 255     scheduler->priv->out = out;
 256 
 257     rc = pcmk__verify(scheduler, out, &cib_object);
 258 
 259     if ((rc == pcmk_rc_schema_validation) && !args->quiet) {
 260         const char *failure_type = "";
 261         const char *verbose_hint = "";
 262 
 263         if (pcmk__config_has_error) {
 264             failure_type = " (with errors)";
 265         } else if (pcmk__config_has_warning) {
 266             failure_type = " (with warnings)";
 267         }
 268         if (options.verbosity == 0) {
 269             verbose_hint = " (-V may provide more detail)";
 270         }
 271         out->err(out, "Configuration invalid%s%s", failure_type, verbose_hint);
 272     }
 273 
 274     pe_free_working_set(scheduler);
 275 
 276   done:
 277     g_strfreev(processed_args);
 278     pcmk__free_arg_context(context);
 279     free(options.cib_save);
 280     free(options.xml_file);
 281     free(options.xml_string);
 282 
 283     if (cib_object != NULL) {
 284         pcmk__xml_free(cib_object);
 285     }
 286 
 287     if (exit_code == CRM_EX_OK) {
 288         exit_code = pcmk_rc2exitc(rc);
 289     }
 290 
 291     pcmk__output_and_clear_error(&error, out);
 292 
 293     if (out != NULL) {
 294         out->finish(out, exit_code, true, NULL);
 295         pcmk__output_free(out);
 296     }
 297 
 298     pcmk__unregister_formats();
 299     crm_exit(exit_code);
 300 }

/* [previous][next][first][last][top][bottom][index][help] */