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. main

   1 /*
   2  * Copyright 2004-2021 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/msg_xml.h>
  28 #include <crm/cib.h>
  29 #include <crm/cib/internal.h>
  30 #include <crm/pengine/status.h>
  31 #include <pacemaker-internal.h>
  32 
  33 const char *SUMMARY = "Check a Pacemaker configuration for errors\n\n"
  34                       "Check the well-formedness of a complete Pacemaker XML configuration,\n"
  35                       "its conformance to the configured schema, and the presence of common\n"
  36                       "misconfigurations. Problems reported as errors must be fixed before the\n"
  37                       "cluster will work properly. It is left to the administrator to decide\n"
  38                       "whether to fix problems reported as warnings.";
  39 
  40 struct {
  41     char *cib_save;
  42     gboolean use_live_cib;
  43     char *xml_file;
  44     gboolean xml_stdin;
  45     char *xml_string;
  46 } options;
  47 
  48 extern gboolean stage0(pe_working_set_t * data_set);
  49 
  50 static GOptionEntry data_entries[] = {
  51     { "live-check", 'L', 0, G_OPTION_ARG_NONE,
  52       &options.use_live_cib, "Check the configuration used by the running cluster",
  53       NULL },
  54     { "xml-file", 'x', 0, G_OPTION_ARG_FILENAME,
  55       &options.xml_file, "Check the configuration in the named file",
  56       "FILE" },
  57     { "xml-pipe", 'p', 0, G_OPTION_ARG_NONE,
  58       &options.xml_stdin, "Check the configuration piped in via stdin",
  59       NULL },
  60     { "xml-text", 'X', 0, G_OPTION_ARG_STRING,
  61       &options.xml_string, "Check the configuration in the supplied string",
  62       "XML" },
  63 
  64     { NULL }
  65 };
  66 
  67 static GOptionEntry addl_entries[] = {
  68     { "save-xml", 'S', G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME,
  69       &options.cib_save, "Save verified XML to named file (most useful with -L)",
  70       "FILE" },
  71 
  72     { NULL }
  73 };
  74 
  75 static pcmk__supported_format_t formats[] = {
  76     PCMK__SUPPORTED_FORMAT_NONE,
  77     PCMK__SUPPORTED_FORMAT_TEXT,
  78     PCMK__SUPPORTED_FORMAT_XML,
  79     { NULL, NULL, NULL }
  80 };
  81 
  82 static GOptionContext *
  83 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
     /* [previous][next][first][last][top][bottom][index][help] */
  84     GOptionContext *context = NULL;
  85 
  86     const char *description = "Examples:\n\n"
  87                               "Check the consistency of the configuration in the running cluster:\n\n"
  88                               "\tcrm_verify --live-check\n\n"
  89                               "Check the consistency of the configuration in a given file and "
  90                               "produce verbose output:\n\n"
  91                               "\tcrm_verify --xml-file file.xml --verbose\n\n";
  92 
  93     context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
  94     g_option_context_set_description(context, description);
  95 
  96     pcmk__add_arg_group(context, "data", "Data sources:",
  97                         "Show data options", data_entries);
  98     pcmk__add_arg_group(context, "additional", "Additional options:",
  99                         "Show additional options", addl_entries);
 100 
 101     return context;
 102 }
 103 
 104 int
 105 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 106 {
 107     xmlNode *cib_object = NULL;
 108     xmlNode *status = NULL;
 109 
 110     pe_working_set_t *data_set = NULL;
 111     const char *xml_tag = NULL;
 112 
 113     int rc = pcmk_rc_ok;
 114     crm_exit_t exit_code = CRM_EX_OK;
 115 
 116     GError *error = NULL;
 117 
 118     pcmk__output_t *out = NULL;
 119 
 120     GOptionGroup *output_group = NULL;
 121     pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
 122     gchar **processed_args = pcmk__cmdline_preproc(argv, "xSX");
 123     GOptionContext *context = build_arg_context(args, &output_group);
 124 
 125     pcmk__register_formats(output_group, formats);
 126     if (!g_option_context_parse_strv(context, &processed_args, &error)) {
 127         exit_code = CRM_EX_USAGE;
 128         goto done;
 129     }
 130 
 131     pcmk__cli_init_logging("crm_verify", args->verbosity);
 132 
 133     rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
 134     if (rc != pcmk_rc_ok) {
 135         exit_code = CRM_EX_ERROR;
 136         g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s",
 137                     args->output_ty, pcmk_rc_str(rc));
 138         goto done;
 139     }
 140 
 141     if (args->version) {
 142         out->version(out, false);
 143         goto done;
 144     }
 145 
 146     pcmk__register_lib_messages(out);
 147 
 148     crm_info("=#=#=#=#= Getting XML =#=#=#=#=");
 149 
 150     if (options.use_live_cib) {
 151         crm_info("Reading XML from: live cluster");
 152         rc = cib__signon_query(NULL, &cib_object);
 153 
 154         if (rc != pcmk_rc_ok) {
 155             g_set_error(&error, PCMK__RC_ERROR, rc, "CIB query failed: %s", pcmk_rc_str(rc));
 156             goto done;
 157         }
 158 
 159     } else if (options.xml_file != NULL) {
 160         cib_object = filename2xml(options.xml_file);
 161         if (cib_object == NULL) {
 162             rc = ENODATA;
 163             g_set_error(&error, PCMK__RC_ERROR, rc, "Couldn't parse input file: %s", options.xml_file);
 164             goto done;
 165         }
 166 
 167     } else if (options.xml_string != NULL) {
 168         cib_object = string2xml(options.xml_string);
 169         if (cib_object == NULL) {
 170             rc = ENODATA;
 171             g_set_error(&error, PCMK__RC_ERROR, rc, "Couldn't parse input string: %s", options.xml_string);
 172             goto done;
 173         }
 174     } else if (options.xml_stdin) {
 175         cib_object = stdin2xml();
 176         if (cib_object == NULL) {
 177             rc = ENODATA;
 178             g_set_error(&error, PCMK__RC_ERROR, rc, "Couldn't parse input from STDIN.");
 179             goto done;
 180         }
 181 
 182     } else {
 183         rc = ENODATA;
 184         g_set_error(&error, PCMK__RC_ERROR, rc,
 185                     "No configuration source specified.  Use --help for usage information.");
 186         goto done;
 187     }
 188 
 189     xml_tag = crm_element_name(cib_object);
 190     if (!pcmk__str_eq(xml_tag, XML_TAG_CIB, pcmk__str_casei)) {
 191         rc = EBADMSG;
 192         g_set_error(&error, PCMK__RC_ERROR, rc,
 193                     "This tool can only check complete configurations (i.e. those starting with <cib>).");
 194         goto done;
 195     }
 196 
 197     if (options.cib_save != NULL) {
 198         write_xml_file(cib_object, options.cib_save, FALSE);
 199     }
 200 
 201     status = get_object_root(XML_CIB_TAG_STATUS, cib_object);
 202     if (status == NULL) {
 203         create_xml_node(cib_object, XML_CIB_TAG_STATUS);
 204     }
 205 
 206     if (validate_xml(cib_object, NULL, FALSE) == FALSE) {
 207         pcmk__config_err("CIB did not pass schema validation");
 208         free_xml(cib_object);
 209         cib_object = NULL;
 210 
 211     } else if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
 212         crm_config_error = TRUE;
 213         free_xml(cib_object);
 214         cib_object = NULL;
 215         out->err(out, "The cluster will NOT be able to use this configuration.\n"
 216                  "Please manually update the configuration to conform to the %s syntax.",
 217                  xml_latest_schema());
 218     }
 219 
 220     data_set = pe_new_working_set();
 221     if (data_set == NULL) {
 222         rc = errno;
 223         crm_perror(LOG_CRIT, "Unable to allocate working set");
 224         goto done;
 225     }
 226     pe__set_working_set_flags(data_set, pe_flag_no_counts|pe_flag_no_compat);
 227     data_set->priv = out;
 228 
 229     if (cib_object == NULL) {
 230     } else if (status != NULL || options.use_live_cib) {
 231         /* live queries will always have a status section and can do a full simulation */
 232         pcmk__schedule_actions(data_set, cib_object, NULL);
 233 
 234     } else {
 235         data_set->now = crm_time_new(NULL);
 236         data_set->input = cib_object;
 237         stage0(data_set);
 238     }
 239     pe_free_working_set(data_set);
 240 
 241     if (crm_config_error) {
 242         rc = pcmk_rc_schema_validation;
 243 
 244         if (args->verbosity > 0) {
 245             g_set_error(&error, PCMK__RC_ERROR, rc,
 246                         "Errors found during check: config not valid");
 247         } else {
 248             g_set_error(&error, PCMK__RC_ERROR, rc,
 249                         "Errors found during check: config not valid\n-V may provide more details");
 250         }
 251 
 252     } else if (crm_config_warning) {
 253         rc = pcmk_rc_schema_validation;
 254 
 255         if (args->verbosity > 0) {
 256             g_set_error(&error, PCMK__RC_ERROR, rc,
 257                         "Warnings found during check: config may not be valid");
 258         } else {
 259             g_set_error(&error, PCMK__RC_ERROR, rc,
 260                         "Warnings found during check: config may not be valid\n-V may provide more details");
 261         }
 262     }
 263 
 264   done:
 265     g_strfreev(processed_args);
 266     pcmk__free_arg_context(context);
 267     free(options.cib_save);
 268     free(options.xml_file);
 269     free(options.xml_string);
 270 
 271     if (exit_code == CRM_EX_OK) {
 272         exit_code = pcmk_rc2exitc(rc);
 273     }
 274 
 275     pcmk__output_and_clear_error(error, NULL);
 276 
 277     if (out != NULL) {
 278         out->finish(out, exit_code, true, NULL);
 279         pcmk__output_free(out);
 280     }
 281 
 282     crm_exit(exit_code);
 283 }

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